mirror of
https://github.com/moparisthebest/k-9
synced 2024-12-25 17:18:50 -05:00
Added option to have attachments store on sd card
(this is still a rough implementation)
This commit is contained in:
parent
49b223e20c
commit
55dac7ee4e
@ -655,4 +655,10 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
|||||||
|
|
||||||
<string name="remote_control_label">K-9 Mail remote control</string>
|
<string name="remote_control_label">K-9 Mail remote control</string>
|
||||||
<string name="remote_control_desc">Allows this application to control K-9 Mail activities and settings.</string>
|
<string name="remote_control_desc">Allows this application to control K-9 Mail activities and settings.</string>
|
||||||
|
|
||||||
|
<string name="account_setup_store_attachment_on_sd_card_label">Attachments On SD Cards</string>
|
||||||
|
<string name="account_setup_store_attachment_on_sd_card_summary">Whether or not attachments are store on the SD card</string>
|
||||||
|
<string name="account_setup_store_attachment_on_sd_card_error">No SD card found</string>
|
||||||
|
|
||||||
|
<string name="sd_card_error">No SD card found</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -30,9 +30,16 @@
|
|||||||
android:key="account_default"
|
android:key="account_default"
|
||||||
android:title="@string/account_settings_default_label"
|
android:title="@string/account_settings_default_label"
|
||||||
android:summary="@string/account_settings_default_summary" />
|
android:summary="@string/account_settings_default_summary" />
|
||||||
</PreferenceCategory>
|
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/account_settings_message_lists">
|
<CheckBoxPreference
|
||||||
|
android:key="account_setup_store_attachment_on_sd_card"
|
||||||
|
android:title="@string/account_setup_store_attachment_on_sd_card_label"
|
||||||
|
android:summary="@string/account_setup_store_attachment_on_sd_card_summary" />
|
||||||
|
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
|
||||||
|
<PreferenceCategory android:title="@string/account_settings_message_lists">
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="account_display_count"
|
android:key="account_display_count"
|
||||||
@ -40,9 +47,9 @@
|
|||||||
android:entries="@array/account_settings_display_count_entries"
|
android:entries="@array/account_settings_display_count_entries"
|
||||||
android:entryValues="@array/account_settings_display_count_values"
|
android:entryValues="@array/account_settings_display_count_values"
|
||||||
android:dialogTitle="@string/account_settings_mail_display_count_label" />
|
android:dialogTitle="@string/account_settings_mail_display_count_label" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/account_settings_message_view">
|
<PreferenceCategory android:title="@string/account_settings_message_view">
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="hide_buttons_enum"
|
android:key="hide_buttons_enum"
|
||||||
@ -51,9 +58,9 @@
|
|||||||
android:entryValues="@array/account_settings_hide_buttons_values"
|
android:entryValues="@array/account_settings_hide_buttons_values"
|
||||||
android:dialogTitle="@string/account_settings_hide_buttons_label" />
|
android:dialogTitle="@string/account_settings_hide_buttons_label" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/account_settings_sync">
|
<PreferenceCategory android:title="@string/account_settings_sync">
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="account_check_frequency"
|
android:key="account_check_frequency"
|
||||||
android:title="@string/account_settings_mail_check_frequency_label"
|
android:title="@string/account_settings_mail_check_frequency_label"
|
||||||
@ -102,7 +109,7 @@
|
|||||||
android:summary="@string/account_settings_incoming_summary"
|
android:summary="@string/account_settings_incoming_summary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/account_settings_folders">
|
<PreferenceCategory android:title="@string/account_settings_folders">
|
||||||
|
|
||||||
|
@ -60,10 +60,11 @@ public class Account implements Serializable
|
|||||||
boolean mIsSignatureBeforeQuotedText;
|
boolean mIsSignatureBeforeQuotedText;
|
||||||
private String mExpungePolicy = EXPUNGE_IMMEDIATELY;
|
private String mExpungePolicy = EXPUNGE_IMMEDIATELY;
|
||||||
private int mMaxPushFolders;
|
private int mMaxPushFolders;
|
||||||
|
private boolean mStoreAttachmentsOnSdCard;
|
||||||
|
|
||||||
List<Identity> identities;
|
List<Identity> identities;
|
||||||
|
|
||||||
public enum FolderMode
|
public enum FolderMode
|
||||||
{
|
{
|
||||||
NONE, ALL, FIRST_CLASS, FIRST_AND_SECOND_CLASS, NOT_SECOND_CLASS;
|
NONE, ALL, FIRST_CLASS, FIRST_AND_SECOND_CLASS, NOT_SECOND_CLASS;
|
||||||
}
|
}
|
||||||
@ -274,7 +275,6 @@ public class Account implements Serializable
|
|||||||
mFolderPushMode = FolderMode.FIRST_CLASS;
|
mFolderPushMode = FolderMode.FIRST_CLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mFolderTargetMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderTargetMode",
|
mFolderTargetMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderTargetMode",
|
||||||
@ -286,6 +286,7 @@ public class Account implements Serializable
|
|||||||
}
|
}
|
||||||
|
|
||||||
mIsSignatureBeforeQuotedText = preferences.getPreferences().getBoolean(mUuid + ".signatureBeforeQuotedText", false);
|
mIsSignatureBeforeQuotedText = preferences.getPreferences().getBoolean(mUuid + ".signatureBeforeQuotedText", false);
|
||||||
|
mStoreAttachmentsOnSdCard = preferences.getPreferences().getBoolean(mUuid + ".storeAttachmentOnSdCard", true);
|
||||||
identities = loadIdentities(preferences.getPreferences());
|
identities = loadIdentities(preferences.getPreferences());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,6 +531,7 @@ public class Account implements Serializable
|
|||||||
editor.remove(mUuid + ".signatureBeforeQuotedText");
|
editor.remove(mUuid + ".signatureBeforeQuotedText");
|
||||||
editor.remove(mUuid + ".expungePolicy");
|
editor.remove(mUuid + ".expungePolicy");
|
||||||
editor.remove(mUuid + ".maxPushFolders");
|
editor.remove(mUuid + ".maxPushFolders");
|
||||||
|
editor.remove(mUuid + ".storeAttachmentOnSdCard");
|
||||||
deleteIdentities(preferences.getPreferences(), editor);
|
deleteIdentities(preferences.getPreferences(), editor);
|
||||||
editor.commit();
|
editor.commit();
|
||||||
}
|
}
|
||||||
@ -602,6 +604,7 @@ public class Account implements Serializable
|
|||||||
editor.putBoolean(mUuid + ".signatureBeforeQuotedText", this.mIsSignatureBeforeQuotedText);
|
editor.putBoolean(mUuid + ".signatureBeforeQuotedText", this.mIsSignatureBeforeQuotedText);
|
||||||
editor.putString(mUuid + ".expungePolicy", mExpungePolicy);
|
editor.putString(mUuid + ".expungePolicy", mExpungePolicy);
|
||||||
editor.putInt(mUuid + ".maxPushFolders", mMaxPushFolders);
|
editor.putInt(mUuid + ".maxPushFolders", mMaxPushFolders);
|
||||||
|
editor.putBoolean(mUuid + ".storeAttachmentOnSdCard", mStoreAttachmentsOnSdCard);
|
||||||
saveIdentities(preferences.getPreferences(), editor);
|
saveIdentities(preferences.getPreferences(), editor);
|
||||||
|
|
||||||
editor.commit();
|
editor.commit();
|
||||||
@ -965,4 +968,13 @@ public class Account implements Serializable
|
|||||||
mRing = ring;
|
mRing = ring;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isStoreAttachmentOnSdCard()
|
||||||
|
{
|
||||||
|
return mStoreAttachmentsOnSdCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStoreAttachmentOnSdCard(boolean mStoreAttachmentOnSdCard)
|
||||||
|
{
|
||||||
|
this.mStoreAttachmentsOnSdCard = mStoreAttachmentOnSdCard;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import android.app.PendingIntent;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
@ -46,7 +47,6 @@ import com.fsck.k9.mail.Folder;
|
|||||||
import com.fsck.k9.mail.Message;
|
import com.fsck.k9.mail.Message;
|
||||||
import com.fsck.k9.mail.MessageRemovalListener;
|
import com.fsck.k9.mail.MessageRemovalListener;
|
||||||
import com.fsck.k9.mail.MessageRetrievalListener;
|
import com.fsck.k9.mail.MessageRetrievalListener;
|
||||||
import com.fsck.k9.mail.MessagingException;
|
|
||||||
import com.fsck.k9.mail.Part;
|
import com.fsck.k9.mail.Part;
|
||||||
import com.fsck.k9.mail.PushReceiver;
|
import com.fsck.k9.mail.PushReceiver;
|
||||||
import com.fsck.k9.mail.Pusher;
|
import com.fsck.k9.mail.Pusher;
|
||||||
@ -54,6 +54,7 @@ import com.fsck.k9.mail.Store;
|
|||||||
import com.fsck.k9.mail.Transport;
|
import com.fsck.k9.mail.Transport;
|
||||||
import com.fsck.k9.mail.Folder.FolderType;
|
import com.fsck.k9.mail.Folder.FolderType;
|
||||||
import com.fsck.k9.mail.Folder.OpenMode;
|
import com.fsck.k9.mail.Folder.OpenMode;
|
||||||
|
import com.fsck.k9.mail.MessagingException;
|
||||||
import com.fsck.k9.mail.internet.MimeMessage;
|
import com.fsck.k9.mail.internet.MimeMessage;
|
||||||
import com.fsck.k9.mail.internet.MimeUtility;
|
import com.fsck.k9.mail.internet.MimeUtility;
|
||||||
import com.fsck.k9.mail.internet.TextBody;
|
import com.fsck.k9.mail.internet.TextBody;
|
||||||
@ -61,6 +62,10 @@ import com.fsck.k9.mail.store.LocalStore;
|
|||||||
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
|
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
|
||||||
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
|
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
|
||||||
import com.fsck.k9.mail.store.LocalStore.PendingCommand;
|
import com.fsck.k9.mail.store.LocalStore.PendingCommand;
|
||||||
|
import com.fsck.k9.mail.transport.EOLConvertingOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a long running (application) Thread that will run through commands
|
* Starts a long running (application) Thread that will run through commands
|
||||||
@ -3858,13 +3863,19 @@ public class MessagingController implements Runnable
|
|||||||
|
|
||||||
for (final Account account : accounts)
|
for (final Account account : accounts)
|
||||||
{
|
{
|
||||||
|
if (account.isStoreAttachmentOnSdCard()
|
||||||
|
&& !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
if (K9.DEBUG)
|
||||||
|
Log.i(K9.LOG_TAG, "SD card not mounted: skipping synchronizing account " + account.getDescription());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final long accountInterval = account.getAutomaticCheckIntervalMinutes() * 60 * 1000;
|
final long accountInterval = account.getAutomaticCheckIntervalMinutes() * 60 * 1000;
|
||||||
if (ignoreLastCheckedTime == false && accountInterval <= 0)
|
if (ignoreLastCheckedTime == false && accountInterval <= 0)
|
||||||
{
|
{
|
||||||
if (K9.DEBUG)
|
if (K9.DEBUG)
|
||||||
Log.i(K9.LOG_TAG, "Skipping synchronizing account " + account.getDescription());
|
Log.i(K9.LOG_TAG, "Skipping synchronizing account " + account.getDescription());
|
||||||
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3947,8 +3958,6 @@ public class MessagingController implements Runnable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (K9.DEBUG)
|
if (K9.DEBUG)
|
||||||
Log.v(K9.LOG_TAG, "Folder " + folder.getName() + " was last synced @ " +
|
Log.v(K9.LOG_TAG, "Folder " + folder.getName() + " was last synced @ " +
|
||||||
new Date(folder.getLastChecked()));
|
new Date(folder.getLastChecked()));
|
||||||
@ -3967,6 +3976,16 @@ public class MessagingController implements Runnable
|
|||||||
{
|
{
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
|
//Let's be conservative and check the sd card
|
||||||
|
//in case it was unmounted while we are sync'ing this account
|
||||||
|
if (account.isStoreAttachmentOnSdCard()
|
||||||
|
&& !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
if (K9.DEBUG)
|
||||||
|
Log.i(K9.LOG_TAG, "SD card not mounted: skipping synchronizing: account " + account.getDescription() + " folder=" + folder.getName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LocalFolder tLocalFolder = null;
|
LocalFolder tLocalFolder = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -4010,7 +4029,6 @@ public class MessagingController implements Runnable
|
|||||||
{
|
{
|
||||||
synchronizeMailboxSynchronous(account, folder.getName(), listener);
|
synchronizeMailboxSynchronous(account, folder.getName(), listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (account.isShowOngoing())
|
if (account.isShowOngoing())
|
||||||
@ -4523,6 +4541,14 @@ public class MessagingController implements Runnable
|
|||||||
{
|
{
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
|
if (account.isStoreAttachmentOnSdCard()
|
||||||
|
&& !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
if (K9.DEBUG)
|
||||||
|
Log.i(K9.LOG_TAG, "SD card not mounted: skipping reception of pushed messages: account=" + account.getDescription() + ", folder=" + remoteFolder.getName() + ", message count=" + messages.size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LocalFolder localFolder = null;
|
LocalFolder localFolder = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@ import android.content.Intent;
|
|||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.view.*;
|
import android.view.*;
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
@ -377,6 +378,13 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
|||||||
|
|
||||||
private void onCheckMail(Account account)
|
private void onCheckMail(Account account)
|
||||||
{
|
{
|
||||||
|
if (account.isStoreAttachmentOnSdCard()
|
||||||
|
&& !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
Toast.makeText(this, R.string.sd_card_error, Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MessagingController.getInstance(getApplication()).checkMail(this, account, true, true, null);
|
MessagingController.getInstance(getApplication()).checkMail(this, account, true, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import android.content.DialogInterface;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
@ -172,6 +173,13 @@ public class FolderList extends K9ListActivity
|
|||||||
|
|
||||||
private void checkMail(FolderInfoHolder folder)
|
private void checkMail(FolderInfoHolder folder)
|
||||||
{
|
{
|
||||||
|
if (mAccount.isStoreAttachmentOnSdCard()
|
||||||
|
&& !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
Toast.makeText(this, R.string.sd_card_error, Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||||
final WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email - UpdateWorker");
|
final WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email - UpdateWorker");
|
||||||
wakeLock.setReferenceCounted(false);
|
wakeLock.setReferenceCounted(false);
|
||||||
@ -447,6 +455,13 @@ public class FolderList extends K9ListActivity
|
|||||||
|
|
||||||
private void checkMail(final Account account)
|
private void checkMail(final Account account)
|
||||||
{
|
{
|
||||||
|
if (mAccount.isStoreAttachmentOnSdCard()
|
||||||
|
&& !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
Toast.makeText(this, R.string.sd_card_error, Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MessagingController.getInstance(getApplication()).checkMail(this, account, true, true, mAdapter.mListener);
|
MessagingController.getInstance(getApplication()).checkMail(this, account, true, true, mAdapter.mListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,11 +10,9 @@ import android.content.Intent;
|
|||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.text.SpannableString;
|
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.style.ForegroundColorSpan;
|
|
||||||
import android.text.style.StyleSpan;
|
|
||||||
import android.text.style.TextAppearanceSpan;
|
import android.text.style.TextAppearanceSpan;
|
||||||
import android.util.Config;
|
import android.util.Config;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -974,6 +972,13 @@ public class MessageList
|
|||||||
|
|
||||||
private void checkMail(Account account, String folderName)
|
private void checkMail(Account account, String folderName)
|
||||||
{
|
{
|
||||||
|
if (mAccount.isStoreAttachmentOnSdCard()
|
||||||
|
&& !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
Toast.makeText(this, R.string.sd_card_error, Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mController.synchronizeMailbox(account, folderName, mAdapter.mListener);
|
mController.synchronizeMailbox(account, folderName, mAdapter.mListener);
|
||||||
sendMail(account);
|
sendMail(account);
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,12 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.preference.*;
|
import android.preference.*;
|
||||||
|
import android.preference.Preference.OnPreferenceChangeListener;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
import android.widget.Toast;
|
||||||
import com.fsck.k9.*;
|
import com.fsck.k9.*;
|
||||||
import com.fsck.k9.activity.ChooseFolder;
|
import com.fsck.k9.activity.ChooseFolder;
|
||||||
import com.fsck.k9.activity.ChooseIdentity;
|
import com.fsck.k9.activity.ChooseIdentity;
|
||||||
@ -45,6 +48,7 @@ public class AccountSettings extends K9PreferenceActivity
|
|||||||
private static final String PREFERENCE_DELETE_POLICY = "delete_policy";
|
private static final String PREFERENCE_DELETE_POLICY = "delete_policy";
|
||||||
private static final String PREFERENCE_EXPUNGE_POLICY = "expunge_policy";
|
private static final String PREFERENCE_EXPUNGE_POLICY = "expunge_policy";
|
||||||
private static final String PREFERENCE_AUTO_EXPAND_FOLDER = "account_setup_auto_expand_folder";
|
private static final String PREFERENCE_AUTO_EXPAND_FOLDER = "account_setup_auto_expand_folder";
|
||||||
|
private static final String PREFERENCE_STORE_ATTACHMENTS_ON_SD_CARD = "account_setup_store_attachment_on_sd_card";
|
||||||
|
|
||||||
|
|
||||||
private Account mAccount;
|
private Account mAccount;
|
||||||
@ -67,6 +71,7 @@ public class AccountSettings extends K9PreferenceActivity
|
|||||||
private ListPreference mDeletePolicy;
|
private ListPreference mDeletePolicy;
|
||||||
private ListPreference mExpungePolicy;
|
private ListPreference mExpungePolicy;
|
||||||
private Preference mAutoExpandFolder;
|
private Preference mAutoExpandFolder;
|
||||||
|
private CheckBoxPreference mStoreAttachmentsOnSdCard;
|
||||||
|
|
||||||
|
|
||||||
public static void actionSettings(Context context, Account account)
|
public static void actionSettings(Context context, Account account)
|
||||||
@ -349,6 +354,28 @@ public class AccountSettings extends K9PreferenceActivity
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mStoreAttachmentsOnSdCard = (CheckBoxPreference) findPreference(PREFERENCE_STORE_ATTACHMENTS_ON_SD_CARD);
|
||||||
|
mStoreAttachmentsOnSdCard.setChecked(mAccount.isStoreAttachmentOnSdCard());
|
||||||
|
mStoreAttachmentsOnSdCard.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
if (newValue instanceof Boolean)
|
||||||
|
{
|
||||||
|
Boolean b = (Boolean)newValue;
|
||||||
|
if (b.booleanValue()
|
||||||
|
&& !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
Toast.makeText(
|
||||||
|
AccountSettings.this,
|
||||||
|
R.string.account_setup_store_attachment_on_sd_card_error,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -378,6 +405,7 @@ public class AccountSettings extends K9PreferenceActivity
|
|||||||
mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue()));
|
mAccount.setFolderTargetMode(Account.FolderMode.valueOf(mTargetMode.getValue()));
|
||||||
mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue()));
|
mAccount.setDeletePolicy(Integer.parseInt(mDeletePolicy.getValue()));
|
||||||
mAccount.setExpungePolicy(mExpungePolicy.getValue());
|
mAccount.setExpungePolicy(mExpungePolicy.getValue());
|
||||||
|
mAccount.setStoreAttachmentOnSdCard(mStoreAttachmentsOnSdCard.isChecked());
|
||||||
|
|
||||||
SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences();
|
SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences();
|
||||||
String newRingtone = prefs.getString(PREFERENCE_RINGTONE, null);
|
String newRingtone = prefs.getString(PREFERENCE_RINGTONE, null);
|
||||||
|
@ -8,8 +8,10 @@ import android.database.Cursor;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Environment;
|
||||||
import android.text.util.Regex;
|
import android.text.util.Regex;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
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.Utility;
|
import com.fsck.k9.Utility;
|
||||||
@ -36,9 +38,11 @@ public class LocalStore extends Store implements Serializable
|
|||||||
private static final int DB_VERSION = 33;
|
private static final int DB_VERSION = 33;
|
||||||
private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
|
private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
|
||||||
|
|
||||||
|
private Account mAccount;
|
||||||
private String mPath;
|
private String mPath;
|
||||||
private SQLiteDatabase mDb;
|
private SQLiteDatabase mDb;
|
||||||
private File mAttachmentsDir;
|
private File mInternalAttachmentsDir = null;
|
||||||
|
private File mExternalAttachmentsDir = null;
|
||||||
private Application mApplication;
|
private Application mApplication;
|
||||||
private String uUid = null;
|
private String uUid = null;
|
||||||
|
|
||||||
@ -65,6 +69,24 @@ public class LocalStore extends Store implements Serializable
|
|||||||
public LocalStore(String _uri, Application application) throws MessagingException
|
public LocalStore(String _uri, Application application) throws MessagingException
|
||||||
{
|
{
|
||||||
mApplication = application;
|
mApplication = application;
|
||||||
|
|
||||||
|
//Store should be passed their store
|
||||||
|
//but let's not break the interface now
|
||||||
|
for (Account account : Preferences.getPreferences(mApplication).getAccounts())
|
||||||
|
{
|
||||||
|
if (_uri.equals(account.getLocalStoreUri()))
|
||||||
|
{
|
||||||
|
mAccount = account;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mAccount == null)
|
||||||
|
{
|
||||||
|
//Should not happend
|
||||||
|
throw new IllegalArgumentException("No account found: uri=" + _uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
URI uri = null;
|
URI uri = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -94,10 +116,20 @@ public class LocalStore extends Store implements Serializable
|
|||||||
parentDir.mkdirs();
|
parentDir.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
mAttachmentsDir = new File(mPath + "_att");
|
mInternalAttachmentsDir = new File(mPath + "_att");
|
||||||
if (!mAttachmentsDir.exists())
|
if (!mInternalAttachmentsDir.exists())
|
||||||
{
|
{
|
||||||
mAttachmentsDir.mkdirs();
|
mInternalAttachmentsDir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useExternalAttachmentDir())
|
||||||
|
{
|
||||||
|
String externalAttachmentsPath = "/sdcard" + mPath.substring("//data".length());
|
||||||
|
mExternalAttachmentsDir = new File(externalAttachmentsPath + "_att");
|
||||||
|
if (!mExternalAttachmentsDir.exists())
|
||||||
|
{
|
||||||
|
mExternalAttachmentsDir.mkdirs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mDb = SQLiteDatabase.openOrCreateDatabase(mPath, null);
|
mDb = SQLiteDatabase.openOrCreateDatabase(mPath, null);
|
||||||
@ -235,7 +267,21 @@ public class LocalStore extends Store implements Serializable
|
|||||||
{
|
{
|
||||||
long attachmentLength = 0;
|
long attachmentLength = 0;
|
||||||
|
|
||||||
File[] files = mAttachmentsDir.listFiles();
|
attachmentLength =+ getSize(mInternalAttachmentsDir);
|
||||||
|
if (useExternalAttachmentDir())
|
||||||
|
{
|
||||||
|
attachmentLength =+ getSize(mExternalAttachmentsDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
File dbFile = new File(mPath);
|
||||||
|
return dbFile.length() + attachmentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getSize(File attachmentsDir)
|
||||||
|
{
|
||||||
|
long attachmentLength = 0;
|
||||||
|
|
||||||
|
File[] files = attachmentsDir.listFiles();
|
||||||
for (File file : files)
|
for (File file : files)
|
||||||
{
|
{
|
||||||
if (file.exists())
|
if (file.exists())
|
||||||
@ -244,9 +290,7 @@ public class LocalStore extends Store implements Serializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return attachmentLength;
|
||||||
File dbFile = new File(mPath);
|
|
||||||
return dbFile.length() + attachmentLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void compact() throws MessagingException
|
public void compact() throws MessagingException
|
||||||
@ -375,24 +419,13 @@ public class LocalStore extends Store implements Serializable
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
try
|
|
||||||
{
|
delete(mInternalAttachmentsDir);
|
||||||
File[] attachments = mAttachmentsDir.listFiles();
|
if (useExternalAttachmentDir())
|
||||||
for (File attachment : attachments)
|
|
||||||
{
|
|
||||||
if (attachment.exists())
|
|
||||||
{
|
|
||||||
attachment.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mAttachmentsDir.exists())
|
|
||||||
{
|
|
||||||
mAttachmentsDir.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
{
|
||||||
|
delete(mExternalAttachmentsDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
new File(mPath).delete();
|
new File(mPath).delete();
|
||||||
@ -403,24 +436,53 @@ public class LocalStore extends Store implements Serializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void delete(File attachmentsDir) {
|
||||||
|
try {
|
||||||
|
File[] attachments = attachmentsDir.listFiles();
|
||||||
|
for (File attachment : attachments)
|
||||||
|
{
|
||||||
|
if (attachment.exists())
|
||||||
|
{
|
||||||
|
attachment.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attachmentsDir.exists())
|
||||||
|
{
|
||||||
|
attachmentsDir.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.w(K9.LOG_TAG, null, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void pruneCachedAttachments() throws MessagingException
|
public void pruneCachedAttachments() throws MessagingException
|
||||||
{
|
{
|
||||||
pruneCachedAttachments(false);
|
pruneCachedAttachments(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes all cached attachments for the entire store.
|
|
||||||
*/
|
|
||||||
public void pruneCachedAttachments(boolean force) throws MessagingException
|
public void pruneCachedAttachments(boolean force) throws MessagingException
|
||||||
{
|
{
|
||||||
|
|
||||||
if (force)
|
if (force)
|
||||||
{
|
{
|
||||||
ContentValues cv = new ContentValues();
|
ContentValues cv = new ContentValues();
|
||||||
cv.putNull("content_uri");
|
cv.putNull("content_uri");
|
||||||
mDb.update("attachments", cv, null, null);
|
mDb.update("attachments", cv, null, null);
|
||||||
}
|
}
|
||||||
File[] files = mAttachmentsDir.listFiles();
|
pruneCachedAttachments(force, mInternalAttachmentsDir);
|
||||||
|
if (useExternalAttachmentDir())
|
||||||
|
{
|
||||||
|
pruneCachedAttachments(force, mExternalAttachmentsDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all cached attachments for the entire store.
|
||||||
|
*/
|
||||||
|
private void pruneCachedAttachments(boolean force, File attachmentsDir) throws MessagingException
|
||||||
|
{
|
||||||
|
File[] files = attachmentsDir.listFiles();
|
||||||
for (File file : files)
|
for (File file : files)
|
||||||
{
|
{
|
||||||
if (file.exists())
|
if (file.exists())
|
||||||
@ -1719,7 +1781,7 @@ public class LocalStore extends Store implements Serializable
|
|||||||
* so we copy the data into a cached attachment file.
|
* so we copy the data into a cached attachment file.
|
||||||
*/
|
*/
|
||||||
InputStream in = attachment.getBody().getInputStream();
|
InputStream in = attachment.getBody().getInputStream();
|
||||||
tempAttachmentFile = File.createTempFile("att", null, mAttachmentsDir);
|
tempAttachmentFile = File.createTempFile("att", null, getAttachmentsDir());
|
||||||
FileOutputStream out = new FileOutputStream(tempAttachmentFile);
|
FileOutputStream out = new FileOutputStream(tempAttachmentFile);
|
||||||
size = IOUtils.copy(in, out);
|
size = IOUtils.copy(in, out);
|
||||||
in.close();
|
in.close();
|
||||||
@ -1784,7 +1846,7 @@ public class LocalStore extends Store implements Serializable
|
|||||||
|
|
||||||
if (tempAttachmentFile != null)
|
if (tempAttachmentFile != null)
|
||||||
{
|
{
|
||||||
File attachmentFile = new File(mAttachmentsDir, Long.toString(attachmentId));
|
File attachmentFile = new File(getAttachmentsDir(), Long.toString(attachmentId));
|
||||||
tempAttachmentFile.renameTo(attachmentFile);
|
tempAttachmentFile.renameTo(attachmentFile);
|
||||||
contentUri = AttachmentProvider.getAttachmentUri(
|
contentUri = AttachmentProvider.getAttachmentUri(
|
||||||
new File(mPath).getName(),
|
new File(mPath).getName(),
|
||||||
@ -1942,11 +2004,20 @@ public class LocalStore extends Store implements Serializable
|
|||||||
long attachmentId = attachmentsCursor.getLong(0);
|
long attachmentId = attachmentsCursor.getLong(0);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File file = new File(mAttachmentsDir, Long.toString(attachmentId));
|
File file;
|
||||||
|
|
||||||
|
file = new File(mInternalAttachmentsDir, Long.toString(attachmentId));
|
||||||
if (file.exists())
|
if (file.exists())
|
||||||
{
|
{
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file = new File(mExternalAttachmentsDir, Long.toString(attachmentId));
|
||||||
|
if (file.exists())
|
||||||
|
{
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -2509,14 +2580,6 @@ public class LocalStore extends Store implements Serializable
|
|||||||
{
|
{
|
||||||
return mApplication.getContentResolver().openInputStream(mUri);
|
return mApplication.getContentResolver().openInputStream(mUri);
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException fnfe)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Since it's completely normal for us to try to serve up attachments that
|
|
||||||
* have been blown away, we just return an empty stream.
|
|
||||||
*/
|
|
||||||
return new ByteArrayInputStream(new byte[0]);
|
|
||||||
}
|
|
||||||
catch (IOException ioe)
|
catch (IOException ioe)
|
||||||
{
|
{
|
||||||
throw new MessagingException("Invalid attachment.", ioe);
|
throw new MessagingException("Invalid attachment.", ioe);
|
||||||
@ -2536,4 +2599,34 @@ public class LocalStore extends Store implements Serializable
|
|||||||
return mUri;
|
return mUri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private File getAttachmentsDir()
|
||||||
|
{
|
||||||
|
if (useExternalAttachmentDir())
|
||||||
|
{
|
||||||
|
return mExternalAttachmentsDir;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return mInternalAttachmentsDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean useExternalAttachmentDir()
|
||||||
|
{
|
||||||
|
if (mAccount.isStoreAttachmentOnSdCard()) {
|
||||||
|
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("SDCard not mounted");
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.fsck.k9.Account;
|
import com.fsck.k9.Account;
|
||||||
@ -156,6 +157,29 @@ public class AttachmentProvider extends ContentProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private File getFile(String dbName, String id)
|
||||||
|
throws FileNotFoundException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File attachmentsDir = getContext().getDatabasePath(dbName + "_att");
|
||||||
|
File file = new File(attachmentsDir, id);
|
||||||
|
if (!file.exists())
|
||||||
|
{
|
||||||
|
file = new File("/sdcard" + attachmentsDir.getCanonicalPath().substring("/data".length()), id);
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new FileNotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
Log.w(K9.LOG_TAG, null, e);
|
||||||
|
throw new FileNotFoundException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException
|
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException
|
||||||
{
|
{
|
||||||
@ -176,10 +200,9 @@ public class AttachmentProvider extends ContentProvider
|
|||||||
String type = getType(attachmentUri);
|
String type = getType(attachmentUri);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FileInputStream in = new FileInputStream(
|
FileInputStream in = new FileInputStream(getFile(dbName, id));
|
||||||
new File(getContext().getDatabasePath(dbName + "_att"), id));
|
|
||||||
Bitmap thumbnail = createThumbnail(type, in);
|
Bitmap thumbnail = createThumbnail(type, in);
|
||||||
thumbnail = thumbnail.createScaledBitmap(thumbnail, width, height, true);
|
thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true);
|
||||||
FileOutputStream out = new FileOutputStream(file);
|
FileOutputStream out = new FileOutputStream(file);
|
||||||
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out);
|
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||||
out.close();
|
out.close();
|
||||||
@ -195,7 +218,7 @@ public class AttachmentProvider extends ContentProvider
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
return ParcelFileDescriptor.open(
|
return ParcelFileDescriptor.open(
|
||||||
new File(getContext().getDatabasePath(dbName + "_att"), id),
|
getFile(dbName, id),
|
||||||
ParcelFileDescriptor.MODE_READ_ONLY);
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user