Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c8a6f05 authored by Vincent Breitmoser's avatar Vincent Breitmoser
Browse files

make Attachment class immutable

parent 099d03f4
Loading
Loading
Loading
Loading
+2 −5
Original line number Diff line number Diff line
@@ -131,11 +131,8 @@ public class AttachmentPresenter {
    }

    public void addAttachment(Uri uri, String contentType) {
        Attachment attachment = new Attachment();
        attachment.uri = uri;
        attachment.state = Attachment.LoadingState.URI_ONLY;
        attachment.contentType = contentType;
        attachment.loaderId = getNextFreeLoaderId();
        int loaderId = getNextFreeLoaderId();
        Attachment attachment = Attachment.createAttachment(uri, loaderId, contentType);

        if (attachments.containsKey(uri)) {
            return;
+19 −15
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.activity.misc.Attachment;

import com.fsck.k9.activity.misc.Attachment.LoadingState;
import de.cketti.safecontentresolver.SafeContentResolver;
import de.cketti.safecontentresolver.SafeContentResolverCompat;
import org.apache.commons.io.IOUtils;
@@ -24,20 +25,27 @@ import org.apache.commons.io.IOUtils;
public class AttachmentContentLoader extends AsyncTaskLoader<Attachment> {
    private static final String FILENAME_PREFIX = "attachment";

    private final Attachment mAttachment;

    private final Attachment sourceAttachment;
    private Attachment cachedResultAttachment;


    public AttachmentContentLoader(Context context, Attachment attachment) {
        super(context);
        mAttachment = attachment;
        if (attachment.state != LoadingState.METADATA) {
            throw new IllegalArgumentException("Attachment provided to content loader must be in METADATA state");
        }

        sourceAttachment = attachment;
    }

    @Override
    protected void onStartLoading() {
        if (mAttachment.state == Attachment.LoadingState.COMPLETE) {
            deliverResult(mAttachment);
        if (cachedResultAttachment != null) {
            deliverResult(sourceAttachment);
        }

        if (takeContentChanged() || mAttachment.state == Attachment.LoadingState.METADATA) {
        if (takeContentChanged() || cachedResultAttachment == null) {
            forceLoad();
        }
    }
@@ -55,7 +63,7 @@ public class AttachmentContentLoader extends AsyncTaskLoader<Attachment> {
            }

            SafeContentResolver safeContentResolver = SafeContentResolverCompat.newInstance(context);
            InputStream in = safeContentResolver.openInputStream(mAttachment.uri);
            InputStream in = safeContentResolver.openInputStream(sourceAttachment.uri);
            try {
                FileOutputStream out = new FileOutputStream(file);
                try {
@@ -67,17 +75,13 @@ public class AttachmentContentLoader extends AsyncTaskLoader<Attachment> {
                in.close();
            }

            mAttachment.filename = file.getAbsolutePath();
            mAttachment.state = Attachment.LoadingState.COMPLETE;

            return mAttachment;
            cachedResultAttachment = sourceAttachment.deriveWithLoadComplete(file.getAbsolutePath());
            return cachedResultAttachment;
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(K9.LOG_TAG, "Error saving attachment!", e);
        }

        mAttachment.filename = null;
        mAttachment.state = Attachment.LoadingState.CANCELLED;

        return mAttachment;
        cachedResultAttachment = sourceAttachment.deriveWithLoadCancelled();
        return cachedResultAttachment;
    }
}
+16 −13
Original line number Diff line number Diff line
@@ -12,34 +12,41 @@ import android.util.Log;

import com.fsck.k9.K9;
import com.fsck.k9.activity.misc.Attachment;
import com.fsck.k9.activity.misc.Attachment.LoadingState;
import com.fsck.k9.mail.internet.MimeUtility;

/**
 * Loader to fetch metadata of an attachment.
 */
public class AttachmentInfoLoader  extends AsyncTaskLoader<Attachment> {
    private final Attachment mAttachment;
    private final Attachment sourceAttachment;
    private Attachment cachedResultAttachment;


    public AttachmentInfoLoader(Context context, Attachment attachment) {
        super(context);
        mAttachment = attachment;
        if (attachment.state != LoadingState.URI_ONLY) {
            throw new IllegalArgumentException("Attachment provided to metadata loader must be in URI_ONLY state");
        }

        sourceAttachment = attachment;
    }

    @Override
    protected void onStartLoading() {
        if (mAttachment.state == Attachment.LoadingState.METADATA) {
            deliverResult(mAttachment);
        if (cachedResultAttachment != null) {
            deliverResult(cachedResultAttachment);
        }

        if (takeContentChanged() || mAttachment.state == Attachment.LoadingState.URI_ONLY) {
        if (takeContentChanged() || cachedResultAttachment == null) {
            forceLoad();
        }
    }

    @Override
    public Attachment loadInBackground() {
        Uri uri = mAttachment.uri;
        String contentType = mAttachment.contentType;
        Uri uri = sourceAttachment.uri;
        String contentType = sourceAttachment.contentType;

        long size = -1;
        String name = null;
@@ -91,11 +98,7 @@ public class AttachmentInfoLoader extends AsyncTaskLoader<Attachment> {
        }
        Log.v(K9.LOG_TAG, "new attachment.size: " + size);

        mAttachment.contentType = usableContentType;
        mAttachment.name = name;
        mAttachment.size = size;
        mAttachment.state = Attachment.LoadingState.METADATA;

        return mAttachment;
        cachedResultAttachment = sourceAttachment.deriveWithMetadataLoaded(usableContentType, name, size);
        return cachedResultAttachment;
    }
}
+67 −45
Original line number Diff line number Diff line
@@ -15,76 +15,103 @@ public class Attachment implements Parcelable {
     *
     * In most cases this will be a {@code content://}-URI.
     */
    public Uri uri;
    public final Uri uri;

    /**
     * The current loading state.
     */
    public LoadingState state;
    public final LoadingState state;

    /**
     * The ID of the loader that is used to load the metadata or contents.
     */
    public int loaderId;
    public final int loaderId;

    /**
     * The content type of the attachment.
     *
     * Only valid when {@link #state} is {@link LoadingState#METADATA} or
     * {@link LoadingState#COMPLETE}.
     * Valid iff {@link #state} is {@link LoadingState#METADATA} or {@link LoadingState#COMPLETE}.
     */
    public String contentType;
    public final String contentType;

    /**
     * The (file)name of the attachment.
     *
     * Only valid when {@link #state} is {@link LoadingState#METADATA} or
     * {@link LoadingState#COMPLETE}.
     * Valid iff {@link #state} is {@link LoadingState#METADATA} or {@link LoadingState#COMPLETE}.
     */
    public String name;
    public final String name;

    /**
     * The size of the attachment.
     *
     * Only valid when {@link #state} is {@link LoadingState#METADATA} or
     * {@link LoadingState#COMPLETE}.
     * Valid iff {@link #state} is {@link LoadingState#METADATA} or {@link LoadingState#COMPLETE}.
     */
    public long size;
    public final Long size;

    /**
     * The name of the temporary file containing the local copy of the attachment.
     *
     * Only valid when {@link #state} is {@link LoadingState#COMPLETE}.
     * Valid iff {@link #state} is {@link LoadingState#COMPLETE}.
     */
    public String filename;


    public Attachment() {}
    public final String filename;

    public enum LoadingState {
        /**
         * The only thing we know about this attachment is {@link #uri}.
         */
        URI_ONLY,

        /**
         * The metadata of this attachment have been loaded.
         *
         * {@link #contentType}, {@link #name}, and {@link #size} should contain usable values.
         */
        METADATA,

        /**
         * The contents of the attachments have been copied to the temporary file {@link #filename}.
         */
        COMPLETE,

        /**
         * Something went wrong while trying to fetch the attachment's contents.
         */
        CANCELLED
    }

    private Attachment(Uri uri, LoadingState state, int loaderId, String contentType, String name, Long size,
            String filename) {
        this.uri = uri;
        this.state = state;
        this.loaderId = loaderId;
        this.contentType = contentType;
        this.name = name;
        this.size = size;
        this.filename = filename;
    }

    private Attachment(Parcel in) {
        uri = in.readParcelable(Uri.class.getClassLoader());
        state = (LoadingState) in.readSerializable();
        loaderId = in.readInt();
        contentType = in.readString();
        name = in.readString();
        if (in.readInt() != 0) {
            size = in.readLong();
        } else {
            size = null;
        }
        filename = in.readString();
    }

    public static Attachment createAttachment(Uri uri, int loaderId, String contentType) {
        return new Attachment(uri, Attachment.LoadingState.URI_ONLY, loaderId, contentType, null, null, null);
    }

    public Attachment deriveWithMetadataLoaded(String usableContentType, String name, long size) {
        if (state != Attachment.LoadingState.URI_ONLY) {
            throw new IllegalStateException("deriveWithMetadataLoaded can only be called on a URI_ONLY attachment!");
        }
        return new Attachment(uri, Attachment.LoadingState.METADATA, loaderId, usableContentType, name, size, null);
    }

    public Attachment deriveWithLoadCancelled() {
        if (state != Attachment.LoadingState.METADATA) {
            throw new IllegalStateException("deriveWitLoadCancelled can only be called on a METADATA attachment!");
        }
        return new Attachment(uri, Attachment.LoadingState.CANCELLED, loaderId, contentType, name, size, null);
    }

    public Attachment deriveWithLoadComplete(String absolutePath) {
        if (state != Attachment.LoadingState.METADATA) {
            throw new IllegalStateException("deriveWithLoadComplete can only be called on a METADATA attachment!");
        }
        return new Attachment(uri, Attachment.LoadingState.COMPLETE, loaderId, contentType, name, size, absolutePath);
    }

    // === Parcelable ===

    @Override
@@ -99,7 +126,12 @@ public class Attachment implements Parcelable {
        dest.writeInt(loaderId);
        dest.writeString(contentType);
        dest.writeString(name);
        if (size != null) {
            dest.writeInt(1);
            dest.writeLong(size);
        } else {
            dest.writeInt(0);
        }
        dest.writeString(filename);
    }

@@ -115,14 +147,4 @@ public class Attachment implements Parcelable {
            return new Attachment[size];
        }
    };

    public Attachment(Parcel in) {
        uri = in.readParcelable(Uri.class.getClassLoader());
        state = (LoadingState) in.readSerializable();
        loaderId = in.readInt();
        contentType = in.readString();
        name = in.readString();
        size = in.readLong();
        filename = in.readString();
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -376,7 +376,7 @@ public class PgpMessageBuilderTest {
                .setEnablePgpInline(true)
                .build();
        pgpMessageBuilder.setCryptoStatus(cryptoStatus);
        pgpMessageBuilder.setAttachments(Collections.singletonList(new Attachment()));
        pgpMessageBuilder.setAttachments(Collections.singletonList(Attachment.createAttachment(null, 0, null)));

        Callback mockCallback = mock(Callback.class);
        pgpMessageBuilder.buildAsync(mockCallback);
@@ -393,7 +393,7 @@ public class PgpMessageBuilderTest {
                .setEnablePgpInline(true)
                .build();
        pgpMessageBuilder.setCryptoStatus(cryptoStatus);
        pgpMessageBuilder.setAttachments(Collections.singletonList(new Attachment()));
        pgpMessageBuilder.setAttachments(Collections.singletonList(Attachment.createAttachment(null, 0, null)));

        Callback mockCallback = mock(Callback.class);
        pgpMessageBuilder.buildAsync(mockCallback);