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