1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-17 06:55:03 -05:00

Merge commit '4.117' into issue-162-new

This commit is contained in:
ashley willis 2012-09-11 01:20:56 -05:00
commit 83fb5b5c9a
13 changed files with 634 additions and 142 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="15015"
android:versionName="4.116" package="com.fsck.k9"
android:versionCode="15016"
android:versionName="4.117" package="com.fsck.k9"
>
<uses-sdk
android:minSdkVersion="7"

View File

@ -181,16 +181,16 @@
<!-- Yahoo! Mail Variants -->
<provider id="yahoo" label="Yahoo" domain="yahoo.com">
<incoming uri="imap+tls://imap.mail.yahoo.com" username="$user" />
<outgoing uri="smtp+tls://smtp.mobile.mail.yahoo.com" username="$user" />
<incoming uri="imap+ssl+://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.yahoo.com" username="$email" />
</provider>
<provider id="ymail" label="YMail" domain="ymail.com">
<incoming uri="imap+tls://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+tls://smtp.mobile.mail.yahoo.com" username="$email" />
<incoming uri="imap+ssl+://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.yahoo.com" username="$email" />
</provider>
<provider id="rocketmail" label="Rocketmail" domain="rocketmail.com">
<incoming uri="imap+tls://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+tls://smtp.mobile.mail.yahoo.com" username="$email" />
<incoming uri="imap+ssl+://imap.mail.yahoo.com" username="$email" />
<outgoing uri="smtp+ssl+://smtp.mail.yahoo.com" username="$email" />
</provider>

View File

