1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-08-13 17:03:48 -04:00

Merge branch 'master' into pgp-fixes

This commit is contained in:
ashley willis 2011-11-21 02:24:10 -06:00
commit e9c8ec5598
32 changed files with 250 additions and 773 deletions

View File

@ -8,5 +8,6 @@
<classpathentry kind="lib" path="libs/commons-io-2.0.1.jar"/>
<classpathentry kind="lib" path="libs/jzlib-1.0.7.jar"/>
<classpathentry kind="lib" path="libs/jutf7-1.0.1-SNAPSHOT.jar"/>
<classpathentry kind="lib" path="libs/htmlcleaner-2.2.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -340,6 +340,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
<string name="global_settings_confirm_actions_summary">選択した動作を実行するときに常にダイアログを表示する</string>
<string name="global_settings_confirm_action_archive">アーカイブ</string>
<string name="global_settings_confirm_action_delete">削除(メッセージ表示画面のみ)</string>
<string name="global_settings_confirm_action_delete_starred">スター付きメッセージの削除 (メッセージ表示画面のみ)</string>
<string name="global_settings_confirm_action_spam">迷惑メール</string>
<string name="global_settings_confirm_action_mark_all_as_read">すべて既読にする</string>
<string name="global_settings_confirm_action_send">送信</string>
@ -564,9 +565,13 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
<string name="account_settings_reply_after_quote_label">引用テキストの後に返信を書く</string>
<string name="account_settings_reply_after_quote_summary">返信するときに元のメッセージを返信の上に表示</string>
<string name="account_settings_strip_signature_label">引用から署名を除く</string>
<string name="account_settings_strip_signature_summary">メッセージの返信時に引用文にある署名を取り除く</string>
<string name="account_settings_message_format_label">メッセージの形式</string>
<string name="account_settings_message_format_text">テキスト(画像や書式は取り除く)</string>
<string name="account_settings_message_format_html">HTML (画像や書式を保持)</string>
<string name="account_settings_message_format_auto">自動 (HTMLメールに対する返信でなければテキスト)</string>
<string name="account_settings_message_read_receipt_label">開封確認</string>
<string name="account_settings_message_read_receipt_summary">常に開封確認を要求する</string>

View File

