1/*
2 * Copyright (C) 2013 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mail.browse;
19
20import android.content.Context;
21import android.database.Cursor;
22import android.net.Uri;
23
24import com.android.emailcommon.internet.MimeMessage;
25import com.android.emailcommon.mail.MessagingException;
26import com.android.mail.browse.MessageCursor.ConversationController;
27import com.android.mail.content.CursorCreator;
28import com.android.mail.providers.Account;
29import com.android.mail.providers.Attachment;
30import com.android.mail.providers.Conversation;
31import com.android.mail.providers.Message;
32import com.android.mail.ui.ConversationUpdater;
33import com.google.common.base.Objects;
34
35/**
36 * A message created as part of a conversation view. Sometimes, like during star/unstar, it's
37 * handy to have the owning {@link com.android.mail.providers.Conversation} for context.
38 *
39 * <p>This class must remain separate from the {@link MessageCursor} from whence it came,
40 * because cursors can be closed by their Loaders at any time. The
41 * {@link ConversationController} intermediate is used to obtain the currently opened cursor.
42 *
43 * <p>(N.B. This is a {@link android.os.Parcelable}, so try not to add non-transient fields here.
44 * Parcelable state belongs either in {@link com.android.mail.providers.Message} or
45 * {@link com.android.mail.ui.ConversationViewState.MessageViewState}. The
46 * assumption is that this class never needs the state of its extra context saved.)
47 */
48public final class ConversationMessage extends Message {
49
50    private transient ConversationController mController;
51
52    private ConversationMessage(Cursor cursor) {
53        super(cursor);
54    }
55
56    public ConversationMessage(Context context, MimeMessage mimeMessage, Uri emlFileUri)
57            throws MessagingException {
58        super(context, mimeMessage, emlFileUri);
59    }
60
61    public void setController(ConversationController controller) {
62        mController = controller;
63    }
64
65    public Conversation getConversation() {
66        return mController != null ? mController.getConversation() : null;
67    }
68
69    public Account getAccount() {
70        return mController != null ? mController.getAccount() : null;
71    }
72
73    /**
74     * Returns a hash code based on this message's identity, contents and current state.
75     * This is a separate method from hashCode() to allow for an instance of this class to be
76     * a functional key in a hash-based data structure.
77     *
78     */
79    public int getStateHashCode() {
80        return Objects.hashCode(uri, read, starred, getAttachmentsStateHashCode());
81    }
82
83    private int getAttachmentsStateHashCode() {
84        int hash = 0;
85        for (Attachment a : getAttachments()) {
86            final Uri uri = a.getIdentifierUri();
87            hash += (uri != null ? uri.hashCode() : 0);
88        }
89        return hash;
90    }
91
92    public boolean isConversationStarred() {
93        final MessageCursor c = mController.getMessageCursor();
94        return c != null && c.isConversationStarred();
95    }
96
97    public void star(boolean newStarred) {
98        final ConversationUpdater listController = mController.getListController();
99        if (listController != null) {
100            listController.starMessage(this, newStarred);
101        }
102    }
103
104    /**
105     * Public object that knows how to construct Messages given Cursors.
106     */
107    public static final CursorCreator<ConversationMessage> FACTORY =
108            new CursorCreator<ConversationMessage>() {
109                @Override
110                public ConversationMessage createFromCursor(Cursor c) {
111                    return new ConversationMessage(c);
112                }
113
114                @Override
115                public String toString() {
116                    return "ConversationMessage CursorCreator";
117                }
118            };
119
120}
121