15ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee/*
25ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Copyright (C) 2009 The Android Open Source Project
35ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee *
45ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Licensed under the Apache License, Version 2.0 (the "License");
55ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * you may not use this file except in compliance with the License.
65ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * You may obtain a copy of the License at
75ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee *
85ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee *      http://www.apache.org/licenses/LICENSE-2.0
95ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee *
105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Unless required by applicable law or agreed to in writing, software
115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * distributed under the License is distributed on an "AS IS" BASIS,
125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * See the License for the specific language governing permissions and
145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * limitations under the License.
155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */
165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leepackage com.android.contacts.common.util;
185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.content.Context;
205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.content.pm.PackageManager;
215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.database.Cursor;
225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.graphics.drawable.Drawable;
235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.Data;
245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.text.TextUtils;
255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.text.format.DateUtils;
265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.R;
285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee/**
305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Storage for a social status update. Holds a single update, but can use
315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link #possibleUpdate(Cursor)} to consider updating when a better status
325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * exists. Statuses with timestamps, or with newer timestamps win.
335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */
345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leepublic class DataStatus {
355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private int mPresence = -1;
365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private String mStatus = null;
375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private long mTimestamp = -1;
385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private String mResPackage = null;
405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private int mIconRes = -1;
415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private int mLabelRes = -1;
425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public DataStatus() {
445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public DataStatus(Cursor cursor) {
475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        // When creating from cursor row, fill normally
485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        fromCursor(cursor);
495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    /**
525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee     * Attempt updating this {@link DataStatus} based on values at the
535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee     * current row of the given {@link Cursor}.
545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee     */
555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public void possibleUpdate(Cursor cursor) {
565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final boolean hasStatus = !isNull(cursor, Data.STATUS);
575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final boolean hasTimestamp = !isNull(cursor, Data.STATUS_TIMESTAMP);
585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        // Bail early when not valid status, or when previous status was
605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        // found and we can't compare this one.
615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        if (!hasStatus) return;
625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        if (isValid() && !hasTimestamp) return;
635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        if (hasTimestamp) {
655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee            // Compare timestamps and bail if older status
665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee            final long newTimestamp = getLong(cursor, Data.STATUS_TIMESTAMP, -1);
675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee            if (newTimestamp < mTimestamp) return;
685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee            mTimestamp = newTimestamp;
705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        }
715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        // Fill in remaining details from cursor
735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        fromCursor(cursor);
745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private void fromCursor(Cursor cursor) {
775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        mPresence = getInt(cursor, Data.PRESENCE, -1);
785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        mStatus = getString(cursor, Data.STATUS);
795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        mTimestamp = getLong(cursor, Data.STATUS_TIMESTAMP, -1);
805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        mResPackage = getString(cursor, Data.STATUS_RES_PACKAGE);
815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        mIconRes = getInt(cursor, Data.STATUS_ICON, -1);
825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        mLabelRes = getInt(cursor, Data.STATUS_LABEL, -1);
835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public boolean isValid() {
865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return !TextUtils.isEmpty(mStatus);
875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public int getPresence() {
905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return mPresence;
915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public CharSequence getStatus() {
945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return mStatus;
955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public long getTimestamp() {
985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return mTimestamp;
995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
1005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    /**
1025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee     * Build any timestamp and label into a single string.
1035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee     */
1045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public CharSequence getTimestampLabel(Context context) {
1055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final PackageManager pm = context.getPackageManager();
1065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        // Use local package for resources when none requested
1085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        if (mResPackage == null) mResPackage = context.getPackageName();
1095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final boolean validTimestamp = mTimestamp > 0;
1115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final boolean validLabel = mResPackage != null && mLabelRes != -1;
1125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final CharSequence timeClause = validTimestamp ? DateUtils.getRelativeTimeSpanString(
1145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee                mTimestamp, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,
1155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee                DateUtils.FORMAT_ABBREV_RELATIVE) : null;
1165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final CharSequence labelClause = validLabel ? pm.getText(mResPackage, mLabelRes,
1175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee                null) : null;
1185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        if (validTimestamp && validLabel) {
1205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee            return context.getString(
1215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee                    R.string.contact_status_update_attribution_with_date,
1225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee                    timeClause, labelClause);
1235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        } else if (validLabel) {
1245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee            return context.getString(
1255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee                    R.string.contact_status_update_attribution,
1265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee                    labelClause);
1275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        } else if (validTimestamp) {
1285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee            return timeClause;
1295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        } else {
1305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee            return null;
1315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        }
1325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
1335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    public Drawable getIcon(Context context) {
1355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final PackageManager pm = context.getPackageManager();
1365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        // Use local package for resources when none requested
1385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        if (mResPackage == null) mResPackage = context.getPackageName();
1395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final boolean validIcon = mResPackage != null && mIconRes != -1;
1415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return validIcon ? pm.getDrawable(mResPackage, mIconRes, null) : null;
1425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
1435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private static String getString(Cursor cursor, String columnName) {
1455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return cursor.getString(cursor.getColumnIndex(columnName));
1465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
1475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private static int getInt(Cursor cursor, String columnName) {
1495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return cursor.getInt(cursor.getColumnIndex(columnName));
1505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
1515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private static int getInt(Cursor cursor, String columnName, int missingValue) {
1535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final int columnIndex = cursor.getColumnIndex(columnName);
1545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return cursor.isNull(columnIndex) ? missingValue : cursor.getInt(columnIndex);
1555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
1565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private static long getLong(Cursor cursor, String columnName, long missingValue) {
1585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        final int columnIndex = cursor.getColumnIndex(columnName);
1595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return cursor.isNull(columnIndex) ? missingValue : cursor.getLong(columnIndex);
1605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
1615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee
1625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    private static boolean isNull(Cursor cursor, String columnName) {
1635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee        return cursor.isNull(cursor.getColumnIndex(columnName));
1645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee    }
1655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee}
166