@ -2,7 +2,6 @@
package com.fsck.k9;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@ -23,7 +22,6 @@ import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.text.format.Time;
import android.text.style.AbsoluteSizeSpan;
import android.util.Log;
import com.fsck.k9.activity.MessageCompose;
@ -68,11 +66,6 @@ public class K9 extends Application {
*/
private static List<ApplicationAware> observers = new ArrayList<ApplicationAware>();
/**
* @see K9#createAbsoluteSizeSpan(int)
*/
private static Constructor<AbsoluteSizeSpan> sAbsoluteSizeSpanConstructor;
public enum BACKGROUND_OPS {
WHEN_CHECKED, ALWAYS, NEVER, WHEN_CHECKED_AUTO_SYNC
}
@ -1023,48 +1016,4 @@ public class K9 extends Application {
public static void setAttachmentDefaultPath(String attachmentDefaultPath) {
K9.mAttachmentDefaultPath = attachmentDefaultPath;
}
/**
* Creates an {@link AbsoluteSizeSpan} object.
*
* <p>
* Android versions prior to 2.0 don't support the constructor with two parameters
* ({@link AbsoluteSizeSpan#AbsoluteSizeSpan(int, boolean)}). So we have to perform some
* reflection magic to dynamically load the new constructor on devices that support it.
* For devices with old Android versions we just use the size as pixels (instead of dip).
* </p>
*
* @param size This is used as the {@code size} parameter for the AbsoluteSizeSpan constructor.
* @return a AbsoluteSizeSpan object with the specified text size.
*/
public static AbsoluteSizeSpan createAbsoluteSizeSpan(int size) {
if (Integer.parseInt(android.os.Build.VERSION.SDK) < 5) {
// For Android 1.5/1.6 simply use the constructor with only the size parameter.
// Yes, that will most likely look wrong!
return new AbsoluteSizeSpan(size);
}
if (sAbsoluteSizeSpanConstructor == null) {
try {
sAbsoluteSizeSpanConstructor = AbsoluteSizeSpan.class.getConstructor(int.class, boolean.class);
} catch (Exception e) {
Log.e(K9.LOG_TAG, "Couldn't get the AbsoluteSizeSpan(int, boolean) constructor", e);
// Fallback
return new AbsoluteSizeSpan(size);
}
}
AbsoluteSizeSpan result;
try {
result = sAbsoluteSizeSpanConstructor.newInstance(size, true);
} catch (Exception e) {
Log.e(K9.LOG_TAG, "Couldn't call the AbsoluteSizeSpan(int, boolean) constructor", e);
// Fallback
result = new AbsoluteSizeSpan(size);
}
return result;
}
}

View File

@ -1,7 +1,6 @@
package com.fsck.k9.activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@ -125,12 +124,9 @@ public class EditIdentity extends K9Activity {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
saveIdentity();
return true;
}
return super.onKeyDown(keyCode, event);
public void onBackPressed() {
saveIdentity();
super.onBackPressed();
}
@Override

View File

@ -356,38 +356,18 @@ public class FolderList extends K9ListActivity {
@Override
public void onBackPressed() {
// This will be called either automatically for you on 2.0
// or later, or by the code above on earlier versions of the
// platform.
if (K9.manageBack()) {
onAccounts();
} else {
// TODO - when we move to android 2.0, uncomment this instead.
// super.onBackPressed()
finish();
super.onBackPressed();
}
}
@Override public boolean onKeyDown(int keyCode, KeyEvent event) {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//Shortcuts that work no matter what is selected
if (
// TODO - when we move to android 2.0, uncomment this.
// android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR &&
keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0
&& K9.manageBack()) {
// Take care of calling this method on earlier versions of
// the platform where it doesn't exist.
onBackPressed();
return true;
}
switch (keyCode) {
case KeyEvent.KEYCODE_Q:
//case KeyEvent.KEYCODE_BACK:
{
onAccounts();
return true;

View File

@ -119,11 +119,9 @@ public class ManageIdentities extends ChooseIdentity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
saveIdentities();
}
return super.onKeyDown(keyCode, event);
public void onBackPressed() {
saveIdentities();
super.onBackPressed();
}
private void saveIdentities() {

View File

@ -30,7 +30,6 @@ import android.os.Parcelable;
import android.provider.OpenableColumns;
import android.text.util.Rfc822Tokenizer;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@ -717,9 +716,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
* it wrong! So go fix your program or get AOSP to change the documentation.
*/
}
//TODO: Use constant Intent.ACTION_SEND_MULTIPLE once we drop Android 1.5 support
else if (Intent.ACTION_SEND.equals(action) ||
"android.intent.action.SEND_MULTIPLE".equals(action)) {
else if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.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
@ -1980,16 +1977,13 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
@Override
public void onBackPressed() {
// This will be called either automatically for you on 2.0
// or later, or by the code above on earlier versions of the
// platform.
if (mEncryptCheckbox.isChecked()) {
showDialog(DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED);
}
else if (mDraftNeedsSaving) {
showDialog(DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE);
} else {
finish();
super.onBackPressed();
}
}
@ -2045,24 +2039,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
return super.onCreateDialog(id);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (
// TODO - when we move to android 2.0, uncomment this.
// android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR &&
keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0
&& K9.manageBack()) {
// Take care of calling this method on earlier versions of
// the platform where it doesn't exist.
onBackPressed();
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* Returns true if all attachments were able to be attached, otherwise returns false.
*/

View File

@ -18,6 +18,7 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.util.Log;
@ -897,9 +898,6 @@ public class MessageList
@Override
public void onBackPressed() {
// This will be called either automatically for you on 2.0
// or later, or by the code above on earlier versions of the
// platform.
if (K9.manageBack()) {
if (mQueryString == null) {
onShowFolderList();
@ -907,24 +905,12 @@ public class MessageList
onAccounts();
}
} else {
finish();
super.onBackPressed();
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (
// XXX TODO - when we go to android 2.0, uncomment this
// android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR &&
keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0
) {
// Take care of calling this method on earlier versions of
// the platform where it doesn't exist.
onBackPressed();
return true;
}
// Shortcuts that work no matter what is selected
switch (keyCode) {
@ -2181,7 +2167,7 @@ public class MessageList
0,
noSender.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
str.setSpan(K9.createAbsoluteSizeSpan(mFontSizes.getMessageListSender()),
str.setSpan(new AbsoluteSizeSpan(mFontSizes.getMessageListSender(), true),
0,
noSender.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
@ -2270,7 +2256,7 @@ public class MessageList
0,
message.sender.length() + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
str.setSpan(K9.createAbsoluteSizeSpan(mFontSizes.getMessageListSender()),
str.setSpan(new AbsoluteSizeSpan(mFontSizes.getMessageListSender(), true),
0,
message.sender.length() + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

View File

@ -27,8 +27,6 @@ import com.fsck.k9.view.SingleMessageView;
import com.fsck.k9.view.AttachmentView.AttachmentFileDownloadCallback;
import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
public class MessageView extends K9Activity implements OnClickListener {
@ -42,27 +40,6 @@ public class MessageView extends K9Activity implements OnClickListener {
private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2;
private static final int ACTIVITY_CHOOSE_DIRECTORY = 3;
/**
* Whether parent class have the onBackPressed() method (with no argument)
*/
private static final boolean HAS_SUPER_ON_BACK_METHOD;
static {
boolean hasOnBackMethod;
try {
final Class <? super MessageView > superClass = MessageView.class.getSuperclass();
final Method method = superClass.getMethod("onBackPressed", new Class[] {});
hasOnBackMethod = (method.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC;
} catch (final SecurityException e) {
if (K9.DEBUG) {
Log.v(K9.LOG_TAG, "Security exception while checking for 'onBackPressed' method", e);
}
hasOnBackMethod = false;
} catch (final NoSuchMethodException e) {
hasOnBackMethod = false;
}
HAS_SUPER_ON_BACK_METHOD = hasOnBackMethod;
}
private SingleMessageView mMessageView;
private PgpData mPgpData;
@ -140,7 +117,7 @@ public class MessageView extends K9Activity implements OnClickListener {
public boolean dispatchKeyEvent(KeyEvent event) {
boolean ret = false;
if (KeyEvent.ACTION_DOWN == event.getAction()) {
ret = onKeyDown(event.getKeyCode(), event);
ret = onCustomKeyDown(event.getKeyCode(), event);
}
if (!ret) {
ret = super.dispatchKeyEvent(event);
@ -148,29 +125,36 @@ public class MessageView extends K9Activity implements OnClickListener {
return ret;
}
@Override
public boolean onKeyDown(final int keyCode, final KeyEvent event) {
if (
// XXX TODO - when we go to android 2.0, uncomment this
// android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR &&
keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
// Take care of calling this method on earlier versions of
// the platform where it doesn't exist.
onBackPressed();
return true;
}
/**
* Handle hotkeys
*
* <p>
* This method is called by {@link #dispatchKeyEvent(KeyEvent)} before any view had the chance
* to consume this key event.
* </p>
*
* @param keyCode
* The value in {@code event.getKeyCode()}.
* @param event
* Description of the key event.
*
* @return {@code true} if this event was consumed.
*/
public boolean onCustomKeyDown(final int keyCode, final KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP: {
if (K9.useVolumeKeysForNavigationEnabled()) {
onNext();
return true;
}
break;
}
case KeyEvent.KEYCODE_VOLUME_DOWN: {
if (K9.useVolumeKeysForNavigationEnabled()) {
onPrevious();
return true;
}
break;
}
case KeyEvent.KEYCODE_SHIFT_LEFT:
case KeyEvent.KEYCODE_SHIFT_RIGHT: {
@ -245,7 +229,7 @@ public class MessageView extends K9Activity implements OnClickListener {
return true;
}
}
return super.onKeyDown(keyCode, event);
return false;
}
@Override
@ -263,17 +247,12 @@ public class MessageView extends K9Activity implements OnClickListener {
@Override
public void onBackPressed() {
// This will be called either automatically for you on 2.0
// or later, or by the code above on earlier versions of the
// platform.
if (K9.manageBack()) {
String folder = (mMessage != null) ? mMessage.getFolder().getName() : null;
MessageList.actionHandleFolder(this, mAccount, folder);
finish();
} else if (HAS_SUPER_ON_BACK_METHOD) {
super.onBackPressed();
} else {
finish();
super.onBackPressed();
}
}

View File

@ -9,7 +9,6 @@ import android.os.Bundle;
import android.os.Vibrator;
import android.preference.*;
import android.util.Log;
import android.view.KeyEvent;
import java.util.Iterator;
import java.util.Map;
@ -823,11 +822,9 @@ public class AccountSettings extends K9PreferenceActivity {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
saveSettings();
}
return super.onKeyDown(keyCode, event);
public void onBackPressed() {
saveSettings();
super.onBackPressed();
}
private void onCompositionSettings() {
@ -924,8 +921,8 @@ public class AccountSettings extends K9PreferenceActivity {
}
}
allFolderValues = new String[folders.size()+1];
allFolderLabels = new String[folders.size()+1];
allFolderValues = new String[folders.size() + 1];
allFolderLabels = new String[folders.size() + 1];
allFolderValues[0] = K9.FOLDER_NONE;
allFolderLabels[0] = K9.FOLDER_NONE;

View File

@ -3,7 +3,6 @@ package com.fsck.k9.activity.setup;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.CheckBox;
@ -121,11 +120,9 @@ public class AccountSetupComposition extends K9Activity {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
saveSettings();
}
return super.onKeyDown(keyCode, event);
public void onBackPressed() {
saveSettings();
super.onBackPressed();
}
@Override

View File

@ -8,7 +8,6 @@ import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.util.Log;
import android.view.KeyEvent;
import com.fsck.k9.*;
import com.fsck.k9.activity.K9PreferenceActivity;
import com.fsck.k9.mail.Folder.FolderClass;
@ -151,16 +150,13 @@ public class FolderSettings extends K9PreferenceActivity {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
try {
saveSettings();
} catch (MessagingException e) {
Log.e(K9.LOG_TAG, "Saving folder settings failed", e);
}
public void onBackPressed() {
try {
saveSettings();
} catch (MessagingException e) {
Log.e(K9.LOG_TAG, "Saving folder settings failed", e);
}
return super.onKeyDown(keyCode, event);
super.onBackPressed();
}
}

View File

@ -7,7 +7,6 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.*;
import android.view.KeyEvent;
import com.fsck.k9.*;
import com.fsck.k9.activity.K9PreferenceActivity;
@ -160,10 +159,8 @@ public class FontSizeSettings extends K9PreferenceActivity {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
saveSettings();
}
return super.onKeyDown(keyCode, event);
public void onBackPressed() {
saveSettings();
super.onBackPressed();
}
}

View File

@ -17,7 +17,6 @@ import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.view.KeyEvent;
import android.widget.Toast;
import com.fsck.k9.K9;
@ -268,7 +267,7 @@ public class Prefs extends K9PreferenceActivity {
mZoomControlsEnabled.setChecked(K9.zoomControlsEnabled());
mMobileOptimizedLayout = (CheckBoxPreference) findPreference(PREFERENCE_MESSAGEVIEW_MOBILE_LAYOUT);
if (Integer.parseInt(Build.VERSION.SDK) <= 7) {
if (Build.VERSION.SDK_INT <= 7) {
mMobileOptimizedLayout.setEnabled(false);
}
@ -404,16 +403,15 @@ public class Prefs extends K9PreferenceActivity {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
saveSettings();
if (K9.manageBack()) {
Accounts.listAccounts(this);
finish();
return true;
}
public void onBackPressed() {
saveSettings();
if (K9.manageBack()) {
Accounts.listAccounts(this);
finish();
} else {
super.onBackPressed();
}
return super.onKeyDown(keyCode, event);
}
private void onFontSizeSettings() {

View File

@ -1,115 +0,0 @@
package com.fsck.k9.helper;
import com.fsck.k9.K9;
import android.os.Build;
import android.util.Log;
/**
* Helper class to get the current state of the auto-sync setting.
*/
public class AutoSyncHelper {
/**
* False, if we never tried to load the class for this SDK version.
* True, otherwise.
*
* Note: if sAutoSync is null and sChecked is true, then an error occurred
* while loading the class for the SDK version we're running on.
*/
private static boolean sChecked = false;
/**
* Instance of the SDK specific class that implements the IAutoSync
* interface.
*/
private static IAutoSync sAutoSync = null;
/**
* String for the auto-sync changed Intent. This isn't currently exposed by the API
*/
public static String SYNC_CONN_STATUS_CHANGE = "com.android.sync.SYNC_CONN_STATUS_CHANGED";
/**
* Try loading the class that implements IAutoSync for this SDK version.
*
* @return the IAutoSync object for this SDK version, or null if something
* went wrong.
*/
private static IAutoSync loadAutoSync() {
/*
* We're trying to load the class for this SDK version. If anything
* goes wrong after this point, we don't want to try again.
*/
sChecked = true;
/*
* Check the version of the SDK we are running on. Choose an
* implementation class designed for that version of the SDK.
*/
int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
String className = null;
if (sdkVersion == Build.VERSION_CODES.CUPCAKE) {
className = "com.fsck.k9.helper.AutoSyncSdk3";
} else if (sdkVersion == Build.VERSION_CODES.DONUT) {
className = "com.fsck.k9.helper.AutoSyncSdk4";
} else if (sdkVersion >= Build.VERSION_CODES.ECLAIR) {
className = "com.fsck.k9.helper.AutoSyncSdk5";
}
/*
* Find the required class by name and instantiate it.
*/
try {
Class <? extends IAutoSync > clazz =
Class.forName(className).asSubclass(IAutoSync.class);
IAutoSync autoSync = clazz.newInstance();
autoSync.initialize(K9.app);
return autoSync;
} catch (ClassNotFoundException e) {
Log.e(K9.LOG_TAG, "Couldn't find class: " + className, e);
} catch (InstantiationException e) {
Log.e(K9.LOG_TAG, "Couldn't instantiate class: " + className, e);
} catch (IllegalAccessException e) {
Log.e(K9.LOG_TAG, "Couldn't access class: " + className, e);
} catch (NoSuchMethodException e) {
if (K9.DEBUG) {
Log.d(K9.LOG_TAG, "Couldn't load method to get auto-sync state", e);
}
}
return null;
}
/**
* Checks whether we can query the auto-sync state using
* getMasterSyncAutomatically() or not.
*
* @return true, if calls to getMasterSyncAutomatically() will return the
* state of the auto-sync setting. false, otherwise.
*/
public static boolean isAvailable() {
if (!sChecked) {
sAutoSync = loadAutoSync();
}
return (sAutoSync != null);
}
/**
* Query the state of the auto-sync setting.
*
* @return the state of the auto-sync setting.
* @see IAutoSync
*/
public static boolean getMasterSyncAutomatically() {
if (!sChecked) {
sAutoSync = loadAutoSync();
}
if (sAutoSync == null) {
throw new RuntimeException(
"Called getMasterSyncAutomatically() before checking if it's available.");
}
return sAutoSync.getMasterSyncAutomatically();
}
}

View File

@ -1,39 +0,0 @@
package com.fsck.k9.helper;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
public class AutoSyncSdk3 implements IAutoSync {
private Method mGetListenForNetworkTickles;
private Object mQueryMap;
public void initialize(Context context) throws NoSuchMethodException {
/*
* There's no documented/official way to query the state of the
* auto-sync setting for a normal application in SDK 1.5/API 3.
*
* We use reflection to get an Sync.Settings.QueryMap" object, so we
* can call its getListenForNetworkTickles() method. This will return
* the current auto-sync state.
*/
try {
Class<?> clazz = Class.forName("android.provider.Sync$Settings$QueryMap");
Constructor<?> c = clazz.getConstructor(ContentResolver.class, boolean.class, Handler.class);
mQueryMap = c.newInstance(context.getContentResolver(), true, null);
mGetListenForNetworkTickles = mQueryMap.getClass().getMethod("getListenForNetworkTickles");
} catch (Exception e) {
throw new NoSuchMethodException();
}
}
public boolean getMasterSyncAutomatically() {
try {
return (Boolean) mGetListenForNetworkTickles.invoke(mQueryMap);
} catch (Exception e) {
return false;
}
}
}

View File

@ -1,41 +0,0 @@
package com.fsck.k9.helper;
import java.lang.reflect.Method;
import com.fsck.k9.K9;
import android.content.ContentResolver;
import android.content.Context;
import android.util.Log;
public class AutoSyncSdk4 implements IAutoSync {
private Method mGetListenForNetworkTickles;
private Object mContentService;
public void initialize(Context context) throws NoSuchMethodException {
/*
* There's no documented/official way to query the state of the
* auto-sync setting for a normal application in SDK 1.6/API 4.
*
* We use reflection to get an ContentService object, so we can call its
* getListenForNetworkTickles() method. This will return the current
* auto-sync state.
*/
try {
Method getContentService = ContentResolver.class.getMethod("getContentService");
mContentService = getContentService.invoke(null);
mGetListenForNetworkTickles = mContentService.getClass().getMethod("getListenForNetworkTickles");
} catch (Exception e) {
throw new NoSuchMethodException();
}
}
public boolean getMasterSyncAutomatically() {
try {
return (Boolean) mGetListenForNetworkTickles.invoke(mContentService);
} catch (Exception e) {
Log.e(K9.LOG_TAG, "Could not query for network tickle", e);
return true;
}
}
}

View File

@ -1,18 +0,0 @@
package com.fsck.k9.helper;
import android.content.ContentResolver;
import android.content.Context;
public class AutoSyncSdk5 implements IAutoSync {
public void initialize(Context context) throws NoSuchMethodException {
// Nothing to do here
}
public boolean getMasterSyncAutomatically() {
/*
* SDK 2.0/API 5 introduced an official method to query the auto-sync
* state.
*/
return ContentResolver.getMasterSyncAutomatically();
}
}

View File

@ -18,8 +18,8 @@ import com.fsck.k9.mail.Address;
* A class that uses the latest contacts API available on the device will be
* loaded at runtime.
*
* @see ContactsSdk3_4
* @see ContactsSdk5
* @see ContactsSdk5p
*/
public abstract class Contacts {
/**
@ -40,12 +40,8 @@ public abstract class Contacts {
* Check the version of the SDK we are running on. Choose an
* implementation class designed for that version of the SDK.
*/
int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
String className = null;
if (sdkVersion <= Build.VERSION_CODES.DONUT) {
className = "com.fsck.k9.helper.ContactsSdk3_4";
} else if (sdkVersion <= Build.VERSION_CODES.ECLAIR_MR1) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ECLAIR_MR1) {
/*
* The new API was introduced with SDK 5. But Android versions < 2.2
* need some additional code to be able to search for phonetic names.

View File

@ -1,263 +0,0 @@
package com.fsck.k9.helper;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import android.provider.Contacts;
import android.provider.Contacts.ContactMethods;
import com.fsck.k9.mail.Address;
import com.fsck.k9.K9;
/**
* Access the contacts on the device using the old API (introduced in SDK 1).
*
* @see android.provider.Contacts
*/
@SuppressWarnings("deprecation")
public class ContactsSdk3_4 extends com.fsck.k9.helper.Contacts {
/**
* The order in which the search results are returned by
* {@link #searchContacts(CharSequence)}.
*/
private static final String SORT_ORDER =
Contacts.ContactMethods.TIMES_CONTACTED + " DESC, " +
Contacts.ContactMethods.DISPLAY_NAME + ", " +
Contacts.ContactMethods._ID;
/**
* Array of columns to load from the database.
*
* Important: The _ID field is needed by
* {@link com.fsck.k9.EmailAddressAdapter} or more specificly by
* {@link android.widget.ResourceCursorAdapter}.
*/
private static final String PROJECTION[] = {
Contacts.ContactMethods._ID,
Contacts.ContactMethods.DISPLAY_NAME,
Contacts.ContactMethods.DATA,
Contacts.ContactMethods.PERSON_ID
};
/**
* Index of the name field in the projection. This must match the order in
* {@link #PROJECTION}.
*/
private static final int NAME_INDEX = 1;
/**
* Index of the email address field in the projection. This must match the
* order in {@link #PROJECTION}.
*/
private static final int EMAIL_INDEX = 2;
/**
* Index of the contact id field in the projection. This must match the order in
* {@link #PROJECTION}.
*/
private static final int CONTACT_ID_INDEX = 3;
public ContactsSdk3_4(final Context context) {
super(context);
}
@Override
public void createContact(final Address email) {
final Uri contactUri = Uri.fromParts("mailto", email.getAddress(), null);
final Intent contactIntent = new Intent(Contacts.Intents.SHOW_OR_CREATE_CONTACT);
contactIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
contactIntent.setData(contactUri);
// Pass along full E-mail string for possible create dialog
contactIntent.putExtra(Contacts.Intents.EXTRA_CREATE_DESCRIPTION,
email.toString());
// Only provide personal name hint if we have one
final String senderPersonal = email.getPersonal();
if (senderPersonal != null) {
contactIntent.putExtra(Contacts.Intents.Insert.NAME, senderPersonal);
}
mContext.startActivity(contactIntent);
}
@Override
public boolean isInContacts(final String emailAddress) {
boolean result = false;
final Cursor c = getContactByAddress(emailAddress);
if (c != null) {
if (c.getCount() > 0) {
result = true;
}
c.close();
}
return result;
}
@Override
public Cursor searchContacts(final CharSequence constraint) {
final String where;
final String[] args;
if (constraint == null) {
where = Contacts.ContactMethods.KIND + " = " + Contacts.KIND_EMAIL;
args = null;
} else {
where = Contacts.ContactMethods.KIND + " = " + Contacts.KIND_EMAIL +
" AND " +
"(" +
// Match if name starts with "constraint"
Contacts.People.NAME + " LIKE ?" +
" OR " +
// Match if name contains a word that starts with "constraint"
Contacts.People.NAME + " LIKE ?" +
" OR " +
// Match if phonetic name starts with "constraint"
Contacts.People.PHONETIC_NAME + " LIKE ?" +
" OR " +
// Match if phonetic name contains a word that starts with "constraint"
Contacts.People.PHONETIC_NAME + " LIKE ?" +
" OR " +
// Match if email address starts with "constraint"
Contacts.ContactMethods.DATA + " LIKE ?" +
")";
final String filter = constraint.toString() + "%";
final String filter2 = "% " + filter;
args = new String[] {filter, filter2, filter, filter2, filter};
}
final Cursor c = mContentResolver.query(
Contacts.ContactMethods.CONTENT_URI,
PROJECTION,
where,
args,
SORT_ORDER);
if (c != null) {
/*
* To prevent expensive execution in the UI thread:
* Cursors get lazily executed, so if you don't call anything on
* the cursor before returning it from the background thread you'll
* have a complied program for the cursor, but it won't have been
* executed to generate the data yet. Often the execution is more
* expensive than the compilation...
*/
c.getCount();
}
return c;
}
@Override
public String getNameForAddress(String address) {
if (address == null) {
return null;
}
final Cursor c = getContactByAddress(address);
String name = null;
if (c != null) {
if (c.getCount() > 0) {
c.moveToFirst();
name = getName(c);
}
c.close();
}
return name;
}
@Override
public String getName(Cursor c) {
return c.getString(NAME_INDEX);
}
@Override
public String getEmail(Cursor c) {
return c.getString(EMAIL_INDEX);
}
@Override
public void markAsContacted(final Address[] addresses) {
//TODO: Optimize! Potentially a lot of database queries
for (final Address address : addresses) {
final Cursor c = getContactByAddress(address.getAddress());
if (c != null) {
if (c.getCount() > 0) {
c.moveToFirst();
final long personId = c.getLong(CONTACT_ID_INDEX);
Contacts.People.markAsContacted(mContentResolver, personId);
}
c.close();
}
}
}
@Override
public Intent contactPickerIntent() {
return new Intent(Intent.ACTION_PICK, Contacts.People.CONTENT_URI);
}
@Override
public String getEmailFromContactPicker(final Intent data) {
Cursor cursor = null;
Cursor cursor2 = null;
String email = "";
try {
Uri result = data.getData();
cursor = mContentResolver.query(result, null, null, null, null);
if (cursor.moveToFirst()) {
String emailId = cursor.getString(cursor.getColumnIndex(Contacts.People.PRIMARY_EMAIL_ID));
cursor2 = mContext.getContentResolver().query(
ContactMethods.CONTENT_EMAIL_URI,
new String[] { ContactMethods.DATA },
"contact_methods._id=?",
new String[] { emailId },
null);
if (cursor2.moveToFirst()) {
email = cursor2.getString(0);
}
}
} catch (Exception e) {
Log.e(K9.LOG_TAG, "Failed to get email data", e);
} finally {
Utility.closeQuietly(cursor);
Utility.closeQuietly(cursor2);
}
return email;
}
/**
* Return a {@link Cursor} instance that can be used to fetch information
* about the contact with the given email address.
*
* @param address The email address to search for.
* @return A {@link Cursor} instance that can be used to fetch information
* about the contact with the given email address
*/
private Cursor getContactByAddress(String address) {
final String where = Contacts.ContactMethods.KIND + " = " + Contacts.KIND_EMAIL +
" AND " +
Contacts.ContactMethods.DATA + " = ?";
final String[] args = new String[] {address};
final Cursor c = mContentResolver.query(
Contacts.ContactMethods.CONTENT_URI,
PROJECTION,
where,
args,
SORT_ORDER);
return c;
}
}

View File

@ -1,26 +0,0 @@
package com.fsck.k9.helper;
import android.content.Context;
/**
* Classes that implement this interface know how to query the system for the
* current state of the auto-sync setting. This method differs from SDK 3 to
* SDK 5, so there are specialized implementations for each SDK version.
*/
public interface IAutoSync {
/**
* Do the necessary reflection magic to get the necessary objects and/or
* methods to later query the state of the auto-sync setting.
*
* @param context The application context object.
* @throws NoSuchMethodException if something went wrong.
*/
public void initialize(Context context) throws NoSuchMethodException;
/**
* Query the state of the auto-sync setting.
*
* @return the state of the auto-sync setting.
*/
public boolean getMasterSyncAutomatically();
}

View File

@ -1081,7 +1081,7 @@ public class MimeUtility {
*/
if (contentTransferEncoding != null) {
contentTransferEncoding =
MimeUtility.getHeaderParameter(contentTransferEncoding, null);
MimeUtility.getHeaderParameter(contentTransferEncoding, null);
if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) {
in = new QuotedPrintableInputStream(in);
} else if ("base64".equalsIgnoreCase(contentTransferEncoding)) {
@ -1107,7 +1107,7 @@ public class MimeUtility {
* @throws MessagingException
*/
public static void collectParts(Part part, ArrayList<Part> viewables,
ArrayList<Part> attachments) throws MessagingException {
ArrayList<Part> attachments) throws MessagingException {
/*
* If the part is Multipart but not alternative it's either mixed or
* something we don't know about, which means we treat it as mixed
@ -1334,10 +1334,10 @@ public class MimeUtility {
private static String getJisVariantFromAddress(String address) {
if (isInDomain(address, "docomo.ne.jp") || isInDomain(address, "dwmail.jp") ||
isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
return "docomo";
else if (isInDomain(address, "softbank.ne.jp") || isInDomain(address, "vodafone.ne.jp") ||
isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp"))
isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp"))
return "softbank";
else if (isInDomain(address, "ezweb.ne.jp") || isInDomain(address, "ido.ne.jp"))
return "kddi";
@ -1372,14 +1372,14 @@ public class MimeUtility {
// iso-2022-jp variants are supported by no versions as of Dec 2010.
if (charset.length() > 19 && charset.startsWith("x-") &&
charset.endsWith("-iso-2022-jp-2007") && !Charset.isSupported(charset)) {
charset.endsWith("-iso-2022-jp-2007") && !Charset.isSupported(charset)) {
in = new Iso2022JpToShiftJisInputStream(in);
charset = "x-" + charset.substring(2, charset.length() - 17) + "-shift_jis-2007";
}
// shift_jis variants are supported by Eclair and later.
if (charset.length() > 17 && charset.startsWith("x-") &&
charset.endsWith("-shift_jis-2007") && !Charset.isSupported(charset)) {
charset.endsWith("-shift_jis-2007") && !Charset.isSupported(charset)) {
// If the JIS variant is iPhone, map the Unicode private use area in iPhone to the one in Android after
// converting the character set from the standard Shift JIS to Unicode.
if (charset.substring(2, charset.length() - 15).equals("iphone"))
@ -1400,7 +1400,7 @@ public class MimeUtility {
}
if (!supported) {
Log.e(K9.LOG_TAG, "I don't know how to deal with the charset " + charset +
". Falling back to US-ASCII");
". Falling back to US-ASCII");
charset = "US-ASCII";
}
/*
@ -2401,12 +2401,12 @@ public class MimeUtility {
public static void setCharset(String charset, Part part) throws MessagingException {
part.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
part.getMimeType() + ";\n charset=" + getExternalCharset(charset));
part.getMimeType() + ";\n charset=" + getExternalCharset(charset));
}
public static String getExternalCharset(String charset) {
if (charset.length() > 17 && charset.startsWith("x-") &&
charset.endsWith("-shift_jis-2007"))
charset.endsWith("-shift_jis-2007"))
return "shift_jis";
return charset;

View File

@ -1,5 +1,6 @@
package com.fsck.k9.mail.store;
import android.text.TextUtils;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.filter.FixedLengthInputStream;
import com.fsck.k9.mail.filter.PeekableInputStream;
@ -44,10 +45,8 @@ public class ImapResponseParser {
parseUntaggedResponse();
readTokens(response);
} else if (ch == '+') {
response.mCommandContinuationRequested =
parseCommandContinuationRequest();
//TODO: Add special "resp-text" parsing
readTokens(response);
response.mCommandContinuationRequested = parseCommandContinuationRequest();
parseResponseText(response);
} else {
response.mTag = parseTaggedResponse();
readTokens(response);
@ -67,24 +66,72 @@ public class ImapResponseParser {
private void readTokens(ImapResponse response) throws IOException {
response.clear();
Object token;
while ((token = readToken(response)) != null) {
if (!(token instanceof ImapList)) {
response.add(token);
}
/*
* TODO: Check for responses ("OK", "PREAUTH", "BYE", "NO", "BAD")
* that can contain resp-text tokens. If found, hand over to a special
* method that parses a resp-text token. There's no need to use
* readToken()/parseToken() on that data.
*
* See RFC 3501, Section 9 Formal Syntax (resp-text)
*/
String firstToken = (String) readToken(response);
response.add(firstToken);
if (isStatusResponse(firstToken)) {
parseResponseText(response);
} else {
Object token;
while ((token = readToken(response)) != null) {
if (!(token instanceof ImapList)) {
response.add(token);
}
}
}
response.mCompleted = true;
}
/**
* Parse {@code resp-text} tokens
*
* <p>
* Responses "OK", "PREAUTH", "BYE", "NO", "BAD", and continuation request responses can
* contain {@code resp-text} tokens. We parse the {@code resp-text-code} part as tokens and
* read the rest as sequence of characters to avoid the parser interpreting things like
* "{123}" as start of a literal.
* </p>
* <p>Example:</p>
* <p>
* {@code * OK [UIDVALIDITY 3857529045] UIDs valid}
* </p>
* <p>
* See RFC 3501, Section 9 Formal Syntax (resp-text)
* </p>
*
* @param parent
* The {@link ImapResponse} instance that holds the parsed tokens of the response.
*
* @throws IOException
* If there's a network error.
*
* @see #isStatusResponse(String)
*/
private void parseResponseText(ImapResponse parent) throws IOException {
skipIfSpace();
int next = mIn.peek();
if (next == '[') {
parseSequence(parent);
skipIfSpace();
}
String rest = readStringUntil('\r');
expect('\n');
if (!TextUtils.isEmpty(rest)) {
// The rest is free-form text.
parent.add(rest);
}
}
private void skipIfSpace() throws IOException {
if (mIn.peek() == ' ') {
expect(' ');
}
}
/**
* Reads the next token of the response. The token can be one of: String -
* for NIL, QUOTED, NUMBER, ATOM. Object - for LITERAL.
@ -480,6 +527,14 @@ public class ImapResponseParser {
}
}
public boolean isStatusResponse(String symbol) {
return symbol.equalsIgnoreCase("OK") ||
symbol.equalsIgnoreCase("NO") ||
symbol.equalsIgnoreCase("BAD") ||
symbol.equalsIgnoreCase("PREAUTH") ||
symbol.equalsIgnoreCase("BYE");
}
public static boolean equalsIgnoreCase(Object o1, Object o2) {
if (o1 != null && o2 != null && o1 instanceof String && o2 instanceof String) {
String s1 = (String)o1;

View File

@ -12,7 +12,6 @@ import android.net.Uri;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.helper.AutoSyncHelper;
public class BootReceiver extends CoreReceiver {
@ -41,7 +40,7 @@ public class BootReceiver extends CoreReceiver {
} else if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
MailService.connectivityChange(context, tmpWakeLockId);
tmpWakeLockId = null;
} else if (AutoSyncHelper.SYNC_CONN_STATUS_CHANGE.equals(action)) {
} else if ("com.android.sync.SYNC_CONN_STATUS_CHANGED".equals(action)) {
K9.BACKGROUND_OPS bOps = K9.getBackgroundOps();
if (bOps == K9.BACKGROUND_OPS.WHEN_CHECKED_AUTO_SYNC) {
MailService.actionReset(context, tmpWakeLockId);

View File

@ -199,9 +199,7 @@ public abstract class CoreService extends Service {
}
@Override
public final void onStart(Intent intent, int startId) {
// deprecated method but still used for backwards compatibility with Android version <2.0
public final int onStartCommand(Intent intent, int flags, int startId) {
/*
* When a process is killed due to low memory, it's later restarted and services that were
* started with START_STICKY are started with the intent being null.
@ -213,7 +211,7 @@ public abstract class CoreService extends Service {
*/
if (intent == null) {
stopSelf(startId);
return;
return START_NOT_STICKY;
}
// Acquire new wake lock
@ -253,9 +251,9 @@ public abstract class CoreService extends Service {
// Run the actual start-code of the service
mImmediateShutdown = true;
int startFlag;
try {
super.onStart(intent, startId);
startService(intent, startId);
startFlag = startService(intent, startId);
} finally {
try {
// Release the wake lock acquired at the start of this method
@ -267,9 +265,12 @@ public abstract class CoreService extends Service {
// this service.
if (mAutoShutdown && mImmediateShutdown && startId != -1) {
stopSelf(startId);
startFlag = START_NOT_STICKY;
}
} catch (Exception e) { /* ignore */ }
}
return startFlag;
}
/**
@ -371,7 +372,7 @@ public abstract class CoreService extends Service {
}
/**
* Subclasses need to implement this instead of overriding {@link #onStart(Intent, int)}.
* Subclasses need to implement this instead of overriding {@link #onStartCommand(Intent, int, int)}.
*
* <p>
* This allows {@link CoreService} to manage the service lifecycle, incl. wake lock management.
@ -382,8 +383,12 @@ public abstract class CoreService extends Service {
* @param startId
* A unique integer representing this specific request to start. Use with
* {@link #stopSelfResult(int)}.
*
* @return The return value indicates what semantics the system should use for the service's
* current started state. It may be one of the constants associated with the
* {@link Service#START_CONTINUATION_MASK} bits.
*/
public abstract void startService(Intent intent, int startId);
public abstract int startService(Intent intent, int startId);
@Override
public void onLowMemory() {

View File

@ -4,6 +4,7 @@ package com.fsck.k9.service;
import java.util.Collection;
import java.util.Date;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -18,7 +19,6 @@ import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.Account.FolderMode;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.helper.AutoSyncHelper;
import com.fsck.k9.mail.Pusher;
public class MailService extends CoreService {
@ -84,7 +84,7 @@ public class MailService extends CoreService {
}
@Override
public void startService(Intent intent, int startId) {
public int startService(Intent intent, int startId) {
long startTime = System.currentTimeMillis();
boolean oldIsSyncDisabled = isSyncDisabled();
ConnectivityManager connectivityManager = (ConnectivityManager)getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
@ -98,12 +98,7 @@ public class MailService extends CoreService {
hasConnectivity = state == State.CONNECTED;
}
boolean backgroundData = connectivityManager.getBackgroundDataSetting();
boolean autoSync = true;
if (AutoSyncHelper.isAvailable()) {
autoSync = AutoSyncHelper.getMasterSyncAutomatically();
Log.i(K9.LOG_TAG, "AutoSync help is available, autoSync = " + autoSync);
}
boolean autoSync = ContentResolver.getMasterSyncAutomatically();
K9.BACKGROUND_OPS bOps = K9.getBackgroundOps();
@ -170,6 +165,8 @@ public class MailService extends CoreService {
if (K9.DEBUG)
Log.i(K9.LOG_TAG, "MailService.onStart took " + (System.currentTimeMillis() - startTime) + "ms");
return START_NOT_STICKY;
}
@Override

View File

@ -42,7 +42,7 @@ public class PollService extends CoreService {
}
@Override
public void startService(Intent intent, int startId) {
public int startService(Intent intent, int startId) {
if (START_SERVICE.equals(intent.getAction())) {
if (K9.DEBUG)
Log.i(K9.LOG_TAG, "PollService started with startId = " + startId);
@ -68,6 +68,7 @@ public class PollService extends CoreService {
stopSelf();
}
return START_NOT_STICKY;
}
@Override

View File

@ -27,7 +27,8 @@ public class PushService extends CoreService {
}
@Override
public void startService(Intent intent, int startId) {
public int startService(Intent intent, int startId) {
int startFlag = START_STICKY;
if (START_SERVICE.equals(intent.getAction())) {
if (K9.DEBUG)
Log.i(K9.LOG_TAG, "PushService started with startId = " + startId);
@ -35,8 +36,10 @@ public class PushService extends CoreService {
if (K9.DEBUG)
Log.i(K9.LOG_TAG, "PushService stopping with startId = " + startId);
stopSelf(startId);
startFlag = START_NOT_STICKY;
}
return startFlag;
}
@Override

View File

@ -34,7 +34,7 @@ public class RemoteControlService extends CoreService {
public static final int REMOTE_CONTROL_SERVICE_WAKE_LOCK_TIMEOUT = 20000;
@Override
public void startService(final Intent intent, final int startId) {
public int startService(final Intent intent, final int startId) {
if (K9.DEBUG)
Log.i(K9.LOG_TAG, "RemoteControlService started with startId = " + startId);
final Preferences preferences = Preferences.getPreferences(this);
@ -155,6 +155,8 @@ public class RemoteControlService extends CoreService {
}
, RemoteControlService.REMOTE_CONTROL_SERVICE_WAKE_LOCK_TIMEOUT, startId);
}
return START_NOT_STICKY;
}
}

View File

@ -113,12 +113,13 @@ public class SleepService extends CoreService {
}
@Override
public void startService(Intent intent, int startId) {
public int startService(Intent intent, int startId) {
try {
if (intent.getAction().startsWith(ALARM_FIRED)) {
Integer id = intent.getIntExtra(LATCH_ID, -1);
endSleep(id);
}
return START_NOT_STICKY;
}
finally {
stopSelf(startId);

View File

@ -91,9 +91,7 @@ public class MessageWebView extends WebView {
// SINGLE_COLUMN layout was broken on Android < 2.2, so we
// administratively disable it
if (
(Integer.parseInt(Build.VERSION.SDK) > 7)
&& K9.mobileOptimizedLayout()) {
if (Build.VERSION.SDK_INT > 7 && K9.mobileOptimizedLayout()) {
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
} else {
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);

View File

@ -0,0 +1,67 @@
package com.fsck.k9.mail.store;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import com.fsck.k9.mail.filter.PeekableInputStream;
import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
import junit.framework.TestCase;
public class ImapResponseParserTest extends TestCase {
public void testSimpleOkResponse() throws IOException {
ImapResponseParser parser = createParser("* OK\r\n");
ImapResponse response = parser.readResponse();
assertNotNull(response);
assertEquals(1, response.size());
assertEquals("OK", response.get(0));
}
public void testOkResponseWithText() throws IOException {
ImapResponseParser parser = createParser("* OK Some text here\r\n");
ImapResponse response = parser.readResponse();
assertNotNull(response);
assertEquals(2, response.size());
assertEquals("OK", response.get(0));
assertEquals("Some text here", response.get(1));
}
public void testOkResponseWithRespTextCode() throws IOException {
ImapResponseParser parser = createParser("* OK [UIDVALIDITY 3857529045]\r\n");
ImapResponse response = parser.readResponse();
assertNotNull(response);
assertEquals(2, response.size());
assertEquals("OK", response.get(0));
assertTrue(response.get(1) instanceof ImapList);
ImapList respTextCode = (ImapList) response.get(1);
assertEquals(2, respTextCode.size());
assertEquals("UIDVALIDITY", respTextCode.get(0));
assertEquals("3857529045", respTextCode.get(1));
}
public void testOkResponseWithRespTextCodeAndText() throws IOException {
ImapResponseParser parser = createParser("* OK [token1 token2] {x} test [...]\r\n");
ImapResponse response = parser.readResponse();
assertNotNull(response);
assertEquals(3, response.size());
assertEquals("OK", response.get(0));
assertTrue(response.get(1) instanceof ImapList);
assertEquals("{x} test [...]", response.get(2));
ImapList respTextCode = (ImapList) response.get(1);
assertEquals(2, respTextCode.size());
assertEquals("token1", respTextCode.get(0));
assertEquals("token2", respTextCode.get(1));
}
private ImapResponseParser createParser(String response) {
ByteArrayInputStream in = new ByteArrayInputStream(response.getBytes());
PeekableInputStream pin = new PeekableInputStream(in);
return new ImapResponseParser(pin);
}
}