/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package info.guardianproject.otr.app.im.provider; import info.guardianproject.otr.app.im.app.ImApp; import java.util.HashMap; import java.util.UUID; import android.content.ContentQueryMap; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.net.Uri.Builder; import android.os.Handler; import android.provider.BaseColumns; import android.util.Log; /** * The IM provider stores all information about roster contacts, chat messages, * presence, etc. * * @hide */ public class Imps { /** no public constructor since this is a utility class */ private Imps() { } /** The Columns for IM providers (i.e. AIM, Y!, GTalk) */ public interface ProviderColumns { /** The name of the IM provider <P>Type: TEXT</P> */ String NAME = "name"; /** The full name of the provider <P>Type: TEXT</P> */ String FULLNAME = "fullname"; /** * The category for the provider, used to form intent. <P>Type: TEXT</P> */ String CATEGORY = "category"; /** * The url users should visit to create a new account for this provider * <P>Type: TEXT</P> */ String SIGNUP_URL = "signup_url"; } /** Known names corresponding to the {@link ProviderColumns#NAME} column */ public interface ProviderNames { // //NOTE: update Contacts.java with new providers when they're added. // String YAHOO = "Yahoo"; String GTALK = "GTalk"; String MSN = "MSN"; String ICQ = "ICQ"; String AIM = "AIM"; String XMPP = "XMPP"; String JABBER = "JABBER"; String SKYPE = "SKYPE"; String QQ = "QQ"; } /** This table contains the IM providers */ public static final class Provider implements BaseColumns, ProviderColumns { private Provider() { } public static final long getProviderIdForName(ContentResolver cr, String providerName) { String select = NAME + "=?"; String[] selectionArgs = {providerName}; Cursor cursor = cr.query(CONTENT_URI, PROVIDER_PROJECTION, select, selectionArgs, null); long retVal = 0; try { if (cursor.moveToFirst()) { retVal = cursor.getLong(cursor.getColumnIndexOrThrow(_ID)); } } finally { if (cursor != null) cursor.close(); } return retVal; } public static final String getProviderNameForId(ContentResolver cr, long providerId) { Cursor cursor = cr.query(CONTENT_URI, PROVIDER_PROJECTION, _ID + "=" + providerId, null, null); String retVal = null; try { if (cursor.moveToFirst()) { retVal = cursor.getString(cursor.getColumnIndexOrThrow(NAME)); } } finally { cursor.close(); } return retVal; } private static final String[] PROVIDER_PROJECTION = new String[] { _ID, NAME }; public static final String ACTIVE_ACCOUNT_ID = "account_id"; public static final String ACTIVE_ACCOUNT_USERNAME = "account_username"; public static final String ACTIVE_ACCOUNT_PW = "account_pw"; public static final String ACTIVE_ACCOUNT_LOCKED = "account_locked"; public static final String ACTIVE_ACCOUNT_KEEP_SIGNED_IN = "account_keepSignedIn"; public static final String ACCOUNT_PRESENCE_STATUS = "account_presenceStatus"; public static final String ACCOUNT_CONNECTION_STATUS = "account_connStatus"; /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/providers"); public static final Uri CONTENT_URI_WITH_ACCOUNT = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/providers/account"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * people. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-providers"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-providers"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "providers._ID ASC"; } /** * The columns for IM accounts. There can be more than one account for each * IM provider. */ public interface AccountColumns { /** The name of the account <P>Type: TEXT</P> */ String NAME = "name"; /** The IM provider for this account <P>Type: INTEGER</P> */ String PROVIDER = "provider"; /** The username for this account <P>Type: TEXT</P> */ String USERNAME = "username"; /** The password for this account <P>Type: TEXT</P> */ String PASSWORD = "pw"; /** * A boolean value indicates if the account is active. <P>Type: * INTEGER</P> */ String ACTIVE = "active"; /** * A boolean value indicates if the account is locked (not editable) * <P>Type: INTEGER</P> */ String LOCKED = "locked"; /** * A boolean value to indicate whether this account is kept signed in. * <P>Type: INTEGER</P> */ String KEEP_SIGNED_IN = "keep_signed_in"; /** * A boolean value indiciating the last login state for this account * <P>Type: INTEGER</P> */ String LAST_LOGIN_STATE = "last_login_state"; } /** This table contains the IM accounts. */ public static final class Account implements BaseColumns, AccountColumns { private Account() { } public static final long getProviderIdForAccount(ContentResolver cr, long accountId) { Cursor cursor = cr.query(CONTENT_URI, PROVIDER_PROJECTION, _ID + "=" + accountId, null /* selection args */, null /* sort order */); long providerId = 0; try { if (cursor.moveToFirst()) { providerId = cursor.getLong(PROVIDER_COLUMN); } } finally { cursor.close(); } return providerId; } public static final String getUserName(ContentResolver cr, long accountId) { Cursor cursor = cr.query(CONTENT_URI, new String[] { USERNAME }, _ID + "=" + accountId, null /* selection args */, null /* sort order */); String ret = null; try { if (cursor.moveToFirst()) { ret = cursor.getString(cursor.getColumnIndexOrThrow(USERNAME)); } } finally { cursor.close(); } return ret; } public static final String getPassword(ContentResolver cr, long accountId) { Cursor cursor = cr.query(CONTENT_URI, new String[] { PASSWORD }, _ID + "=" + accountId, null /* selection args */, null /* sort order */); String ret = null; try { if (cursor.moveToFirst()) { ret = cursor.getString(cursor.getColumnIndexOrThrow(PASSWORD)); } } finally { cursor.close(); } return ret; } private static final String[] PROVIDER_PROJECTION = new String[] { PROVIDER }; private static final int PROVIDER_COLUMN = 0; /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/accounts"); /** The content:// style URL for looking up by domain */ public static final Uri BY_DOMAIN_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/domainAccounts"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * account. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-accounts"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * account. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-accounts"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "name ASC"; } /** Connection status */ public interface ConnectionStatus { /** The connection is offline, not logged in. */ int OFFLINE = 0; /** The connection is attempting to connect. */ int CONNECTING = 1; /** The connection is suspended due to network not available. */ int SUSPENDED = 2; /** The connection is logged in and online. */ int ONLINE = 3; } public interface AccountStatusColumns { /** account id <P>Type: INTEGER</P> */ String ACCOUNT = "account"; /** * User's presence status, see definitions in {#link * CommonPresenceColumn} <P>Type: INTEGER</P> */ String PRESENCE_STATUS = "presenceStatus"; /** * The connection status of this account, see {#link ConnectionStatus} * <P>Type: INTEGER</P> */ String CONNECTION_STATUS = "connStatus"; } public static final class AccountStatus implements BaseColumns, AccountStatusColumns { /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/accountStatus"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * account status. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-account-status"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * account status. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-account-status"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "name ASC"; } /** Columns from the Contacts table. */ public interface ContactsColumns { /** The username <P>Type: TEXT</P> */ String USERNAME = "username"; /** The nickname or display name <P>Type: TEXT</P> */ String NICKNAME = "nickname"; /** The IM provider for this contact <P>Type: INTEGER</P> */ String PROVIDER = "provider"; /** * The account (within a IM provider) for this contact <P>Type: * INTEGER</P> */ String ACCOUNT = "account"; /** The contactList this contact belongs to <P>Type: INTEGER</P> */ String CONTACTLIST = "contactList"; /** Contact type <P>Type: INTEGER</P> */ String TYPE = "type"; /** normal IM contact */ int TYPE_NORMAL = 0; /** * temporary contact, someone not in the list of contacts that we * subscribe presence for. Usually created because of the user is having * a chat session with this contact. */ int TYPE_TEMPORARY = 1; /** temporary contact created for group chat. */ int TYPE_GROUP = 2; /** blocked contact. */ int TYPE_BLOCKED = 3; /** * the contact is hidden. The client should always display this contact * to the user. */ int TYPE_HIDDEN = 4; /** * the contact is pinned. The client should always display this contact * to the user. */ int TYPE_PINNED = 5; /** Contact subscription status <P>Type: INTEGER</P> */ String SUBSCRIPTION_STATUS = "subscriptionStatus"; /** no pending subscription */ int SUBSCRIPTION_STATUS_NONE = 0; /** requested to subscribe */ int SUBSCRIPTION_STATUS_SUBSCRIBE_PENDING = 1; /** requested to unsubscribe */ int SUBSCRIPTION_STATUS_UNSUBSCRIBE_PENDING = 2; /** Contact subscription type <P>Type: INTEGER </P> */ String SUBSCRIPTION_TYPE = "subscriptionType"; /** The user and contact have no interest in each other's presence. */ int SUBSCRIPTION_TYPE_NONE = 0; /** The user wishes to stop receiving presence updates from the contact. */ int SUBSCRIPTION_TYPE_REMOVE = 1; /** * The user is interested in receiving presence updates from the * contact. */ int SUBSCRIPTION_TYPE_TO = 2; /** * The contact is interested in receiving presence updates from the * user. */ int SUBSCRIPTION_TYPE_FROM = 3; /** * The user and contact have a mutual interest in each other's presence. */ int SUBSCRIPTION_TYPE_BOTH = 4; /** This is a special type reserved for pending subscription requests */ int SUBSCRIPTION_TYPE_INVITATIONS = 5; /** * Quick Contact: derived from Google Contact Extension's * "message_count" attribute. <P>Type: INTEGER</P> */ String QUICK_CONTACT = "qc"; /** * Google Contact Extension attribute * * Rejected: a boolean value indicating whether a subscription request * from this client was ever rejected by the user. "true" indicates that * it has. This is provided so that a client can block repeated * subscription requests. <P>Type: INTEGER</P> */ String REJECTED = "rejected"; /** * Off The Record status: 0 for disabled, 1 for enabled <P>Type: INTEGER * </P> */ String OTR = "otr"; } /** This defines the different type of values of {@link ContactsColumns#OTR} */ public interface OffTheRecordType { /* * Off the record not turned on */ int DISABLED = 0; /** Off the record turned on, but we don't know who turned it on */ int ENABLED = 1; /** Off the record turned on by the user */ int ENABLED_BY_USER = 2; /** Off the record turned on by the buddy */ int ENABLED_BY_BUDDY = 3; }; /** This table contains contacts. */ public static final class Contacts implements BaseColumns, ContactsColumns, PresenceColumns, ChatsColumns { /** no public constructor since this is a utility class */ private Contacts() { } /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contacts"); /** The content:// style URL for contacts joined with presence */ public static final Uri CONTENT_URI_WITH_PRESENCE = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contactsWithPresence"); /** * The content:// style URL for barebone contacts, not joined with any * other table */ public static final Uri CONTENT_URI_CONTACTS_BAREBONE = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contactsBarebone"); /** The content:// style URL for contacts who have an open chat session */ public static final Uri CONTENT_URI_CHAT_CONTACTS = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contacts/chatting"); /** The content:// style URL for contacts who have been blocked */ public static final Uri CONTENT_URI_BLOCKED_CONTACTS = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contacts/blocked"); /** The content:// style URL for contacts by provider and account */ public static final Uri CONTENT_URI_CONTACTS_BY = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contacts"); /** * The content:// style URL for contacts by provider and account, and * who have an open chat session */ public static final Uri CONTENT_URI_CHAT_CONTACTS_BY = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contacts/chatting"); /** * The content:// style URL for contacts by provider and account, and * who are online */ public static final Uri CONTENT_URI_ONLINE_CONTACTS_BY = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contacts/online"); /** * The content:// style URL for contacts by provider and account, and * who are offline */ public static final Uri CONTENT_URI_OFFLINE_CONTACTS_BY = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contacts/offline"); /** The content:// style URL for operations on bulk contacts */ public static final Uri BULK_CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/bulk_contacts"); /** * The content:// style URL for the count of online contacts in each * contact list by provider and account. */ public static final Uri CONTENT_URI_ONLINE_COUNT = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contacts/onlineCount"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * people. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-contacts"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * person. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-contacts"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "subscriptionType DESC, last_message_date DESC," + " mode DESC, nickname COLLATE NOCASE ASC"; /** The default sort order for this table */ public static final String ALPHA_SORT_ORDER = "nickname COLLATE NOCASE ASC"; /** The default sort order for this table */ public static final String MODE_AND_ALPHA_SORT_ORDER = "mode DESC, nickname COLLATE NOCASE ASC"; public static final String CHATS_CONTACT = "chats_contact"; public static final String AVATAR_HASH = "avatars_hash"; public static final String AVATAR_DATA = "avatars_data"; } /** Columns from the ContactList table. */ public interface ContactListColumns { String NAME = "name"; String PROVIDER = "provider"; String ACCOUNT = "account"; } /** This table contains the contact lists. */ public static final class ContactList implements BaseColumns, ContactListColumns { private ContactList() { } /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contactLists"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * people. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-contactLists"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * person. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-contactLists"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "name COLLATE UNICODE ASC"; public static final String PROVIDER_NAME = "provider_name"; public static final String ACCOUNT_NAME = "account_name"; } /** Columns from the BlockedList table. */ public interface BlockedListColumns { /** The username of the blocked contact. <P>Type: TEXT</P> */ String USERNAME = "username"; /** The nickname of the blocked contact. <P>Type: TEXT</P> */ String NICKNAME = "nickname"; /** The provider id of the blocked contact. <P>Type: INT</P> */ String PROVIDER = "provider"; /** The account id of the blocked contact. <P>Type: INT</P> */ String ACCOUNT = "account"; } /** This table contains blocked lists */ public static final class BlockedList implements BaseColumns, BlockedListColumns { private BlockedList() { } /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/blockedList"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * people. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-blockedList"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * person. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-blockedList"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "nickname ASC"; public static final String PROVIDER_NAME = "provider_name"; public static final String ACCOUNT_NAME = "account_name"; public static final String AVATAR_DATA = "avatars_data"; } /** Columns from the contactsEtag table */ public interface ContactsEtagColumns { /** * The roster etag, computed by the server, stored on the client. There * is one etag per account roster. <P>Type: TEXT</P> */ String ETAG = "etag"; /** * The OTR etag, computed by the server, stored on the client. There is * one OTR etag per account roster. <P>Type: TEXT</P> */ String OTR_ETAG = "otr_etag"; /** The account id for the etag. <P> Type: INTEGER </P> */ String ACCOUNT = "account"; } public static final class ContactsEtag implements BaseColumns, ContactsEtagColumns { private ContactsEtag() { } public static final Cursor query(ContentResolver cr, String[] projection) { return cr.query(CONTENT_URI, projection, null, null, null); } public static final Cursor query(ContentResolver cr, String[] projection, String where, String orderBy) { return cr.query(CONTENT_URI, projection, where, null, orderBy == null ? null : orderBy); } public static final String getRosterEtag(ContentResolver resolver, long accountId) { String retVal = null; Cursor c = resolver.query(CONTENT_URI, CONTACT_ETAG_PROJECTION, ACCOUNT + "=" + accountId, null /* selection args */, null /* sort order */); try { if (c.moveToFirst()) { retVal = c.getString(COLUMN_ETAG); } } finally { c.close(); } return retVal; } public static final String getOtrEtag(ContentResolver resolver, long accountId) { String retVal = null; Cursor c = resolver.query(CONTENT_URI, CONTACT_OTR_ETAG_PROJECTION, ACCOUNT + "=" + accountId, null /* selection args */, null /* sort order */); try { if (c.moveToFirst()) { retVal = c.getString(COLUMN_OTR_ETAG); } } finally { c.close(); } return retVal; } private static final String[] CONTACT_ETAG_PROJECTION = new String[] { Imps.ContactsEtag.ETAG // 0 }; private static int COLUMN_ETAG = 0; private static final String[] CONTACT_OTR_ETAG_PROJECTION = new String[] { Imps.ContactsEtag.OTR_ETAG // 0 }; private static int COLUMN_OTR_ETAG = 0; /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/contactsEtag"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * people. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-contactsEtag"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * person. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-contactsEtag"; } /** Message type definition */ public interface MessageType { /* sent message */ int OUTGOING = 0; /* received message */ int INCOMING = 1; /* presence became available */ int PRESENCE_AVAILABLE = 2; /* presence became away */ int PRESENCE_AWAY = 3; /* presence became DND (busy) */ int PRESENCE_DND = 4; /* presence became unavailable */ int PRESENCE_UNAVAILABLE = 5; /* the message is converted to a group chat */ int CONVERT_TO_GROUPCHAT = 6; /* generic status */ int STATUS = 7; /* the message cannot be sent now, but will be sent later */ int POSTPONED = 8; /* off The Record status is turned off */ int OTR_IS_TURNED_OFF = 9; /* off the record status is turned on */ int OTR_IS_TURNED_ON = 10; /* off the record status turned on by user */ int OTR_TURNED_ON_BY_USER = 11; /* off the record status turned on by buddy */ int OTR_TURNED_ON_BY_BUDDY = 12; /* received message */ int INCOMING_ENCRYPTED = 13; /* received message */ int INCOMING_ENCRYPTED_VERIFIED = 14; /* received message */ int OUTGOING_ENCRYPTED = 15; /* received message */ int OUTGOING_ENCRYPTED_VERIFIED = 16; } /** The common columns for messages table */ public interface MessageColumns { /** * The thread_id column stores the contact id of the contact the message * belongs to. For groupchat messages, the thread_id stores the group * id, which is the contact id of the temporary group contact created * for the groupchat. So there should be no collision between groupchat * message thread id and regular message thread id. */ String THREAD_ID = "thread_id"; /** * The nickname. This is used for groupchat messages to indicate the * participant's nickname. For non groupchat messages, this field should * be left empty. */ String NICKNAME = "nickname"; /** The body <P>Type: TEXT</P> */ String BODY = "body"; /** The date this message is sent or received <P>Type: INTEGER</P> */ String DATE = "date"; /** Message Type, see {@link MessageType} <P>Type: INTEGER</P> */ String TYPE = "type"; /** Error Code: 0 means no error. <P>Type: INTEGER </P> */ String ERROR_CODE = "err_code"; /** Error Message <P>Type: TEXT</P> */ String ERROR_MESSAGE = "err_msg"; /** * Packet ID, auto assigned by the GTalkService for outgoing messages or * the GTalk server for incoming messages. The packet id field is * optional for messages, so it could be null. <P>Type: STRING</P> */ String PACKET_ID = "packet_id"; /** Is groupchat message or not <P>Type: INTEGER</P> */ String IS_GROUP_CHAT = "is_muc"; /** * A hint that the UI should show the sent time of this message <P>Type: * INTEGER</P> */ String DISPLAY_SENT_TIME = "show_ts"; /** Whether a delivery confirmation was received. <P>Type: INTEGER</P> */ String IS_DELIVERED = "is_delivered"; /** Mime type. If non-null, body is a URI. */ String MIME_TYPE = "mime_type"; } /** This table contains messages. */ public static final class Messages implements BaseColumns, MessageColumns { /** no public constructor since this is a utility class */ private Messages() { } /** * Gets the Uri to query messages by thread id. * * @param threadId the thread id of the message. * @return the Uri */ public static final Uri getContentUriByThreadId(long threadId) { Uri.Builder builder = CONTENT_URI_MESSAGES_BY_THREAD_ID.buildUpon(); ContentUris.appendId(builder, threadId); return builder.build(); } /** * @deprecated * * Gets the Uri to query messages by account and contact. * * @param accountId the account id of the contact. * @param username the user name of the contact. * @return the Uri */ public static final Uri getContentUriByContact(long accountId, String username) { Uri.Builder builder = CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT.buildUpon(); ContentUris.appendId(builder, accountId); builder.appendPath(username); return builder.build(); } /** * Gets the Uri to query messages by provider. * * @param providerId the service provider id. * @return the Uri */ public static final Uri getContentUriByProvider(long providerId) { Uri.Builder builder = CONTENT_URI_MESSAGES_BY_PROVIDER.buildUpon(); ContentUris.appendId(builder, providerId); return builder.build(); } /** * Gets the Uri to query off the record messages by account. * * @param accountId the account id. * @return the Uri */ public static final Uri getContentUriByAccount(long accountId) { Uri.Builder builder = CONTENT_URI_BY_ACCOUNT.buildUpon(); ContentUris.appendId(builder, accountId); return builder.build(); } /** * Gets the Uri to query off the record messages by thread id. * * @param threadId the thread id of the message. * @return the Uri */ public static final Uri getOtrMessagesContentUriByThreadId(long threadId) { Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID.buildUpon(); ContentUris.appendId(builder, threadId); return builder.build(); } /** * @deprecated * * Gets the Uri to query off the record messages by account * and contact. * * @param accountId the account id of the contact. * @param username the user name of the contact. * @return the Uri */ public static final Uri getOtrMessagesContentUriByContact(long accountId, String username) { Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT.buildUpon(); ContentUris.appendId(builder, accountId); builder.appendPath(username); return builder.build(); } /** * Gets the Uri to query off the record messages by provider. * * @param providerId the service provider id. * @return the Uri */ public static final Uri getOtrMessagesContentUriByProvider(long providerId) { Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_PROVIDER.buildUpon(); ContentUris.appendId(builder, providerId); return builder.build(); } /** * Gets the Uri to query off the record messages by account. * * @param accountId the account id. * @return the Uri */ public static final Uri getOtrMessagesContentUriByAccount(long accountId) { Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT.buildUpon(); ContentUris.appendId(builder, accountId); return builder.build(); } /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/messages"); /** The content:// style URL for messages by thread id */ public static final Uri CONTENT_URI_MESSAGES_BY_THREAD_ID = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/messagesByThreadId"); /** The content:// style URL for messages by thread id */ public static final Uri CONTENT_URI_MESSAGES_BY_PACKET_ID = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/messagesByPacketId"); /** The content:// style URL for messages by account and contact */ public static final Uri CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/messagesByAcctAndContact"); /** The content:// style URL for messages by provider */ public static final Uri CONTENT_URI_MESSAGES_BY_PROVIDER = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/messagesByProvider"); /** The content:// style URL for messages by account */ public static final Uri CONTENT_URI_BY_ACCOUNT = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/messagesByAccount"); /** The content:// style url for off the record messages */ public static final Uri OTR_MESSAGES_CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/otrMessages"); /** The content:// style url for off the record messages by thread id */ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/otrMessagesByThreadId"); /** * The content:// style url for off the record messages by account and * contact */ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/otrMessagesByAcctAndContact"); /** The content:// style URL for off the record messages by provider */ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_PROVIDER = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/otrMessagesByProvider"); /** The content:// style URL for off the record messages by account */ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/otrMessagesByAccount"); public static final Uri OTR_MESSAGES_CONTENT_URI_BY_PACKET_ID = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/otrMessagesByPacketId"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * people. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-messages"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * person. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-messages"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "date ASC"; /** * The "contact" column. This is not a real column in the messages * table, but a temoprary column created when querying for messages * (joined with the contacts table) */ public static final String CONTACT = "contact"; } /** Columns for the GroupMember table. */ public interface GroupMemberColumns { /** The id of the group this member belongs to. <p>Type: INTEGER</p> */ String GROUP = "groupId"; /** The full name of this member. <p>Type: TEXT</p> */ String USERNAME = "username"; /** The nick name of this member. <p>Type: TEXT</p> */ String NICKNAME = "nickname"; } public final static class GroupMembers implements GroupMemberColumns { private GroupMembers() { } public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/groupMembers"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of group * members. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-groupMembers"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * group member. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-groupMembers"; } /** Columns from the Invitation table. */ public interface InvitationColumns { /** The provider id. <p>Type: INTEGER</p> */ String PROVIDER = "providerId"; /** The account id. <p>Type: INTEGER</p> */ String ACCOUNT = "accountId"; /** The invitation id. <p>Type: TEXT</p> */ String INVITE_ID = "inviteId"; /** The name of the sender of the invitation. <p>Type: TEXT</p> */ String SENDER = "sender"; /** * The name of the group which the sender invite you to join. <p>Type: * TEXT</p> */ String GROUP_NAME = "groupName"; /** A note <p>Type: TEXT</p> */ String NOTE = "note"; /** The current status of the invitation. <p>Type: TEXT</p> */ String STATUS = "status"; int STATUS_PENDING = 0; int STATUS_ACCEPTED = 1; int STATUS_REJECTED = 2; } /** This table contains the invitations received from others. */ public final static class Invitation implements InvitationColumns, BaseColumns { private Invitation() { } /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/invitations"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * invitations. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-invitations"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * invitation. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-invitations"; } /** Columns from the Avatars table */ public interface AvatarsColumns { /** The contact this avatar belongs to <P>Type: TEXT</P> */ String CONTACT = "contact"; String PROVIDER = "provider_id"; String ACCOUNT = "account_id"; /** The hash of the image data <P>Type: TEXT</P> */ String HASH = "hash"; /** raw image data <P>Type: BLOB</P> */ String DATA = "data"; } /** This table contains avatars. */ public static final class Avatars implements BaseColumns, AvatarsColumns { /** no public constructor since this is a utility class */ private Avatars() { } /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/avatars"); /** * The content:// style URL for avatars by provider, account and contact */ public static final Uri CONTENT_URI_AVATARS_BY = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/avatarsBy"); /** The MIME type of {@link #CONTENT_URI} providing the avatars */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-avatars"; /** The MIME type of a {@link #CONTENT_URI} */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-avatars"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "contact ASC"; } /** * Common presence columns shared between the IM and contacts presence * tables */ public interface CommonPresenceColumns { /** The priority, an integer, used by XMPP presence <P>Type: INTEGER</P> */ String PRIORITY = "priority"; /** * The server defined status. <P>Type: INTEGER (one of the values * below)</P> */ String PRESENCE_STATUS = "mode"; /** Presence Status definition */ int OFFLINE = 0; int INVISIBLE = 1; int AWAY = 2; int IDLE = 3; int DO_NOT_DISTURB = 4; int AVAILABLE = 5; int NEW_ACCOUNT = -99; /** The user defined status line. <P>Type: TEXT</P> */ String PRESENCE_CUSTOM_STATUS = "status"; } /** Columns from the Presence table. */ public interface PresenceColumns extends CommonPresenceColumns { /** The contact id <P>Type: INTEGER</P> */ String CONTACT_ID = "contact_id"; /** * The contact's JID resource, only relevant for XMPP contact <P>Type: * TEXT</P> */ String JID_RESOURCE = "jid_resource"; /** The contact's client type */ String CLIENT_TYPE = "client_type"; /** client type definitions */ int CLIENT_TYPE_DEFAULT = 0; int CLIENT_TYPE_MOBILE = 1; int CLIENT_TYPE_ANDROID = 2; } /** Contains presence infomation for contacts. */ public static final class Presence implements BaseColumns, PresenceColumns { /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/presence"); /** The content URL for IM presences for an account */ public static final Uri CONTENT_URI_BY_ACCOUNT = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/presence/account"); /** The content:// style URL for operations on bulk contacts */ public static final Uri BULK_CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/bulk_presence"); /** * The content:// style URL for seeding presences for a given account * id. */ public static final Uri SEED_PRESENCE_BY_ACCOUNT_CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/seed_presence/account"); /** * The MIME type of a {@link #CONTENT_URI} providing a directory of * presence */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-presence"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "mode DESC"; } /** Columns from the Chats table. */ public interface ChatsColumns { /** * The contact ID this chat belongs to. The value is a long. <P>Type: * INT</P> */ String CONTACT_ID = "contact_id"; /** The GTalk JID resource. The value is a string. <P>Type: TEXT</P> */ String JID_RESOURCE = "jid_resource"; /** Whether this is a groupchat or not. <P>Type: INT</P> */ String GROUP_CHAT = "groupchat"; /** * The last unread message. This both indicates that there is an unread * message, and what the message is. <P>Type: TEXT</P> */ String LAST_UNREAD_MESSAGE = "last_unread_message"; /** The last message timestamp <P>Type: INT</P> */ String LAST_MESSAGE_DATE = "last_message_date"; /** * A message that is being composed. This indicates that there was a * message being composed when the chat screen was shutdown, and what * the message is. <P>Type: TEXT</P> */ String UNSENT_COMPOSED_MESSAGE = "unsent_composed_message"; /** * A value from 0-9 indicating which quick-switch chat screen slot this * chat is occupying. If none (for instance, this is the 12th active * chat) then the value is -1. <P>Type: INT</P> */ String SHORTCUT = "shortcut"; } /** Contains ongoing chat sessions. */ public static final class Chats implements BaseColumns, ChatsColumns { /** no public constructor since this is a utility class */ private Chats() { } /** The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/chats"); /** The content URL for all chats that belong to the account */ public static final Uri CONTENT_URI_BY_ACCOUNT = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/chats/account"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of chats. */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/imps-chats"; /** * The MIME type of a {@link #CONTENT_URI} subdirectory of a single * chat. */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/imps-chats"; /** The default sort order for this table */ public static final String DEFAULT_SORT_ORDER = "last_message_date ASC"; } /** Columns from session cookies table. Used for IMPS. */ public static interface SessionCookiesColumns { String NAME = "name"; String VALUE = "value"; String PROVIDER = "provider"; String ACCOUNT = "account"; } /** Contains IMPS session cookies. */ public static class SessionCookies implements SessionCookiesColumns, BaseColumns { private SessionCookies() { } /** The content:// style URI for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/sessionCookies"); /** The content:// style URL for session cookies by provider and account */ public static final Uri CONTENT_URI_SESSION_COOKIES_BY = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/sessionCookiesBy"); /** * The MIME type of {@link #CONTENT_URI} providing a directory of * people. */ public static final String CONTENT_TYPE = "vnd.android-dir/imps-sessionCookies"; } /** Columns from ProviderSettings table */ public static interface ProviderSettingsColumns { /** * The id in database of the related provider * * <P>Type: INT</P> */ String PROVIDER = "provider"; /** The name of the setting <P>Type: TEXT</P> */ String NAME = "name"; /** The value of the setting <P>Type: TEXT</P> */ String VALUE = "value"; } public static class ProviderSettings implements ProviderSettingsColumns { // Global settings are saved with this provider ID, for backward compatibility public static final long PROVIDER_ID_FOR_GLOBAL_SETTINGS = 1; private ProviderSettings() { } /** The content:// style URI for this table */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/providerSettings"); /** The MIME type of {@link #CONTENT_URI} providing provider settings */ public static final String CONTENT_TYPE = "vnd.android-dir/imps-providerSettings"; // ACCOUNT SETTINGS (username and password are part of Account above) // TODO since everything is here except username/password, perhaps it should also be moved here? /** the domain name of the account, i.e. @gmail.com for XMPP */ public static final String DOMAIN = "pref_account_domain"; /** The XMPP Resource string */ public static final String XMPP_RESOURCE = "pref_account_xmpp_resource"; /** The XMPP Resource priority string */ public static final String XMPP_RESOURCE_PRIO = "pref_account_xmpp_resource_prio"; /** the port number to connect to */ public static final String PORT = "pref_account_port"; /** The hostname or IP of the server to connect to */ public static final String SERVER = "pref_account_server"; // ENCRYPTION AND ANONYMITY SETTINGS /** allow plain text authentication */ public static final String ALLOW_PLAIN_AUTH = "pref_security_allow_plain_auth"; /** boolean for the required use of a TLS connection */ public static final String REQUIRE_TLS = "pref_security_require_tls"; /** boolean for whether the TLS certificate should be verified */ public static final String TLS_CERT_VERIFY = "pref_security_tls_cert_verify"; /** * Global setting controlling how OTR engine initiates: auto, force, * requested, disabled */ public static final String OTR_MODE = "pref_security_otr_mode"; /** boolean to specify whether to use Tor proxying or not */ public static final String USE_TOR = "pref_security_use_tor"; /** * boolean to control whether DNS SRV lookups are used to find the * server */ public static final String DO_DNS_SRV = "pref_security_do_dns_srv"; // GENERAL PREFERENCES /** controls whether this provider should show the offline contacts */ public static final String SHOW_OFFLINE_CONTACTS = "show_offline_contacts"; /** controls whether the GTalk service automatically connect to server. */ public static final String AUTOMATICALLY_CONNECT_GTALK = "gtalk_auto_connect"; /** * controls whether the IM service will be automatically started after * boot */ public static final String AUTOMATICALLY_START_SERVICE = "auto_start_service"; public static final String LINKIFY_ON_TOR = "linkify_on_tor"; /** * Global setting which controls whether the offline contacts will be * hid. */ public static final String HIDE_OFFLINE_CONTACTS = "hide_offline_contacts"; public static final String DELETE_UNSECURED_MEDIA = "delete_unsecured_media"; /** Global setting which controls whether enable the IM notification */ public static final String ENABLE_NOTIFICATION = "enable_notification"; /** Global setting which specifies whether to vibrate */ public static final String NOTIFICATION_VIBRATE = "vibrate"; /** Global setting which specifies the Uri string of the ringtone */ public static final String NOTIFICATION_RINGTONE = "ringtone"; /** Global setting which specifies the Uri of the default ringtone */ public static final String RINGTONE_DEFAULT = "content://settings/system/notification_sound"; /** specifies whether to show mobile indicator to friends */ public static final String SHOW_MOBILE_INDICATOR = "mobile_indicator"; /** specifies whether to show as away when device is idle */ public static final String SHOW_AWAY_ON_IDLE = "show_away_on_idle"; /** controls whether the service gets foreground priority */ public static final String USE_FOREGROUND_PRIORITY = "use_foreground_priority"; /** specifies whether to upload heartbeat stat upon login */ public static final String UPLOAD_HEARTBEAT_STAT = "upload_heartbeat_stat"; /** specifies the last heartbeat interval received from the server */ public static final String HEARTBEAT_INTERVAL = "heartbeat_interval"; /** specifiy the JID resource used for Google Talk connection */ public static final String JID_RESOURCE = "jid_resource"; /** * Used for reliable message queue (RMQ). This is for storing the last * rmq id received from the GTalk server */ public static final String LAST_RMQ_RECEIVED = "last_rmq_rec"; /** * use for status persistence */ public static final String PRESENCE_STATE = "presence_state"; public static final String PRESENCE_STATUS_MESSAGE = "presence_status_message"; /** * Query the settings of the provider specified by id * * @param cr the relative content resolver * @param providerId the specified id of provider * @return a HashMap which contains all the settings for the specified * provider */ public static HashMap<String, String> queryProviderSettings(ContentResolver cr, long providerId) { HashMap<String, String> settings = new HashMap<String, String>(); String[] projection = { NAME, VALUE }; Cursor c = cr.query(ContentUris.withAppendedId(CONTENT_URI, providerId), projection, null, null, null); if (c == null) { return null; } while (c.moveToNext()) { settings.put(c.getString(0), c.getString(1)); } c.close(); return settings; } /** * Get the string value of setting which is specified by provider id and * the setting name. * * @param cr The ContentResolver to use to access the settings table. * @param providerId The id of the provider. * @param settingName The name of the setting. * @return The value of the setting if the setting exist, otherwise * return null. */ public static String getStringValue(ContentResolver cr, long providerId, String settingName) { String ret = null; Cursor c = getSettingValue(cr, providerId, settingName); if (c != null) { ret = c.getString(0); c.close(); } return ret; } /** * Get the string value of setting which is specified by provider id and * the setting name. * * @param cr The ContentResolver to use to access the settings table. * @param providerId The id of the provider. * @param settingName The name of the setting. * @return The value of the setting if the setting exist, otherwise * return null. */ public static int getIntValue(ContentResolver cr, long providerId, String settingName) { int ret = -1; Cursor c = getSettingValue(cr, providerId, settingName); if (c != null) { ret = c.getInt(0); c.close(); } return ret; } /** * Get the boolean value of setting which is specified by provider id * and the setting name. * * @param cr The ContentResolver to use to access the settings table. * @param providerId The id of the provider. * @param settingName The name of the setting. * @return The value of the setting if the setting exist, otherwise * return false. */ public static boolean getBooleanValue(ContentResolver cr, long providerId, String settingName) { boolean ret = false; Cursor c = getSettingValue(cr, providerId, settingName); if (c != null) { ret = c.getInt(0) != 0; c.close(); } return ret; } private static Cursor getSettingValue(ContentResolver cr, long providerId, String settingName) { Cursor c = cr.query(ContentUris.withAppendedId(CONTENT_URI, providerId), new String[] { VALUE }, NAME + "=?", new String[] { settingName }, null); if (c != null) { if (!c.moveToFirst()) { c.close(); return null; } } return c; } /** * Save a long value of setting in the table providerSetting. * * @param cr The ContentProvider used to access the providerSetting * table. * @param providerId The id of the provider. * @param name The name of the setting. * @param value The value of the setting. */ public static void putLongValue(ContentResolver cr, long providerId, String name, long value) { ContentValues v = new ContentValues(3); v.put(PROVIDER, providerId); v.put(NAME, name); v.put(VALUE, value); cr.insert(CONTENT_URI, v); } /** * Save a long value of setting in the table providerSetting. * * @param cr The ContentProvider used to access the providerSetting * table. * @param providerId The id of the provider. * @param name The name of the setting. * @param value The value of the setting. */ public static void putIntValue(ContentResolver cr, long providerId, String name, int value) { ContentValues v = new ContentValues(3); v.put(PROVIDER, providerId); v.put(NAME, name); v.put(VALUE, value); cr.insert(CONTENT_URI, v); } /** * Save a boolean value of setting in the table providerSetting. * * @param cr The ContentProvider used to access the providerSetting * table. * @param providerId The id of the provider. * @param name The name of the setting. * @param value The value of the setting. */ public static void putBooleanValue(ContentResolver cr, long providerId, String name, boolean value) { ContentValues v = new ContentValues(3); v.put(PROVIDER, providerId); v.put(NAME, name); v.put(VALUE, Boolean.toString(value)); cr.insert(CONTENT_URI, v); } /** * Save a string value of setting in the table providerSetting. * * @param cr The ContentProvider used to access the providerSetting * table. * @param providerId The id of the provider. * @param name The name of the setting. * @param value The value of the setting. */ public static void putStringValue(ContentResolver cr, long providerId, String name, String value) { ContentValues v = new ContentValues(3); v.put(PROVIDER, providerId); v.put(NAME, name); v.put(VALUE, value); cr.insert(CONTENT_URI, v); } /** * A convenience method to set the domain name affiliated with an * account * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param domain The domain name to use for the account */ public static void setDomain(ContentResolver cr, long providerId, String domain) { putStringValue(cr, providerId, DOMAIN, domain); } /** * A convenience method to set the XMPP Resource string * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param xmppResource the XMPP Resource string */ public static void setXmppResource(ContentResolver cr, long providerId, String xmppResource) { putStringValue(cr, providerId, XMPP_RESOURCE, xmppResource); } /** * A convenience method to set the XMPP Resource priority * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param priority the XMPP Resource priority */ public static void setXmppResourcePrio(ContentResolver cr, long providerId, int priority) { putLongValue(cr, providerId, XMPP_RESOURCE_PRIO, (long) priority); } /** * A convenience method to set the TCP/IP port number to connect to * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param port the TCP/IP port number to connect to */ public static void setPort(ContentResolver cr, long providerId, int port) { putLongValue(cr, providerId, PORT, (long) port); } /** * A convenience method to set the hostname or IP of the server to * connect to * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param server the hostname or IP of the server to connect to */ public static void setServer(ContentResolver cr, long providerId, String server) { putStringValue(cr, providerId, SERVER, server); } /** * A convenience method to set whether to allow plain text auth * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param allowPlainAuth */ public static void setAllowPlainAuth(ContentResolver cr, long providerId, boolean allowPlainAuth) { putBooleanValue(cr, providerId, ALLOW_PLAIN_AUTH, allowPlainAuth); } /** * A convenience method to set whether to require TLS * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param requireTls */ public static void setRequireTls(ContentResolver cr, long providerId, boolean requireTls) { putBooleanValue(cr, providerId, REQUIRE_TLS, requireTls); } /** * A convenience method to set whether to verify the TLS cert * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param tlsCertVerify */ public static void setTlsCertVerify(ContentResolver cr, long providerId, boolean tlsCertVerify) { putBooleanValue(cr, providerId, TLS_CERT_VERIFY, tlsCertVerify); } /** * A convenience method to set the mode of operation for the OTR Engine * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param otrMode OTR Engine mode (force, auto, requested, disabled) */ public static void setOtrMode(ContentResolver cr, long providerId, String otrMode) { putStringValue(cr, providerId, OTR_MODE, otrMode); } /** * A convenience method to set whether to use Tor * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param useTor */ public static void setUseTor(ContentResolver cr, long providerId, boolean useTor) { putBooleanValue(cr, providerId, USE_TOR, useTor); } /** * A convenience method to set whether to use DNS SRV lookups to find * the server * * @param cr The ContentResolver to use to access the settings table * @param providerId used to identify the set of settings for a given * provider * @param doDnsSrv */ public static void setDoDnsSrv(ContentResolver cr, long providerId, boolean doDnsSrv) { putBooleanValue(cr, providerId, DO_DNS_SRV, doDnsSrv); } /** * A convenience method to set whether or not the GTalk service should * be started automatically. * * @param contentResolver The ContentResolver to use to access the * settings table * @param autoConnect Whether the GTalk service should be started * automatically. */ public static void setAutomaticallyConnectGTalk(ContentResolver contentResolver, long providerId, boolean autoConnect) { putBooleanValue(contentResolver, providerId, AUTOMATICALLY_CONNECT_GTALK, autoConnect); } public static void setLinkifyOnTor(ContentResolver contentResolver, long providerId, boolean linkifyOnTor) { putBooleanValue(contentResolver, providerId, LINKIFY_ON_TOR, linkifyOnTor); } /** * A convenience method to set whether or not the offline contacts * should be hided * * @param contentResolver The ContentResolver to use to access the * setting table * @param hideOfflineContacts Whether the offline contacts should be * hided */ public static void setHideOfflineContacts(ContentResolver contentResolver, long providerId, boolean hideOfflineContacts) { putBooleanValue(contentResolver, providerId, HIDE_OFFLINE_CONTACTS, hideOfflineContacts); } public static void setDeleteUnsecuredMedia(ContentResolver contentResolver, long providerId, boolean deleteUnsecuredMedia) { putBooleanValue(contentResolver, providerId, DELETE_UNSECURED_MEDIA, deleteUnsecuredMedia); } public static void setUseForegroundPriority(ContentResolver contentResolver, long providerId, boolean flag) { putBooleanValue(contentResolver, providerId, USE_FOREGROUND_PRIORITY, flag); } /** * A convenience method to set whether or not enable the IM * notification. * * @param contentResolver The ContentResolver to use to access the * setting table. * @param enable Whether enable the IM notification */ public static void setEnableNotification(ContentResolver contentResolver, long providerId, boolean enable) { putBooleanValue(contentResolver, providerId, ENABLE_NOTIFICATION, enable); } /** * A convenience method to set whether or not to vibrate. * * @param contentResolver The ContentResolver to use to access the * setting table. * @param vibrate Whether or not to vibrate */ public static void setVibrate(ContentResolver contentResolver, long providerId, boolean vibrate) { putBooleanValue(contentResolver, providerId, NOTIFICATION_VIBRATE, vibrate); } /** * A convenience method to set the Uri String of the ringtone. * * @param contentResolver The ContentResolver to use to access the * setting table. * @param ringtoneUri The Uri String of the ringtone to be set. */ public static void setRingtoneURI(ContentResolver contentResolver, long providerId, String ringtoneUri) { putStringValue(contentResolver, providerId, NOTIFICATION_RINGTONE, ringtoneUri); } /** * A convenience method to set whether or not to show mobile indicator. * * @param contentResolver The ContentResolver to use to access the * setting table. * @param showMobileIndicator Whether or not to show mobile indicator. */ public static void setShowMobileIndicator(ContentResolver contentResolver, long providerId, boolean showMobileIndicator) { putBooleanValue(contentResolver, providerId, SHOW_MOBILE_INDICATOR, showMobileIndicator); } /** * A convenience method to set whether or not to show as away when * device is idle. * * @param contentResolver The ContentResolver to use to access the * setting table. * @param showAway Whether or not to show as away when device is idle. */ public static void setShowAwayOnIdle(ContentResolver contentResolver, long providerId, boolean showAway) { putBooleanValue(contentResolver, providerId, SHOW_AWAY_ON_IDLE, showAway); } /** * A convenience method to set whether or not to upload heartbeat stat. * * @param contentResolver The ContentResolver to use to access the * setting table. * @param uploadStat Whether or not to upload heartbeat stat. */ public static void setUploadHeartbeatStat(ContentResolver contentResolver, long providerId, boolean uploadStat) { putBooleanValue(contentResolver, providerId, UPLOAD_HEARTBEAT_STAT, uploadStat); } /** * A convenience method to set the heartbeat interval last received from * the server. * * @param contentResolver The ContentResolver to use to access the * setting table. * @param interval The heartbeat interval last received from the server. */ public static void setHeartbeatInterval(ContentResolver contentResolver, long providerId, long interval) { putLongValue(contentResolver, providerId, HEARTBEAT_INTERVAL, interval); } /** * A convenience method to user configure presence state and status * * @param contentResolver The ContentResolver to use to access the * setting table. * @param interval The heartbeat interval last received from the server. */ public static void setPresence(ContentResolver contentResolver, long providerId, int state, String statusMessage) { if (state != -1) putIntValue(contentResolver, providerId, PRESENCE_STATE, state); if (statusMessage != null) putStringValue(contentResolver, providerId, PRESENCE_STATUS_MESSAGE, statusMessage); } /** A convenience method to set the jid resource. */ public static void setJidResource(ContentResolver contentResolver, long providerId, String jidResource) { putStringValue(contentResolver, providerId, JID_RESOURCE, jidResource); } public static class QueryMap extends ContentQueryMap { private ContentResolver mContentResolver; private long mProviderId; private Exception mStacktrace; /* public QueryMap(ContentResolver contentResolver, boolean keepUpdated, Handler handlerForUpdateNotifications) { this(contentResolver, ProviderSettings.PROVIDER_ID_FOR_GLOBAL_SETTINGS, keepUpdated, handlerForUpdateNotifications); }*/ //contentResolver.query(CONTENT_URI,new String[] {NAME, VALUE},PROVIDER + "=?",new String[] { Long.toString(providerId)},null) public QueryMap(Cursor cursor, ContentResolver contentResolver, long providerId, boolean keepUpdated, Handler handlerForUpdateNotifications) { super(cursor, // no sort order NAME, keepUpdated, handlerForUpdateNotifications); mContentResolver = contentResolver; mProviderId = providerId; mStacktrace = new Exception(); } @Override public synchronized void close() { mStacktrace = null; super.close(); } @Override protected void finalize() throws Throwable { if (mStacktrace != null) { Log.w("GB.Imps", "QueryMap cursor not closed before finalize", mStacktrace); } super.finalize(); } /** * Set if the GTalk service should automatically connect to server. * * @param autoConnect if the GTalk service should auto connect to * server. */ public void setAutomaticallyConnectToGTalkServer(boolean autoConnect) { ProviderSettings.setAutomaticallyConnectGTalk(mContentResolver, mProviderId, autoConnect); } /** * Check if the GTalk service should automatically connect to * server. * * @return if the GTalk service should automatically connect to * server. */ public boolean getAutomaticallyConnectToGTalkServer() { return getBoolean(AUTOMATICALLY_CONNECT_GTALK, true /* default to automatically sign in */); } public void setDomain(String domain) { ProviderSettings.setDomain(mContentResolver, mProviderId, domain); } public String getDomain() { return getString(DOMAIN, ""); } public void setXmppResource(String resource) { ProviderSettings.setXmppResource(mContentResolver, mProviderId, resource); } public String getXmppResource() { String currentResource = getString(XMPP_RESOURCE, ImApp.DEFAULT_XMPP_RESOURCE); String defaultResource; if (currentResource.equals(ImApp.DEFAULT_XMPP_RESOURCE)) { defaultResource = ImApp.DEFAULT_XMPP_RESOURCE + "-" + UUID.randomUUID().toString().substring(0, 8); setXmppResource(defaultResource); return defaultResource; } return currentResource; } public void setXmppResourcePrio(int prio) { ProviderSettings.setXmppResourcePrio(mContentResolver, mProviderId, prio); } public int getXmppResourcePrio() { return (int) getLong(XMPP_RESOURCE_PRIO, ImApp.DEFAULT_XMPP_PRIORITY); } public void setPort(int port) { ProviderSettings.setPort(mContentResolver, mProviderId, port); } public int getPort() { return (int) getLong(PORT, 0 /* by default use XMPP's default port */); } public void setServer(String server) { ProviderSettings.setServer(mContentResolver, mProviderId, server); } public String getServer() { return getString(SERVER, ""); } public void setAllowPlainAuth(boolean value) { ProviderSettings.setAllowPlainAuth(mContentResolver, mProviderId, value); } public boolean getAllowPlainAuth() { return getBoolean(ALLOW_PLAIN_AUTH, false /* by default do not send passwords in the clear */); } public void setRequireTls(boolean value) { ProviderSettings.setRequireTls(mContentResolver, mProviderId, value); } public boolean getRequireTls() { return getBoolean(REQUIRE_TLS, true /* by default attempt TLS but don't require */); //n8fr8 2011/04/20 i think we should require it by default so i set to 'true' } public void setTlsCertVerify(boolean value) { ProviderSettings.setTlsCertVerify(mContentResolver, mProviderId, value); } public boolean getTlsCertVerify() { return getBoolean(TLS_CERT_VERIFY, true /* by default try to verify the TLS Cert */); } public void setOtrMode(String otrMode) { ProviderSettings.setOtrMode(mContentResolver, mProviderId, otrMode); } public String getOtrMode() { return getString(OTR_MODE, ImApp.DEFAULT_XMPP_OTR_MODE /* by default, try to use OTR */); } public void setLinkifyOnTor(boolean value) { ProviderSettings.setLinkifyOnTor(mContentResolver, mProviderId, value); } public boolean getLinkifyOnTor() { return getBoolean(LINKIFY_ON_TOR, false /* default do not linkify */); } public void setUseTor(boolean value) { ProviderSettings.setUseTor(mContentResolver, mProviderId, value); } public boolean getUseTor() { return getBoolean(USE_TOR, false /* by default do not use Tor */); } public void setDoDnsSrv(boolean value) { ProviderSettings.setDoDnsSrv(mContentResolver, mProviderId, value); } public boolean getDoDnsSrv() { return getBoolean(DO_DNS_SRV, true /* by default use DNS SRV to find the server */); } /** * Set whether or not the offline contacts should be hided. * * @param hideOfflineContacts Whether or not the offline contacts * should be hided. */ public void setHideOfflineContacts(boolean hideOfflineContacts) { ProviderSettings.setHideOfflineContacts(mContentResolver, mProviderId, hideOfflineContacts); } /** * Check if the offline contacts should be hided. * * @return Whether or not the offline contacts should be hided. */ public boolean getHideOfflineContacts() { return getBoolean(HIDE_OFFLINE_CONTACTS, false /* default*/); } public void setDeleteUnsecuredMedia(boolean deleteUnsecuredMedia) { ProviderSettings.setDeleteUnsecuredMedia(mContentResolver, mProviderId, deleteUnsecuredMedia); } public boolean getDeleteUnsecuredMedia() { return getBoolean(DELETE_UNSECURED_MEDIA, false /* default */); } public void setUseForegroundPriority(boolean flag) { ProviderSettings.setUseForegroundPriority(mContentResolver, mProviderId, flag); } public boolean getUseForegroundPriority() { return getBoolean(USE_FOREGROUND_PRIORITY, false /* default */); } /** * Set whether or not enable the IM notification. * * @param enable Whether or not enable the IM notification. */ public void setEnableNotification(boolean enable) { ProviderSettings.setEnableNotification(mContentResolver, mProviderId, enable); } /** * Check if the IM notification is enabled. * * @return Whether or not enable the IM notification. */ public boolean getEnableNotification() { return getBoolean(ENABLE_NOTIFICATION, true/* by default enable the notification */); } /** * Set whether or not to vibrate on IM notification. * * @param vibrate Whether or not to vibrate. */ public void setVibrate(boolean vibrate) { ProviderSettings.setVibrate(mContentResolver, mProviderId, vibrate); } /** * Gets whether or not to vibrate on IM notification. * * @return Whether or not to vibrate. */ public boolean getVibrate() { return getBoolean(NOTIFICATION_VIBRATE, true /* by default enable vibrate */); } /** * Set the Uri for the ringtone. * * @param ringtoneUri The Uri of the ringtone to be set. */ public void setRingtoneURI(String ringtoneUri) { ProviderSettings.setRingtoneURI(mContentResolver, mProviderId, ringtoneUri); } /** * Get the Uri String of the current ringtone. * * @return The Uri String of the current ringtone. */ public String getRingtoneURI() { return getString(NOTIFICATION_RINGTONE, RINGTONE_DEFAULT); } /** * Set whether or not to show mobile indicator to friends. * * @param showMobile whether or not to show mobile indicator. */ public void setShowMobileIndicator(boolean showMobile) { ProviderSettings.setShowMobileIndicator(mContentResolver, mProviderId, showMobile); } /** * Gets whether or not to show mobile indicator. * * @return Whether or not to show mobile indicator. */ public boolean getShowMobileIndicator() { return getBoolean(SHOW_MOBILE_INDICATOR, true /* by default show mobile indicator */); } /** * Set whether or not to show as away when device is idle. * * @param showAway whether or not to show as away when device is * idle. */ public void setShowAwayOnIdle(boolean showAway) { ProviderSettings.setShowAwayOnIdle(mContentResolver, mProviderId, showAway); } /** * Get whether or not to show as away when device is idle. * * @return Whether or not to show as away when device is idle. */ public boolean getShowAwayOnIdle() { return getBoolean(SHOW_AWAY_ON_IDLE, true /* by default show as away on idle*/); } /** * Set whether or not to upload heartbeat stat. * * @param uploadStat whether or not to upload heartbeat stat. */ public void setUploadHeartbeatStat(boolean uploadStat) { ProviderSettings.setUploadHeartbeatStat(mContentResolver, mProviderId, uploadStat); } /** * Get whether or not to upload heartbeat stat. * * @return Whether or not to upload heartbeat stat. */ public boolean getUploadHeartbeatStat() { return getBoolean(UPLOAD_HEARTBEAT_STAT, false /* by default do not upload */); } /** * Set the heartbeat interval. */ public void setHeartbeatInterval(long interval) { if (interval <= 0) { interval = 1; } else if (interval > 99) { interval = 99; } ProviderSettings.setHeartbeatInterval(mContentResolver, mProviderId, interval); } /** * Get the heartbeat interval, default to 1. */ public long getHeartbeatInterval() { return getLong(HEARTBEAT_INTERVAL, 1); } /** * Set the JID resource. * * @param jidResource the jid resource to be stored. */ public void setJidResource(String jidResource) { ProviderSettings.setJidResource(mContentResolver, mProviderId, jidResource); } /** * Get the JID resource used for the Google Talk connection * * @return the JID resource stored. */ public String getJidResource() { return getString(JID_RESOURCE, null); } /** * Convenience function for retrieving a single settings value as a * boolean. * * @param name The name of the setting to retrieve. * @param def Value to return if the setting is not defined. * @return The setting's current value, or 'def' if it is not * defined. */ private boolean getBoolean(String name, boolean def) { ContentValues values = getValues(name); return values != null ? values.getAsBoolean(VALUE) : def; } /** * Convenience function for retrieving a single settings value as a * String. * * @param name The name of the setting to retrieve. * @param def The value to return if the setting is not defined. * @return The setting's current value or 'def' if it is not * defined. */ private String getString(String name, String def) { ContentValues values = getValues(name); return values != null ? values.getAsString(VALUE) : def; } /** * Convenience function for retrieving a single settings value as an * Integer. * * @param name The name of the setting to retrieve. * @param def The value to return if the setting is not defined. * @return The setting's current value or 'def' if it is not * defined. */ private int getInteger(String name, int def) { ContentValues values = getValues(name); return values != null ? values.getAsInteger(VALUE) : def; } /** * Convenience function for retrieving a single settings value as a * Long. * * @param name The name of the setting to retrieve. * @param def The value to return if the setting is not defined. * @return The setting's current value or 'def' if it is not * defined. */ private long getLong(String name, long def) { ContentValues values = getValues(name); return values != null ? values.getAsLong(VALUE) : def; } } } /** * Columns for IM branding resource map cache table. This table caches the * result of loading the branding resources to speed up IM landing page * start. */ public interface BrandingResourceMapCacheColumns { /** The provider ID <P>Type: INTEGER</P> */ String PROVIDER_ID = "provider_id"; /** The application resource ID <P>Type: INTEGER</P> */ String APP_RES_ID = "app_res_id"; /** The plugin resource ID <P>Type: INTEGER</P> */ String PLUGIN_RES_ID = "plugin_res_id"; } /** The table for caching the result of loading IM branding resources. */ public static final class BrandingResourceMapCache implements BaseColumns, BrandingResourceMapCacheColumns { /** The content:// style URL for this table. */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/brandingResMapCache"); } /** * //TODO: move these to MCS specific provider. The following are MCS stuff, * and should really live in a separate provider specific to MCS code. */ /** Columns from OutgoingRmq table */ public interface OutgoingRmqColumns { String RMQ_ID = "rmq_id"; String TIMESTAMP = "ts"; String DATA = "data"; String PROTOBUF_TAG = "type"; } /** * //TODO: we should really move these to their own provider and database. * The table for storing outgoing rmq packets. */ public static final class OutgoingRmq implements BaseColumns, OutgoingRmqColumns { private static String[] RMQ_ID_PROJECTION = new String[] { RMQ_ID, }; /** * queryHighestRmqId * * @param resolver the content resolver * @return the highest rmq id assigned to the rmq packet, or 0 if there * are no rmq packets in the OutgoingRmq table. */ public static final long queryHighestRmqId(ContentResolver resolver) { Cursor cursor = resolver.query(Imps.OutgoingRmq.CONTENT_URI_FOR_HIGHEST_RMQ_ID, RMQ_ID_PROJECTION, null, // selection null, // selection args null // sort ); long retVal = 0; try { //if (DBG) log("initializeRmqid: cursor.count= " + cursor.count()); if (cursor.moveToFirst()) { retVal = cursor.getLong(cursor.getColumnIndexOrThrow(RMQ_ID)); } } finally { cursor.close(); } return retVal; } /** The content:// style URL for this table. */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/outgoingRmqMessages"); /** * The content:// style URL for the highest rmq id for the outgoing rmq * messages */ public static final Uri CONTENT_URI_FOR_HIGHEST_RMQ_ID = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/outgoingHighestRmqId"); /** The default sort order for this table. */ public static final String DEFAULT_SORT_ORDER = "rmq_id ASC"; } /** * Columns for the LastRmqId table, which stores a single row for the last * client rmq id sent to the server. */ public interface LastRmqIdColumns { String RMQ_ID = "rmq_id"; } /** * //TODO: move these out into their own provider and database The table for * storing the last client rmq id sent to the server. */ public static final class LastRmqId implements BaseColumns, LastRmqIdColumns { private static String[] PROJECTION = new String[] { RMQ_ID, }; /** * queryLastRmqId * * queries the last rmq id saved in the LastRmqId table. * * @param resolver the content resolver. * @return the last rmq id stored in the LastRmqId table, or 0 if not * found. */ public static final long queryLastRmqId(ContentResolver resolver) { Cursor cursor = resolver.query(Imps.LastRmqId.CONTENT_URI, PROJECTION, null, // selection null, // selection args null // sort ); long retVal = 0; try { if (cursor.moveToFirst()) { retVal = cursor.getLong(cursor.getColumnIndexOrThrow(RMQ_ID)); } } finally { cursor.close(); } return retVal; } /** * saveLastRmqId * * saves the rmqId to the lastRmqId table. This will override the * existing row if any, as we only keep one row of data in this table. * * @param resolver the content resolver. * @param rmqId the rmq id to be saved. */ public static final void saveLastRmqId(ContentResolver resolver, long rmqId) { ContentValues values = new ContentValues(); // always replace the first row. values.put(_ID, 1); values.put(RMQ_ID, rmqId); resolver.insert(CONTENT_URI, values); } /** The content:// style URL for this table. */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/lastRmqId"); } /** * Columns for the s2dRmqIds table, which stores the server-to-device * message persistent ids. These are used in the RMQ2 protocol, where in the * login request, the client selective acks these s2d ids to the server. */ public interface ServerToDeviceRmqIdsColumn { String RMQ_ID = "rmq_id"; } public static final class ServerToDeviceRmqIds implements BaseColumns, ServerToDeviceRmqIdsColumn { /** The content:// style URL for this table. */ public static final Uri CONTENT_URI = Uri .parse("content://info.guardianproject.otr.app.im.provider.Imps/s2dids"); } public static boolean isUnlocked(Context context) { try { Cursor cursor = null; Uri uri = Imps.Provider.CONTENT_URI_WITH_ACCOUNT; Builder builder = uri.buildUpon(); builder = builder.appendQueryParameter(ImApp.NO_CREATE_KEY, "1"); uri = builder.build(); cursor = context.getContentResolver().query( uri, null, Imps.Provider.CATEGORY + "=?" /* selection */, new String[] { ImApp.IMPS_CATEGORY } /* selection args */, null); if (cursor != null) { cursor.close(); return true; } else { return false; } } catch (Exception e) { // Only complain if we thought this password should succeed Log.e(ImApp.LOG_TAG, e.getMessage(), e); // needs to be unlocked return false; } } public static boolean isUnencrypted(Context context) { try { Cursor cursor = null; Uri uri = Imps.Provider.CONTENT_URI_WITH_ACCOUNT; Builder builder = uri.buildUpon(); builder.appendQueryParameter(ImApp.CACHEWORD_PASSWORD_KEY, ""); builder = builder.appendQueryParameter(ImApp.NO_CREATE_KEY, "1"); uri = builder.build(); cursor = context.getContentResolver().query( uri, null, Imps.Provider.CATEGORY + "=?" /* selection */, new String[] { ImApp.IMPS_CATEGORY } /* selection args */, null); if (cursor != null) { cursor.close(); return true; } else { return false; } } catch (Exception e) { // Only complain if we thought this password should succeed Log.e(ImApp.LOG_TAG, e.getMessage(), e); // needs to be unlocked return false; } } public static boolean setEmptyPassphrase(Context ctx, boolean noCreate) { String pkey = ""; Uri uri = Provider.CONTENT_URI_WITH_ACCOUNT; Builder builder = uri.buildUpon().appendQueryParameter(ImApp.CACHEWORD_PASSWORD_KEY, pkey); if (noCreate) { builder.appendQueryParameter(ImApp.NO_CREATE_KEY, "1"); } uri = builder.build(); Cursor cursor = ctx.getContentResolver().query(uri, null, null, null, null); if (cursor != null) { cursor.close(); return true; } return false; } public static void clearPassphrase(Context ctx) { Uri uri = Provider.CONTENT_URI_WITH_ACCOUNT; Builder builder = uri.buildUpon().appendQueryParameter(ImApp.CLEAR_PASSWORD_KEY, "1"); uri = builder.build(); Cursor cursor = ctx.getContentResolver().query(uri, null, null, null, null); if (cursor != null) { throw new RuntimeException("Unexpected cursor returned"); } } public static Uri insertMessageInDb(ContentResolver resolver, boolean isGroup, long contactId, boolean isEncrypted, String nickname, String body, long time, int type, int errCode, String id, String mimeType) { ContentValues values = new ContentValues(); values.put(Imps.Messages.BODY, body); values.put(Imps.Messages.DATE, time); values.put(Imps.Messages.TYPE, type); values.put(Imps.Messages.ERROR_CODE, errCode); if (isGroup) { values.put(Imps.Messages.NICKNAME, nickname); values.put(Imps.Messages.IS_GROUP_CHAT, 1); } values.put(Imps.Messages.IS_DELIVERED, 0); values.put(Imps.Messages.MIME_TYPE, mimeType); values.put(Imps.Messages.PACKET_ID, id); return resolver.insert(isEncrypted ? Messages.getOtrMessagesContentUriByThreadId(contactId) : Messages.getContentUriByThreadId(contactId), values); } public static int updateMessageBody(ContentResolver resolver, String id, String body, String mimeType) { Uri.Builder builder = Imps.Messages.OTR_MESSAGES_CONTENT_URI.buildUpon(); builder.appendPath(id); ContentValues values = new ContentValues(); values.put(Imps.Messages.BODY, body); values.put(Imps.Messages.MIME_TYPE, mimeType); return resolver.update(builder.build(), values, null, null); } public static int updateConfirmInDb(ContentResolver resolver, String id, boolean isDelivered) { Uri.Builder builder = Imps.Messages.OTR_MESSAGES_CONTENT_URI_BY_PACKET_ID.buildUpon(); builder.appendPath(id); ContentValues values = new ContentValues(1); values.put(Imps.Messages.IS_DELIVERED, isDelivered); return resolver.update(builder.build(), values, null, null); } }