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 
DataStatus()43     public DataStatus() {
44     }
45 
DataStatus(Cursor cursor)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      */
possibleUpdate(Cursor cursor)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 
fromCursor(Cursor cursor)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 
isValid()85     public boolean isValid() {
86         return !TextUtils.isEmpty(mStatus);
87     }
88 
getPresence()89     public int getPresence() {
90         return mPresence;
91     }
92 
getStatus()93     public CharSequence getStatus() {
94         return mStatus;
95     }
96 
getTimestamp()97     public long getTimestamp() {
98         return mTimestamp;
99     }
100 
101     /**
102      * Build any timestamp and label into a single string.
103      */
getTimestampLabel(Context context)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 
getIcon(Context context)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 
getString(Cursor cursor, String columnName)144     private static String getString(Cursor cursor, String columnName) {
145         return cursor.getString(cursor.getColumnIndex(columnName));
146     }
147 
getInt(Cursor cursor, String columnName)148     private static int getInt(Cursor cursor, String columnName) {
149         return cursor.getInt(cursor.getColumnIndex(columnName));
150     }
151 
getInt(Cursor cursor, String columnName, int missingValue)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 
getLong(Cursor cursor, String columnName, long missingValue)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 
isNull(Cursor cursor, String columnName)162     private static boolean isNull(Cursor cursor, String columnName) {
163         return cursor.isNull(cursor.getColumnIndex(columnName));
164     }
165 }
166