18812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein/* 28812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * Copyright (C) 2013 Google Inc. 38812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * Licensed to The Android Open Source Project. 48812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * 58812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License"); 68812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * you may not use this file except in compliance with the License. 78812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * You may obtain a copy of the License at 88812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * 98812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * http://www.apache.org/licenses/LICENSE-2.0 108812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * 118812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * Unless required by applicable law or agreed to in writing, software 128812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS, 138812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 148812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * See the License for the specific language governing permissions and 158812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * limitations under the License. 168812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein */ 178812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 188812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinpackage com.android.mail.browse; 198812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 207434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.Context; 218812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport android.database.Cursor; 228812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport android.net.Uri; 238812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 248812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.emailcommon.internet.MimeMessage; 258812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.emailcommon.mail.MessagingException; 268812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.mail.browse.MessageCursor.ConversationController; 278812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.mail.content.CursorCreator; 284f347e811052f446c3958c76db278bcd7b39a44fAndy Huangimport com.android.mail.providers.Account; 298812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.mail.providers.Attachment; 308812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.mail.providers.Conversation; 318812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.mail.providers.Message; 328812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.android.mail.ui.ConversationUpdater; 338812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinimport com.google.common.base.Objects; 348812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 358812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein/** 368812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * A message created as part of a conversation view. Sometimes, like during star/unstar, it's 378812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * handy to have the owning {@link com.android.mail.providers.Conversation} for context. 388812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * 398812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * <p>This class must remain separate from the {@link MessageCursor} from whence it came, 408812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * because cursors can be closed by their Loaders at any time. The 418812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * {@link ConversationController} intermediate is used to obtain the currently opened cursor. 428812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * 438812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * <p>(N.B. This is a {@link android.os.Parcelable}, so try not to add non-transient fields here. 448812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * Parcelable state belongs either in {@link com.android.mail.providers.Message} or 458812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * {@link com.android.mail.ui.ConversationViewState.MessageViewState}. The 468812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * assumption is that this class never needs the state of its extra context saved.) 478812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein */ 488812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sappersteinpublic final class ConversationMessage extends Message { 498812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 508812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein private transient ConversationController mController; 518812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 528812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein private ConversationMessage(Cursor cursor) { 538812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein super(cursor); 548812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 558812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 567434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein public ConversationMessage(Context context, MimeMessage mimeMessage, Uri emlFileUri) 577434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein throws MessagingException { 587434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein super(context, mimeMessage, emlFileUri); 598812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 608812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 618812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein public void setController(ConversationController controller) { 628812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein mController = controller; 638812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 648812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 658812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein public Conversation getConversation() { 664ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein return mController != null ? mController.getConversation() : null; 678812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 688812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 694f347e811052f446c3958c76db278bcd7b39a44fAndy Huang public Account getAccount() { 704f347e811052f446c3958c76db278bcd7b39a44fAndy Huang return mController != null ? mController.getAccount() : null; 714f347e811052f446c3958c76db278bcd7b39a44fAndy Huang } 724f347e811052f446c3958c76db278bcd7b39a44fAndy Huang 738812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein /** 748812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * Returns a hash code based on this message's identity, contents and current state. 758812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * This is a separate method from hashCode() to allow for an instance of this class to be 768812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * a functional key in a hash-based data structure. 778812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * 788812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein */ 798812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein public int getStateHashCode() { 808812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein return Objects.hashCode(uri, read, starred, getAttachmentsStateHashCode()); 818812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 828812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 838812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein private int getAttachmentsStateHashCode() { 848812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein int hash = 0; 858812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein for (Attachment a : getAttachments()) { 868812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein final Uri uri = a.getIdentifierUri(); 878812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein hash += (uri != null ? uri.hashCode() : 0); 888812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 898812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein return hash; 908812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 918812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 928812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein public boolean isConversationStarred() { 938812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein final MessageCursor c = mController.getMessageCursor(); 948812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein return c != null && c.isConversationStarred(); 958812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 968812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 978812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein public void star(boolean newStarred) { 988812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein final ConversationUpdater listController = mController.getListController(); 998812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein if (listController != null) { 1008812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein listController.starMessage(this, newStarred); 1018812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 1028812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 1038812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 1048812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein /** 1058812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein * Public object that knows how to construct Messages given Cursors. 1068812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein */ 1078812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein public static final CursorCreator<ConversationMessage> FACTORY = 1088812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein new CursorCreator<ConversationMessage>() { 1098812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein @Override 1108812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein public ConversationMessage createFromCursor(Cursor c) { 1118812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein return new ConversationMessage(c); 1128812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 1138812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 1148812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein @Override 1158812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein public String toString() { 1168812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein return "ConversationMessage CursorCreator"; 1178812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein } 1188812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein }; 1198812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein 1208812d3c50e35c4f2a02d29c35c76082c4ebec0cdAndrew Sapperstein} 121