1 /* 2 * Copyright (C) 2009 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.common.util; 18 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.database.Cursor; 22 import android.graphics.drawable.Drawable; 23 import android.provider.ContactsContract.Data; 24 import android.text.TextUtils; 25 import android.text.format.DateUtils; 26 27 import com.android.contacts.common.R; 28 29 /** 30 * Storage for a social status update. Holds a single update, but can use 31 * {@link #possibleUpdate(Cursor)} to consider updating when a better status 32 * exists. Statuses with timestamps, or with newer timestamps win. 33 */ 34 public class DataStatus { 35 private int mPresence = -1; 36 private String mStatus = null; 37 private long mTimestamp = -1; 38 39 private String mResPackage = null; 40 private int mIconRes = -1; 41 private int mLabelRes = -1; 42 43 public DataStatus() { 44 } 45 46 public DataStatus(Cursor cursor) { 47 // When creating from cursor row, fill normally 48 fromCursor(cursor); 49 } 50 51 /** 52 * Attempt updating this {@link DataStatus} based on values at the 53 * current row of the given {@link Cursor}. 54 */ 55 public void possibleUpdate(Cursor cursor) { 56 final boolean hasStatus = !isNull(cursor, Data.STATUS); 57 final boolean hasTimestamp = !isNull(cursor, Data.STATUS_TIMESTAMP); 58 59 // Bail early when not valid status, or when previous status was 60 // found and we can't compare this one. 61 if (!hasStatus) return; 62 if (isValid() && !hasTimestamp) return; 63 64 if (hasTimestamp) { 65 // Compare timestamps and bail if older status 66 final long newTimestamp = getLong(cursor, Data.STATUS_TIMESTAMP, -1); 67 if (newTimestamp < mTimestamp) return; 68 69 mTimestamp = newTimestamp; 70 } 71 72 // Fill in remaining details from cursor 73 fromCursor(cursor); 74 } 75 76 private void fromCursor(Cursor cursor) { 77 mPresence = getInt(cursor, Data.PRESENCE, -1); 78 mStatus = getString(cursor, Data.STATUS); 79 mTimestamp = getLong(cursor, Data.STATUS_TIMESTAMP, -1); 80 mResPackage = getString(cursor, Data.STATUS_RES_PACKAGE); 81 mIconRes = getInt(cursor, Data.STATUS_ICON, -1); 82 mLabelRes = getInt(cursor, Data.STATUS_LABEL, -1); 83 } 84 85 public boolean isValid() { 86 return !TextUtils.isEmpty(mStatus); 87 } 88 89 public int getPresence() { 90 return mPresence; 91 } 92 93 public CharSequence getStatus() { 94 return mStatus; 95 } 96 97 public long getTimestamp() { 98 return mTimestamp; 99 } 100 101 /** 102 * Build any timestamp and label into a single string. 103 */ 104 public CharSequence getTimestampLabel(Context context) { 105 final PackageManager pm = context.getPackageManager(); 106 107 // Use local package for resources when none requested 108 if (mResPackage == null) mResPackage = context.getPackageName(); 109 110 final boolean validTimestamp = mTimestamp > 0; 111 final boolean validLabel = mResPackage != null && mLabelRes != -1; 112 113 final CharSequence timeClause = validTimestamp ? DateUtils.getRelativeTimeSpanString( 114 mTimestamp, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, 115 DateUtils.FORMAT_ABBREV_RELATIVE) : null; 116 final CharSequence labelClause = validLabel ? pm.getText(mResPackage, mLabelRes, 117 null) : null; 118 119 if (validTimestamp && validLabel) { 120 return context.getString( 121 R.string.contact_status_update_attribution_with_date, 122 timeClause, labelClause); 123 } else if (validLabel) { 124 return context.getString( 125 R.string.contact_status_update_attribution, 126 labelClause); 127 } else if (validTimestamp) { 128 return timeClause; 129 } else { 130 return null; 131 } 132 } 133 134 public Drawable getIcon(Context context) { 135 final PackageManager pm = context.getPackageManager(); 136 137 // Use local package for resources when none requested 138 if (mResPackage == null) mResPackage = context.getPackageName(); 139 140 final boolean validIcon = mResPackage != null && mIconRes != -1; 141 return validIcon ? pm.getDrawable(mResPackage, mIconRes, null) : null; 142 } 143 144 private static String getString(Cursor cursor, String columnName) { 145 return cursor.getString(cursor.getColumnIndex(columnName)); 146 } 147 148 private static int getInt(Cursor cursor, String columnName) { 149 return cursor.getInt(cursor.getColumnIndex(columnName)); 150 } 151 152 private static int getInt(Cursor cursor, String columnName, int missingValue) { 153 final int columnIndex = cursor.getColumnIndex(columnName); 154 return cursor.isNull(columnIndex) ? missingValue : cursor.getInt(columnIndex); 155 } 156 157 private static long getLong(Cursor cursor, String columnName, long missingValue) { 158 final int columnIndex = cursor.getColumnIndex(columnName); 159 return cursor.isNull(columnIndex) ? missingValue : cursor.getLong(columnIndex); 160 } 161 162 private static boolean isNull(Cursor cursor, String columnName) { 163 return cursor.isNull(cursor.getColumnIndex(columnName)); 164 } 165 } 166