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 18 package com.android.mail.browse; 19 20 import android.content.Context; 21 import android.database.Cursor; 22 import android.net.Uri; 23 24 import com.android.emailcommon.internet.MimeMessage; 25 import com.android.emailcommon.mail.MessagingException; 26 import com.android.mail.browse.MessageCursor.ConversationController; 27 import com.android.mail.content.CursorCreator; 28 import com.android.mail.providers.Account; 29 import com.android.mail.providers.Attachment; 30 import com.android.mail.providers.Conversation; 31 import com.android.mail.providers.Message; 32 import com.android.mail.ui.ConversationUpdater; 33 import 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 */ 48 public final class ConversationMessage extends Message { 49 50 private transient ConversationController mController; 51 ConversationMessage(Cursor cursor)52 private ConversationMessage(Cursor cursor) { 53 super(cursor); 54 } 55 ConversationMessage(Context context, MimeMessage mimeMessage, Uri emlFileUri)56 public ConversationMessage(Context context, MimeMessage mimeMessage, Uri emlFileUri) 57 throws MessagingException { 58 super(context, mimeMessage, emlFileUri); 59 } 60 setController(ConversationController controller)61 public void setController(ConversationController controller) { 62 mController = controller; 63 } 64 getConversation()65 public Conversation getConversation() { 66 return mController != null ? mController.getConversation() : null; 67 } 68 getAccount()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 */ getStateHashCode()79 public int getStateHashCode() { 80 return Objects.hashCode(uri, getAttachmentsStateHashCode()); 81 } 82 getAttachmentsStateHashCode()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 isConversationStarred()92 public boolean isConversationStarred() { 93 final MessageCursor c = mController.getMessageCursor(); 94 return c != null && c.isConversationStarred(); 95 } 96 97 /** 98 * Sets the starred state of this Message object and also updates the cached instance in 99 * {@link MessageCursor} (if not null) 100 * 101 * @param starred new starred state 102 */ setStarredInConversation(boolean starred)103 public void setStarredInConversation(boolean starred) { 104 this.starred = starred; 105 final MessageCursor c = mController.getMessageCursor(); 106 if (c != null) { 107 final ConversationMessage other = c.getMessageForId(id); 108 other.starred = starred; 109 } 110 } 111 star(boolean newStarred)112 public void star(boolean newStarred) { 113 final ConversationUpdater listController = mController.getListController(); 114 if (listController != null) { 115 listController.starMessage(this, newStarred); 116 } 117 } 118 119 /** 120 * Public object that knows how to construct Messages given Cursors. 121 */ 122 public static final CursorCreator<ConversationMessage> FACTORY = 123 new CursorCreator<ConversationMessage>() { 124 @Override 125 public ConversationMessage createFromCursor(Cursor c) { 126 return new ConversationMessage(c); 127 } 128 129 @Override 130 public String toString() { 131 return "ConversationMessage CursorCreator"; 132 } 133 }; 134 135 } 136