@ -19,7 +19,9 @@ import com.fsck.k9.K9;
public class K9Activity extends Activity {
private GestureDetector gestureDetector;
protected static final int BEZEL_SWIPE_THRESHOLD = 20;
protected GestureDetector mGestureDetector;
@Override
public void onCreate(Bundle icicle) {
@ -27,10 +29,6 @@ public class K9Activity extends Activity {
setTheme(K9.getK9ThemeResourceId());
super.onCreate(icicle);
setupFormats();
// Gesture detection
gestureDetector = new GestureDetector(new MyGestureDetector());
}
public static void setLanguage(Context context, String language) {
@ -51,8 +49,10 @@ public class K9Activity extends Activity {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
return gestureDetector.onTouchEvent(ev);
if (mGestureDetector != null) {
mGestureDetector.onTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
@Override
@ -184,6 +184,10 @@ public class K9Activity extends Activity {
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
}

View File

@ -759,14 +759,18 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
/*
* Note: According to the documenation ACTION_VIEW and ACTION_SENDTO
* don't accept EXTRA_* parameters. Contrary to the AOSP Email application
* we don't accept those EXTRAs.
* Dear developer, if your application is using those EXTRAs you're doing
* it wrong! So go fix your program or get AOSP to change the documentation.
* Note: According to the documenation ACTION_VIEW and ACTION_SENDTO don't accept
* EXTRA_* parameters.
* And previously we didn't process these EXTRAs. But it looks like nobody bothers to
* read the official documentation and just copies wrong sample code that happens to
* work with the AOSP Email application. And because even big players get this wrong,
* we're now finally giving in and read the EXTRAs for ACTION_SENDTO (below).
*/
}
else if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action) ||
Intent.ACTION_SENDTO.equals(action)) {
/*
* Note: Here we allow a slight deviation from the documentated behavior.
* EXTRA_TEXT is used as message body (if available) regardless of the MIME
@ -774,7 +778,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
* using EXTRA_STREAM.
*/
CharSequence text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT);
if (text != null) {
// Only use EXTRA_TEXT if the body hasn't already been set by the mailto URI
if (text != null && mMessageContentView.getText().length() == 0) {
mMessageContentView.setText(text);
}
@ -797,7 +802,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
if (subject != null) {
// Only use EXTRA_SUBJECT if the subject hasn't already been set by the mailto URI
if (subject != null && mSubjectView.getText().length() == 0) {
mSubjectView.setText(subject);
}
@ -806,16 +812,16 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
String[] extraBcc = intent.getStringArrayExtra(Intent.EXTRA_BCC);
if (extraEmail != null) {
setRecipients(mToView, Arrays.asList(extraEmail));
addRecipients(mToView, Arrays.asList(extraEmail));
}
boolean ccOrBcc = false;
if (extraCc != null) {
ccOrBcc |= setRecipients(mCcView, Arrays.asList(extraCc));
ccOrBcc |= addRecipients(mCcView, Arrays.asList(extraCc));
}
if (extraBcc != null) {
ccOrBcc |= setRecipients(mBccView, Arrays.asList(extraBcc));
ccOrBcc |= addRecipients(mBccView, Arrays.asList(extraBcc));
}
if (ccOrBcc) {
@ -825,19 +831,31 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
}
}
private boolean setRecipients(TextView view, List<String> recipients) {
boolean recipientAdded = false;
if (recipients != null) {
StringBuilder addressList = new StringBuilder();
for (String recipient : recipients) {
addressList.append(recipient);
addressList.append(", ");
recipientAdded = true;
}
view.setText(addressList);
private boolean addRecipients(TextView view, List<String> recipients) {
if (recipients == null || recipients.size() == 0) {
return false;
}
return recipientAdded;
StringBuilder addressList = new StringBuilder();
// Read current contents of the TextView
String text = view.getText().toString();
addressList.append(text);
// Add comma if necessary
if (text.length() != 0 && !(text.endsWith(", ") || text.endsWith(","))) {
addressList.append(", ");
}
// Add recipients
for (String recipient : recipients) {
addressList.append(recipient);
addressList.append(", ");
}
view.setText(addressList);
return true;
}
private void initializeCrypto() {
@ -3003,13 +3021,13 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
to = new ArrayList<String>(to);
to.add(0, recipient);
}
setRecipients(mToView, to);
addRecipients(mToView, to);
// Read carbon copy recipients from the "cc" parameter.
boolean ccOrBcc = setRecipients(mCcView, uri.getQueryParameters("cc"));
boolean ccOrBcc = addRecipients(mCcView, uri.getQueryParameters("cc"));
// Read blind carbon copy recipients from the "bcc" parameter.
ccOrBcc |= setRecipients(mBccView, uri.getQueryParameters("bcc"));
ccOrBcc |= addRecipients(mBccView, uri.getQueryParameters("bcc"));
if (ccOrBcc) {
// Display CC and BCC text fields if CC or BCC recipients were set by the intent.

View File

@ -690,6 +690,9 @@ public class MessageList
mPreviewLines = K9.messageListPreviewLines();
initializeMessageList(getIntent(), true);
// Enable gesture detection for MessageLists
mGestureDetector = new GestureDetector(new MyGestureDetector(true));
}
@Override
@ -932,20 +935,6 @@ public class MessageList
mBatchMoveButton.setVisibility(K9.batchButtonsMove() ? View.VISIBLE : View.GONE);
mBatchFlagButton.setVisibility(K9.batchButtonsFlag() ? View.VISIBLE : View.GONE);
mBatchDoneButton.setVisibility(K9.batchButtonsUnselect() ? View.VISIBLE : View.GONE);
// Gesture detection
gestureDetector = new GestureDetector(new MyGestureDetector(true));
gestureListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
return false;
}
};
mListView.setOnTouchListener(gestureListener);
}
/**
@ -1841,7 +1830,9 @@ public class MessageList
* @param selected true if this was an attempt to select (i.e. left to right).
*/
private void handleSwipe(final MotionEvent downMotion, final boolean selected) {
int position = mListView.pointToPosition((int) downMotion.getX(), (int) downMotion.getY());
int[] listPosition = new int[2];
mListView.getLocationOnScreen(listPosition);
int position = mListView.pointToPosition((int) downMotion.getRawX() - listPosition[0], (int) downMotion.getRawY() - listPosition[1]);
if (position != AdapterView.INVALID_POSITION) {
MessageInfoHolder msgInfoHolder = (MessageInfoHolder) mAdapter.getItem(position);
@ -1886,7 +1877,7 @@ public class MessageList
menu.findItem(R.id.archive).setVisible(false);
}
if (!mAccount.hasSpamFolder()) {
if (!account.hasSpamFolder()) {
menu.findItem(R.id.spam).setVisible(false);
}

View File

@ -81,6 +81,18 @@ public class MessageView extends K9Activity implements OnClickListener {
*/
private Bundle mMessageListExtras;
/**
* Screen width in pixels.
*
* <p>
* Used to detect right-to-left bezel swipes.
* </p>
*
* @see #onSwipeRightToLeft(MotionEvent, MotionEvent)
*/
private int mScreenWidthInPixels;
private final class StorageListenerImplementation implements StorageManager.StorageListener {
@Override
public void onUnmount(String providerId) {
@ -379,6 +391,11 @@ public class MessageView extends K9Activity implements OnClickListener {
mNext.requestFocus();
}
mScreenWidthInPixels = getResources().getDisplayMetrics().widthPixels;
// Enable gesture detection for MessageViews
mGestureDetector = new GestureDetector(new MyGestureDetector(false));
setupButtonViews();
displayMessage(mMessageReference);
}
@ -692,19 +709,24 @@ public class MessageView extends K9Activity implements OnClickListener {
}
/**
* Handle a right-to-left swipe as "move to next message."
* 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) {
onNext();
if ((int) e1.getRawX() > mScreenWidthInPixels - BEZEL_SWIPE_THRESHOLD) {
onNext();
}
}
/**
* Handle a left-to-right swipe as "move to previous message."
* Handle a left-to-right swipe starting at the edge of the screen as
* "move to previous message."
*/
@Override
protected void onSwipeLeftToRight(MotionEvent e1, MotionEvent e2) {
onPrevious();
if ((int) e1.getRawX() < BEZEL_SWIPE_THRESHOLD) {
onPrevious();
}
}
protected void onNext() {

View File

@ -16,12 +16,10 @@ import java.util.concurrent.atomic.AtomicInteger;
import android.app.Application;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.net.Uri;
import android.os.PowerManager;
import android.os.Process;
@ -40,6 +38,7 @@ import com.fsck.k9.K9.Intents;
import com.fsck.k9.activity.FolderList;
import com.fsck.k9.activity.MessageInfoHolder;
import com.fsck.k9.activity.MessageList;
import com.fsck.k9.helper.NotificationBuilder;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.helper.power.TracingPowerManager;
import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock;
@ -3161,80 +3160,139 @@ public class MessagingController implements Runnable {
private void cancelNotification(int id) {
NotificationManager notifMgr =
(NotificationManager)mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
(NotificationManager) mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
notifMgr.cancel(id);
}
private void notifyWhileSendingDone(Account account) {
if (account.isShowOngoing()) {
cancelNotification(K9.FETCHING_EMAIL_NOTIFICATION - account.getAccountNumber());
}
}
/**
* Display an ongoing notification while a message is being sent.
*
* @param account
* The account the message is sent from. Never {@code null}.
*/
private void notifyWhileSending(Account account) {
if (!account.isShowOngoing()) {
return;
}
NotificationManager notifMgr =
(NotificationManager)mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.ic_menu_refresh,
mApplication.getString(R.string.notification_bg_send_ticker, account.getDescription()), System.currentTimeMillis());
Intent intent = MessageList.actionHandleFolderIntent(mApplication, account, account.getInboxFolderName());
(NotificationManager) mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationBuilder builder = NotificationBuilder.getInstance(mApplication);
builder.setSmallIcon(R.drawable.ic_menu_refresh);
builder.setWhen(System.currentTimeMillis());
builder.setOngoing(true);
builder.setTicker(mApplication.getString(R.string.notification_bg_send_ticker,
account.getDescription()));
builder.setContentTitle(mApplication.getString(R.string.notification_bg_send_title));
builder.setContentText(account.getDescription());
Intent intent = MessageList.actionHandleFolderIntent(mApplication, account,
account.getInboxFolderName());
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
notif.setLatestEventInfo(mApplication, mApplication.getString(R.string.notification_bg_send_title),
account.getDescription() , pi);
notif.flags = Notification.FLAG_ONGOING_EVENT;
builder.setContentIntent(pi);
if (K9.NOTIFICATION_LED_WHILE_SYNCING) {
configureNotification(notif, null, null, account.getNotificationSetting().getLedColor(), K9.NOTIFICATION_LED_BLINK_FAST, true);
configureNotification(builder, null, null,
account.getNotificationSetting().getLedColor(),
K9.NOTIFICATION_LED_BLINK_FAST, true);
}
notifMgr.notify(K9.FETCHING_EMAIL_NOTIFICATION - account.getAccountNumber(), notif);
notifMgr.notify(K9.FETCHING_EMAIL_NOTIFICATION - account.getAccountNumber(),
builder.getNotification());
}
private void notifySendTempFailed(Account account, Exception lastFailure) {
notifySendFailed(account, lastFailure, account.getOutboxFolderName());
}
private void notifySendPermFailed(Account account, Exception lastFailure) {
notifySendFailed(account, lastFailure, account.getDraftsFolderName());
}
/**
* Display a notification when sending a message has failed.
*
* @param account
* The account that was used to sent the message.
* @param lastFailure
* The {@link Exception} instance that indicated sending the message has failed.
* @param openFolder
* The name of the folder to open when the notification is clicked.
*/
private void notifySendFailed(Account account, Exception lastFailure, String openFolder) {
NotificationManager notifMgr = (NotificationManager)mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.stat_notify_email_generic, mApplication.getString(R.string.send_failure_subject), System.currentTimeMillis());
NotificationManager notifMgr =
(NotificationManager) mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationBuilder builder = NotificationBuilder.getInstance(mApplication);
builder.setSmallIcon(R.drawable.stat_notify_email_generic);
builder.setWhen(System.currentTimeMillis());
builder.setAutoCancel(true);
builder.setTicker(mApplication.getString(R.string.send_failure_subject));
builder.setContentTitle(mApplication.getString(R.string.send_failure_subject));
builder.setContentText(getRootCauseMessage(lastFailure));
Intent i = FolderList.actionHandleNotification(mApplication, account, openFolder);
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, i, 0);
builder.setContentIntent(pi);
notif.setLatestEventInfo(mApplication, mApplication.getString(R.string.send_failure_subject), getRootCauseMessage(lastFailure), pi);
configureNotification(builder, null, null, K9.NOTIFICATION_LED_SENDING_FAILURE_COLOR,
K9.NOTIFICATION_LED_BLINK_FAST, true);
configureNotification(notif, null, null, K9.NOTIFICATION_LED_SENDING_FAILURE_COLOR, K9.NOTIFICATION_LED_BLINK_FAST, true);
notif.flags |= Notification.FLAG_AUTO_CANCEL;
notifMgr.notify(K9.SEND_FAILED_NOTIFICATION - account.getAccountNumber(), notif);
notifMgr.notify(K9.SEND_FAILED_NOTIFICATION - account.getAccountNumber(),
builder.getNotification());
}
/**
* Display an ongoing notification while checking for new messages on the server.
*
* @param account
* The account that is checked for new messages. Never {@code null}.
* @param folder
* The folder that is being checked for new messages. Never {@code null}.
*/
private void notifyFetchingMail(final Account account, final Folder folder) {
if (account.isShowOngoing()) {
final NotificationManager notifMgr = (NotificationManager)mApplication
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.ic_menu_refresh,
mApplication.getString(R.string.notification_bg_sync_ticker, account.getDescription(), folder.getName()),
System.currentTimeMillis());
Intent intent = MessageList.actionHandleFolderIntent(mApplication, account, account.getInboxFolderName());
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
notif.setLatestEventInfo(mApplication, mApplication.getString(R.string.notification_bg_sync_title), account.getDescription()
+ mApplication.getString(R.string.notification_bg_title_separator) + folder.getName(), pi);
notif.flags = Notification.FLAG_ONGOING_EVENT;
if (K9.NOTIFICATION_LED_WHILE_SYNCING) {
configureNotification(notif, null, null, account.getNotificationSetting().getLedColor(), K9.NOTIFICATION_LED_BLINK_FAST, true);
}
notifMgr.notify(K9.FETCHING_EMAIL_NOTIFICATION - account.getAccountNumber(), notif);
if (!account.isShowOngoing()) {
return;
}
final NotificationManager notifMgr =
(NotificationManager) mApplication.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationBuilder builder = NotificationBuilder.getInstance(mApplication);
builder.setSmallIcon(R.drawable.ic_menu_refresh);
builder.setWhen(System.currentTimeMillis());
builder.setOngoing(true);
builder.setTicker(mApplication.getString(
R.string.notification_bg_sync_ticker, account.getDescription(), folder.getName()));
builder.setContentTitle(mApplication.getString(R.string.notification_bg_sync_title));
builder.setContentText(account.getDescription() +
mApplication.getString(R.string.notification_bg_title_separator) +
folder.getName());
Intent intent = MessageList.actionHandleFolderIntent(mApplication, account,
account.getInboxFolderName());
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
builder.setContentIntent(pi);
if (K9.NOTIFICATION_LED_WHILE_SYNCING) {
configureNotification(builder, null, null,
account.getNotificationSetting().getLedColor(),
K9.NOTIFICATION_LED_BLINK_FAST, true);
}
notifMgr.notify(K9.FETCHING_EMAIL_NOTIFICATION - account.getAccountNumber(),
builder.getNotification());
}
private void notifyFetchingMailCancel(final Account account) {
if (account.isShowOngoing()) {
cancelNotification(K9.FETCHING_EMAIL_NOTIFICATION - account.getAccountNumber());
@ -4496,22 +4554,31 @@ public class MessagingController implements Runnable {
}
NotificationManager notifMgr =
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.stat_notify_email_generic, messageNotice, System.currentTimeMillis());
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationBuilder builder = NotificationBuilder.getInstance(context);
builder.setSmallIcon(R.drawable.stat_notify_email_generic);
builder.setWhen(System.currentTimeMillis());
builder.setTicker(messageNotice);
final int unreadCount = previousUnreadMessageCount + newMessageCount.get();
if (account.isNotificationShowsUnreadCount()) {
notif.number = unreadCount;
builder.setNumber(unreadCount);
}
Intent i = FolderList.actionHandleNotification(context, account, message.getFolder().getName());
String accountDescr = (account.getDescription() != null) ?
account.getDescription() : account.getEmail();
String accountNotice = context.getString(R.string.notification_new_one_account_fmt,
unreadCount, accountDescr);
builder.setContentTitle(accountNotice);
builder.setContentText(messageNotice);
Intent i = FolderList.actionHandleNotification(context, account,
message.getFolder().getName());
PendingIntent pi = PendingIntent.getActivity(context, 0, i, 0);
builder.setContentIntent(pi);
String accountDescr = (account.getDescription() != null) ? account.getDescription() : account.getEmail();
String accountNotice = context.getString(R.string.notification_new_one_account_fmt, unreadCount, accountDescr);
notif.setLatestEventInfo(context, accountNotice, messageNotice, pi);
// Only ring or vibrate if we have not done so already on this
// account and fetch
// Only ring or vibrate if we have not done so already on this account and fetch
boolean ringAndVibrate = false;
if (!account.isRingNotified()) {
account.setRingNotified(true);
@ -4521,38 +4588,36 @@ public class MessagingController implements Runnable {
NotificationSetting n = account.getNotificationSetting();
configureNotification(
notif,
builder,
(n.shouldRing()) ? n.getRingtone() : null,
(n.shouldVibrate()) ? n.getVibration() : null,
(n.isLed()) ? Integer.valueOf(n.getLedColor()) : null,
K9.NOTIFICATION_LED_BLINK_SLOW,
ringAndVibrate);
notifMgr.notify(account.getAccountNumber(), notif);
notifMgr.notify(account.getAccountNumber(), builder.getNotification());
}
/**
* @param notification
* Object to configure. Never <code>null</code>.
* Configure the notification sound and LED
*
* @param builder
* {@link NotificationBuilder} instance used to configure the notification.
* Never {@code null}.
* @param ringtone
* String name of ringtone. <code>null</code> if no ringtone should be played
* String name of ringtone. {@code null}, if no ringtone should be played.
* @param vibrationPattern
* <code>long[]</code> vibration pattern. <code>null</code> if no vibration should be played
* {@code long[]} vibration pattern. {@code null}, if no vibration should be played.
* @param ledColor
* <code>Integer</code> Color to flash LED. <code>null</code> if no LED flash should happen
* Color to flash LED. {@code null}, if no LED flash should happen.
* @param ledSpeed
* <code>int</code> should LEDs flash K9.NOTIFICATION_LED_BLINK_SLOW or K9.NOTIFICATION_LED_BLINK_FAST
* Either {@link K9#NOTIFICATION_LED_BLINK_SLOW} or
* {@link K9#NOTIFICATION_LED_BLINK_FAST}.
* @param ringAndVibrate
* <code>true</code> if ringtone/vibration are allowed,
* <code>false</code> otherwise.
* {@code true}, if ringtone/vibration are allowed. {@code false}, otherwise.
*/
private void configureNotification(final Notification notification,
final String ringtone,
final long[] vibrationPattern,
final Integer ledColor,
final int ledSpeed,
final boolean ringAndVibrate) {
private void configureNotification(NotificationBuilder builder, String ringtone,
long[] vibrationPattern, Integer ledColor, int ledSpeed, boolean ringAndVibrate) {
// if it's quiet time, then we shouldn't be ringing, buzzing or flashing
if (K9.isQuietTime()) {
@ -4560,25 +4625,27 @@ public class MessagingController implements Runnable {
}
if (ringAndVibrate) {
if (ringtone != null) {
notification.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone);
notification.audioStreamType = AudioManager.STREAM_NOTIFICATION;
if (ringtone != null && !TextUtils.isEmpty(ringtone)) {
builder.setSound(Uri.parse(ringtone));
}
if (vibrationPattern != null) {
notification.vibrate = vibrationPattern;
builder.setVibrate(vibrationPattern);
}
}
if (ledColor != null) {
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
notification.ledARGB = ledColor;
int ledOnMS;
int ledOffMS;
if (ledSpeed == K9.NOTIFICATION_LED_BLINK_SLOW) {
notification.ledOnMS = K9.NOTIFICATION_LED_ON_TIME;
notification.ledOffMS = K9.NOTIFICATION_LED_OFF_TIME;
} else if (ledSpeed == K9.NOTIFICATION_LED_BLINK_FAST) {
notification.ledOnMS = K9.NOTIFICATION_LED_FAST_ON_TIME;
notification.ledOffMS = K9.NOTIFICATION_LED_FAST_OFF_TIME;
ledOnMS = K9.NOTIFICATION_LED_ON_TIME;
ledOffMS = K9.NOTIFICATION_LED_OFF_TIME;
} else {
ledOnMS = K9.NOTIFICATION_LED_FAST_ON_TIME;
ledOffMS = K9.NOTIFICATION_LED_FAST_OFF_TIME;
}
builder.setLights(ledColor, ledOnMS, ledOffMS);
}
}

View File

@ -0,0 +1,169 @@
package com.fsck.k9.helper;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Vibrator;
/**
* Helper class to create system notifications
*
* @see NotificationBuilderApi1
* @see NotificationBuilderApi11
*/
public abstract class NotificationBuilder {
/**
* Instance of the API-specific class that is used to create system notifications
*/
private static NotificationBuilder sInstance = null;
/**
* Get API-specific instance of the {@code NotificationBuilder} class
*
* @param context
* A {@link Context} instance.
*
* @return Appropriate {@link NotificationBuilder} instance for this device.
*/
public static NotificationBuilder getInstance(Context context) {
Context appContext = context.getApplicationContext();
if (sInstance == null) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
sInstance = new NotificationBuilderApi1(appContext);
} else {
sInstance = new NotificationBuilderApi11(appContext);
}
}
return sInstance;
}
protected Context mContext;
/**
* Constructor
*
* @param context
* A {@link Context} instance.
*/
protected NotificationBuilder(Context context) {
mContext = context;
}
/**
* Set the small icon to use in the notification layouts.
*
* @param icon
* A resource ID in the application's package of the drawble to use.
*/
public abstract void setSmallIcon(int icon);
/**
* Set the time that the event occurred.
*
* @param when
* Timestamp of when the event occurred.
*/
public abstract void setWhen(long when);
/**
* Set the text that is displayed in the status bar when the notification first arrives.
*
* @param tickerText
* The text to display.
*/
public abstract void setTicker(CharSequence tickerText);
/**
* Set the title (first row) of the notification, in a standard notification.
*
* @param title
* The text to display as notification title.
*/
public abstract void setContentTitle(CharSequence title);
/**
* Set the text (second row) of the notification, in a standard notification.
*
* @param text
* The text to display.
*/
public abstract void setContentText(CharSequence text);
/**
* Supply a PendingIntent to send when the notification is clicked.
*
* @param intent
* The intent that will be sent when the notification was clicked.
*/
public abstract void setContentIntent(PendingIntent intent);
/**
* Set the large number at the right-hand side of the notification.
*
* @param number
* The number to display in the notification.
*/
public abstract void setNumber(int number);
/**
* Set whether this is an ongoing notification.
*
* @param ongoing
* {@code true}, if it this is an ongoing notification. {@code false}, otherwise.
*/
public abstract void setOngoing(boolean ongoing);
/**
* Setting this flag will make it so the notification is automatically canceled when the user
* clicks it in the panel.
*
* @param autoCancel
* {@code true}, if the notification should be automatically cancelled when the user
* clicks on it. {@code false}, otherwise.
*/
public abstract void setAutoCancel(boolean autoCancel);
/**
* Set the sound to play.
*
* It will play on the notification stream.
*
* @param sound
* The URI of the sound to play.
*/
public abstract void setSound(Uri sound);
/**
* Set the vibration pattern to use.
*
* @param pattern
* An array of longs of times for which to turn the vibrator on or off.
*
* @see Vibrator#vibrate(long[], int)
*/
public abstract void setVibrate(long[] pattern);
/**
* Set the color that you would like the LED on the device to blink, as well as the rate.
*
* @param argb
* The color the LED should blink.
* @param onMs
* The number of milliseconds the LED should be on.
* @param offMs
* The number of milliseconds the LED should be off.
*/
public abstract void setLights(int argb, int onMs, int offMs);
/**
* Combine all of the options that have been set and return a new {@link Notification} object.
*
* @return A new {@code Notification} object configured by this {@link NotificationBuilder}.
*/
public abstract Notification getNotification();
}

View File

@ -0,0 +1,130 @@
package com.fsck.k9.helper;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.media.AudioManager;
import android.net.Uri;
/**
* Create notifications using the now deprecated {@link Notification} constructor.
*/
public class NotificationBuilderApi1 extends NotificationBuilder {
private int mSmallIcon;
private long mWhen;
private CharSequence mTickerText;
private CharSequence mContentText;
private CharSequence mContentTitle;
private PendingIntent mContentIntent;
private int mNumber;
private boolean mOngoing;
private boolean mAutoCancel;
private Uri mSoundUri;
private long[] mVibrationPattern;
private int mLedColor;
private int mLedOnMS;
private int mLedOffMS;
private boolean mBlinkLed;
protected NotificationBuilderApi1(Context context) {
super(context);
}
@Override
public void setSmallIcon(int icon) {
mSmallIcon = icon;
}
@Override
public void setWhen(long when) {
mWhen = when;
}
@Override
public void setTicker(CharSequence tickerText) {
mTickerText = tickerText;
}
@Override
public void setContentTitle(CharSequence title) {
mContentTitle = title;
}
@Override
public void setContentText(CharSequence text) {
mContentText = text;
}
@Override
public void setContentIntent(PendingIntent intent) {
mContentIntent = intent;
}
@Override
public void setNumber(int number) {
mNumber = number;
}
@Override
public void setOngoing(boolean ongoing) {
mOngoing = ongoing;
}
@Override
public void setAutoCancel(boolean autoCancel) {
mAutoCancel = autoCancel;
}
@Override
public void setSound(Uri sound) {
mSoundUri = sound;
}
@Override
public void setVibrate(long[] pattern) {
mVibrationPattern = pattern;
}
@Override
public void setLights(int argb, int onMs, int offMs) {
mBlinkLed = true;
mLedColor = argb;
mLedOnMS = onMs;
mLedOffMS = offMs;
}
@SuppressWarnings("deprecation")
@Override
public Notification getNotification() {
Notification notification = new Notification(mSmallIcon, mTickerText, mWhen);
notification.number = mNumber;
notification.setLatestEventInfo(mContext, mContentTitle, mContentText, mContentIntent);
if (mSoundUri != null) {
notification.sound = mSoundUri;
notification.audioStreamType = AudioManager.STREAM_NOTIFICATION;
}
if (mVibrationPattern != null) {
notification.vibrate = mVibrationPattern;
}
if (mBlinkLed) {
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
notification.ledARGB = mLedColor;
notification.ledOnMS = mLedOnMS;
notification.ledOffMS = mLedOffMS;
}
if (mAutoCancel) {
notification.flags |= Notification.FLAG_AUTO_CANCEL;
}
if (mOngoing) {
notification.flags |= Notification.FLAG_ONGOING_EVENT;
}
return notification;
}
}

View File

@ -0,0 +1,86 @@
package com.fsck.k9.helper;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.media.AudioManager;
import android.net.Uri;
/**
* Create notifications using the new {@link android.app.Notification.Builder} class.
*/
public class NotificationBuilderApi11 extends NotificationBuilder {
private Notification.Builder mBuilder;
protected NotificationBuilderApi11(Context context) {
super(context);
mBuilder = new Notification.Builder(context);
}
@Override
public void setSmallIcon(int icon) {
mBuilder.setSmallIcon(icon);
}
@Override
public void setWhen(long when) {
mBuilder.setWhen(when);
}
@Override
public void setTicker(CharSequence tickerText) {
mBuilder.setTicker(tickerText);
}
@Override
public void setContentTitle(CharSequence title) {
mBuilder.setContentTitle(title);
}
@Override
public void setContentText(CharSequence text) {
mBuilder.setContentText(text);
}
@Override
public void setContentIntent(PendingIntent intent) {
mBuilder.setContentIntent(intent);
}
@Override
public void setNumber(int number) {
mBuilder.setNumber(number);
mBuilder.setContentInfo("" + number);
}
@Override
public void setOngoing(boolean ongoing) {
mBuilder.setOngoing(ongoing);
}
@Override
public void setAutoCancel(boolean autoCancel) {
mBuilder.setAutoCancel(autoCancel);
}
@Override
public void setSound(Uri sound) {
mBuilder.setSound(sound, AudioManager.STREAM_NOTIFICATION);
}
@Override
public void setVibrate(long[] pattern) {
mBuilder.setVibrate(pattern);
}
@Override
public void setLights(int argb, int onMs, int offMs) {
mBuilder.setLights(argb, onMs, offMs);
}
@Override
public Notification getNotification() {
return mBuilder.getNotification();
}
}

View File

@ -118,12 +118,12 @@ public class MimeHeader {
writer.flush();
}
// encode non printable characters except LF/CR codes.
// encode non printable characters except LF/CR/TAB codes.
public boolean hasToBeEncoded(String text) {
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c < 0x20 || 0x7e < c) { // non printable
if (c != 0x0a && c != 0x0d) { // non LF/CR
if (c != 0x0a && c != 0x0d && c != 0x09) { // non LF/CR/TAB
return true;
}
}

View File

@ -371,12 +371,12 @@ public class LockableDatabase {
try {
final File databaseFile = prepareStorage(mStorageProviderId);
try {
mDb = application.openOrCreateDatabase(databaseFile.getPath(), Context.MODE_PRIVATE, null);
mDb = application.openOrCreateDatabase(databaseFile.getName(), Context.MODE_PRIVATE, null);
} catch (SQLiteException e) {
// try to gracefully handle DB corruption - see issue 2537
Log.w(K9.LOG_TAG, "Unable to open DB " + databaseFile + " - removing file and retrying", e);
databaseFile.delete();
mDb = application.openOrCreateDatabase(databaseFile.getPath(), Context.MODE_PRIVATE, null);
mDb = application.openOrCreateDatabase(databaseFile.getName(), Context.MODE_PRIVATE, null);
}
if (mDb.getVersion() != mSchemaDefinition.getVersion()) {
mSchemaDefinition.doDbUpgrade(mDb);

View File

@ -354,7 +354,7 @@ public class SettingsImporter {
}
// Make sure the account name is unique
String accountName = (account.name != null) ? account.name : "Imported";
String accountName = account.name;
if (isAccountNameUsed(accountName, accounts)) {
// Account name is already in use. So generate a new one by appending " (x)", where x
// is the first number >= 1 that results in an unused account name.
@ -945,6 +945,11 @@ Log.d("ASH", "import: " + key + ":" + value);
Log.i(K9.LOG_TAG, "Skipping account with UUID " + uuid);
}
// If we couldn't find an account name use the UUID
if (account.name == null) {
account.name = uuid;
}
return account;
}