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
17package com.android.contacts.util;
18
19import android.content.Context;
20import android.content.pm.PackageManager;
21import android.database.Cursor;
22import android.graphics.drawable.Drawable;
23import android.provider.ContactsContract.Data;
24import android.text.TextUtils;
25import android.text.format.DateUtils;
26
27import com.android.contacts.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 */
34public 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