1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.contacts.util; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.provider.ContactsContract.StreamItems; 22 import android.text.Html; 23 24 import com.android.contacts.detail.ContactDetailDisplayUtils; 25 import com.android.contacts.common.test.NeededForTesting; 26 27 import com.google.common.annotations.VisibleForTesting; 28 29 import java.util.ArrayList; 30 import java.util.Collections; 31 import java.util.List; 32 33 /** 34 * Data object for a social stream item. Social stream items may contain multiple 35 * mPhotos. Social stream item entries are comparable; entries with more recent 36 * timestamps will be displayed on top. 37 */ 38 public class StreamItemEntry implements Comparable<StreamItemEntry> { 39 40 // Basic stream item fields. 41 private final long mId; 42 private final String mText; 43 private final String mComments; 44 private final long mTimestamp; 45 private final String mAccountType; 46 private final String mAccountName; 47 private final String mDataSet; 48 49 private boolean mDecoded; 50 private CharSequence mDecodedText; 51 private CharSequence mDecodedComments; 52 53 // Package references for label and icon resources. 54 private final String mResPackage; 55 private final String mIconRes; 56 private final String mLabelRes; 57 58 // Photos associated with this stream item. 59 private List<StreamItemPhotoEntry> mPhotos; 60 61 @NeededForTesting 62 public static StreamItemEntry createForTest(long id, String text, String comments, 63 long timestamp, String accountType, String accountName, String dataSet, 64 String resPackage, String iconRes, String labelRes) { 65 return new StreamItemEntry(id, text, comments, timestamp, accountType, accountName, dataSet, 66 resPackage, iconRes, labelRes); 67 } 68 69 private StreamItemEntry(long id, String text, String comments, long timestamp, 70 String accountType, String accountName, String dataSet, String resPackage, 71 String iconRes, String labelRes) { 72 mId = id; 73 mText = text; 74 mComments = comments; 75 mTimestamp = timestamp; 76 mAccountType = accountType; 77 mAccountName = accountName; 78 mDataSet = dataSet; 79 mResPackage = resPackage; 80 mIconRes = iconRes; 81 mLabelRes = labelRes; 82 mPhotos = new ArrayList<StreamItemPhotoEntry>(); 83 } 84 85 public StreamItemEntry(Cursor cursor) { 86 // This is expected to be populated via a cursor containing all StreamItems columns in 87 // its projection. 88 mId = getLong(cursor, StreamItems._ID); 89 mText = getString(cursor, StreamItems.TEXT); 90 mComments = getString(cursor, StreamItems.COMMENTS); 91 mTimestamp = getLong(cursor, StreamItems.TIMESTAMP); 92 mAccountType = getString(cursor, StreamItems.ACCOUNT_TYPE); 93 mAccountName = getString(cursor, StreamItems.ACCOUNT_NAME); 94 mDataSet = getString(cursor, StreamItems.DATA_SET); 95 mResPackage = getString(cursor, StreamItems.RES_PACKAGE); 96 mIconRes = getString(cursor, StreamItems.RES_ICON); 97 mLabelRes = getString(cursor, StreamItems.RES_LABEL); 98 mPhotos = new ArrayList<StreamItemPhotoEntry>(); 99 } 100 101 public void addPhoto(StreamItemPhotoEntry photoEntry) { 102 mPhotos.add(photoEntry); 103 } 104 105 @Override 106 public int compareTo(StreamItemEntry other) { 107 return mTimestamp == other.mTimestamp ? 0 : mTimestamp > other.mTimestamp ? -1 : 1; 108 } 109 110 public long getId() { 111 return mId; 112 } 113 114 public String getText() { 115 return mText; 116 } 117 118 public String getComments() { 119 return mComments; 120 } 121 122 public long getTimestamp() { 123 return mTimestamp; 124 } 125 126 public String getAccountType() { 127 return mAccountType; 128 } 129 130 public String getAccountName() { 131 return mAccountName; 132 } 133 134 public String getDataSet() { 135 return mDataSet; 136 } 137 138 public String getResPackage() { 139 return mResPackage; 140 } 141 142 public String getIconRes() { 143 return mIconRes; 144 } 145 146 public String getLabelRes() { 147 return mLabelRes; 148 } 149 150 public List<StreamItemPhotoEntry> getPhotos() { 151 Collections.sort(mPhotos); 152 return mPhotos; 153 } 154 155 /** 156 * Make {@link #getDecodedText} and {@link #getDecodedComments} available. Must be called 157 * before calling those. 158 * 159 * We can't do this automatically in the getters, because it'll require a {@link Context}. 160 */ 161 @VisibleForTesting 162 public void decodeHtml(Context context) { 163 final Html.ImageGetter imageGetter = ContactDetailDisplayUtils.getImageGetter(context); 164 if (mText != null) { 165 mDecodedText = HtmlUtils.fromHtml(context, mText, imageGetter, null); 166 } 167 if (mComments != null) { 168 mDecodedComments = HtmlUtils.fromHtml(context, mComments, imageGetter, null); 169 } 170 mDecoded = true; 171 } 172 173 public CharSequence getDecodedText() { 174 checkDecoded(); 175 return mDecodedText; 176 } 177 178 public CharSequence getDecodedComments() { 179 checkDecoded(); 180 return mDecodedComments; 181 } 182 183 private void checkDecoded() { 184 if (!mDecoded) { 185 throw new IllegalStateException("decodeHtml must have been called"); 186 } 187 } 188 189 private static String getString(Cursor cursor, String columnName) { 190 return cursor.getString(cursor.getColumnIndex(columnName)); 191 } 192 193 private static long getLong(Cursor cursor, String columnName) { 194 final int columnIndex = cursor.getColumnIndex(columnName); 195 return cursor.getLong(columnIndex); 196 } 197 } 198