| /* |
| * Copyright (C) 2008 Esmertec AG. |
| * Copyright (C) 2008 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 com.android.im.app; |
| |
| import com.android.im.plugin.ImConfigNames; |
| import com.android.im.provider.Imps; |
| |
| import android.content.ContentResolver; |
| import android.content.ContentUris; |
| import android.content.ContentValues; |
| import android.database.Cursor; |
| import android.graphics.Bitmap; |
| import android.graphics.BitmapFactory; |
| import android.graphics.drawable.BitmapDrawable; |
| import android.graphics.drawable.Drawable; |
| import android.net.Uri; |
| import android.util.Log; |
| import android.util.base64.Base64; |
| |
| import java.util.Map; |
| |
| public class DatabaseUtils { |
| |
| private static final String TAG = ImApp.LOG_TAG; |
| |
| private DatabaseUtils() { |
| } |
| |
| public static Cursor queryAccountsForProvider(ContentResolver cr, |
| String[] projection, long providerId) { |
| StringBuilder where = new StringBuilder(Imps.Account.ACTIVE); |
| where.append("=1 AND ").append(Imps.Account.PROVIDER).append('=').append(providerId); |
| Cursor c = cr.query(Imps.Account.CONTENT_URI, projection, where.toString(), null, null); |
| if (c != null && !c.moveToFirst()) { |
| c.close(); |
| return null; |
| } |
| return c; |
| } |
| |
| public static Drawable getAvatarFromCursor(Cursor cursor, int dataColumn) { |
| byte[] rawData = cursor.getBlob(dataColumn); |
| if (rawData == null) { |
| return null; |
| } |
| return decodeAvatar(rawData); |
| } |
| |
| public static Uri getAvatarUri(Uri baseUri, long providerId, long accountId) { |
| Uri.Builder builder = baseUri.buildUpon(); |
| ContentUris.appendId(builder, providerId); |
| ContentUris.appendId(builder, accountId); |
| return builder.build(); |
| } |
| |
| public static Drawable getAvatarFromCursor(Cursor cursor, int dataColumn, |
| int encodedDataColumn, String username, boolean updateBlobUseCursor, |
| ContentResolver resolver, Uri updateBlobUri) { |
| /** |
| * Optimization: the avatar table in IM content provider have two |
| * columns, one for the raw blob data, another for the base64 encoded |
| * data. The reason for this is when the avatars are initially |
| * downloaded, they are in the base64 encoded form, and instead of |
| * base64 decode the avatars for all the buddies up front, we can just |
| * simply store the encoded data in the table, and decode them on demand |
| * when displaying them. Once we decode the avatar, we store the decoded |
| * data as a blob, and null out the encoded column in the avatars table. |
| * query the raw blob data first, if present, great; if not, query the |
| * encoded data, decode it and store as the blob, and null out the |
| * encoded column. |
| */ |
| byte[] rawData = cursor.getBlob(dataColumn); |
| |
| if (rawData == null) { |
| String encodedData = cursor.getString(encodedDataColumn); |
| if (encodedData == null) { |
| // Log.e(LogTag.LOG_TAG, "getAvatarFromCursor for " + username + |
| // ", no raw or encoded data!"); |
| return null; |
| } |
| |
| rawData = Base64.decode(encodedData, Base64.DEFAULT); |
| |
| // if (DBG) { |
| // log("getAvatarFromCursor for " + username + ": found encoded |
| // data," |
| // + " update blob with data, len=" + rawData.length); |
| // } |
| |
| if (updateBlobUseCursor) { |
| cursor.updateBlob(dataColumn, rawData); |
| cursor.updateString(encodedDataColumn, null); |
| cursor.commitUpdates(); |
| } else { |
| updateAvatarBlob(resolver, updateBlobUri, rawData, username); |
| } |
| } |
| |
| return decodeAvatar(rawData); |
| } |
| |
| private static void updateAvatarBlob(ContentResolver resolver, Uri updateUri, byte[] data, |
| String username) { |
| ContentValues values = new ContentValues(3); |
| values.put(Imps.Avatars.DATA, data); |
| |
| StringBuilder buf = new StringBuilder(Imps.Avatars.CONTACT); |
| buf.append("=?"); |
| |
| String[] selectionArgs = new String[] { |
| username |
| }; |
| |
| resolver.update(updateUri, values, buf.toString(), selectionArgs); |
| } |
| |
| private static Drawable decodeAvatar(byte[] data) { |
| Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length); |
| Drawable avatar = new BitmapDrawable(b); |
| return avatar; |
| } |
| |
| /** |
| * Update IM provider database for a plugin using newly loaded information. |
| * @param cr the resolver |
| * @param providerName the plugin provider name |
| * @param providerFullName the full name |
| * @param signUpUrl the plugin's service signup URL |
| * @param config the plugin's settings |
| * @return the provider ID of the plugin |
| */ |
| public static long updateProviderDb(ContentResolver cr, |
| String providerName, String providerFullName, String signUpUrl, |
| Map<String, String> config) { |
| boolean versionChanged; |
| |
| // query provider data |
| long providerId = Imps.Provider.getProviderIdForName(cr, providerName); |
| if (providerId > 0) { |
| // already loaded, check if version changed |
| String pluginVersion = config.get(ImConfigNames.PLUGIN_VERSION); |
| if (!isPluginVersionChanged(cr, providerId, pluginVersion)) { |
| // no change, just return |
| return providerId; |
| } |
| // changed, update provider meta data |
| updateProviderRow(cr, providerId, providerFullName, signUpUrl); |
| // clear branding resource map cache |
| clearBrandingResourceMapCache(cr, providerId); |
| |
| Log.d(TAG, "Plugin " + providerName + "(" + providerId + |
| ") has a version change. Database updated."); |
| } else { |
| // new plugin, not loaded before, insert the provider data |
| providerId = insertProviderRow(cr, providerName, providerFullName, signUpUrl); |
| |
| Log.d(TAG, "Plugin " + providerName + "(" + providerId + |
| ") is new. Provider added to IM db."); |
| } |
| |
| // plugin provider has been inserted/updated, we need to update settings |
| saveProviderSettings(cr, providerId, config); |
| |
| return providerId; |
| } |
| |
| /** |
| * Clear the branding resource map cache. |
| */ |
| private static int clearBrandingResourceMapCache(ContentResolver cr, long providerId) { |
| StringBuilder where = new StringBuilder(); |
| where.append(Imps.BrandingResourceMapCache.PROVIDER_ID); |
| where.append('='); |
| where.append(providerId); |
| return cr.delete(Imps.BrandingResourceMapCache.CONTENT_URI, where.toString(), null); |
| } |
| |
| /** |
| * Insert the plugin settings into the database. |
| */ |
| private static int saveProviderSettings(ContentResolver cr, long providerId, |
| Map<String, String> config) { |
| ContentValues[] settingValues = new ContentValues[config.size()]; |
| int index = 0; |
| for (Map.Entry<String, String> entry : config.entrySet()) { |
| ContentValues settingValue = new ContentValues(); |
| settingValue.put(Imps.ProviderSettings.PROVIDER, providerId); |
| settingValue.put(Imps.ProviderSettings.NAME, entry.getKey()); |
| settingValue.put(Imps.ProviderSettings.VALUE, entry.getValue()); |
| settingValues[index++] = settingValue; |
| } |
| return cr.bulkInsert(Imps.ProviderSettings.CONTENT_URI, settingValues); |
| } |
| |
| /** |
| * Insert a new plugin provider to the provider table. |
| */ |
| private static long insertProviderRow(ContentResolver cr, String providerName, |
| String providerFullName, String signUpUrl) { |
| ContentValues values = new ContentValues(3); |
| values.put(Imps.Provider.NAME, providerName); |
| values.put(Imps.Provider.FULLNAME, providerFullName); |
| values.put(Imps.Provider.CATEGORY, ImApp.IMPS_CATEGORY); |
| values.put(Imps.Provider.SIGNUP_URL, signUpUrl); |
| Uri result = cr.insert(Imps.Provider.CONTENT_URI, values); |
| return ContentUris.parseId(result); |
| } |
| |
| /** |
| * Update the data of a plugin provider. |
| */ |
| private static int updateProviderRow(ContentResolver cr, long providerId, |
| String providerFullName, String signUpUrl) { |
| // Update the full name, signup url and category each time when the plugin change |
| // instead of specific version change because this is called only once. |
| // It's ok to update them even the values are not changed. |
| // Note that we don't update the provider name because it's used as |
| // identifier at some place and the plugin should never change it. |
| ContentValues values = new ContentValues(3); |
| values.put(Imps.Provider.FULLNAME, providerFullName); |
| values.put(Imps.Provider.SIGNUP_URL, signUpUrl); |
| values.put(Imps.Provider.CATEGORY, ImApp.IMPS_CATEGORY); |
| Uri uri = ContentUris.withAppendedId(Imps.Provider.CONTENT_URI, providerId); |
| return cr.update(uri, values, null, null); |
| } |
| |
| /** |
| * Compare the saved version of a plugin provider with the newly loaded version. |
| */ |
| private static boolean isPluginVersionChanged(ContentResolver cr, long providerId, |
| String newVersion) { |
| String oldVersion = Imps.ProviderSettings.getStringValue(cr, providerId, |
| ImConfigNames.PLUGIN_VERSION); |
| if (oldVersion == null) { |
| return true; |
| } |
| return !oldVersion.equals(newVersion); |
| } |
| } |