/*
* 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 org.awesomeapp.messenger.ui.legacy;
import org.awesomeapp.messenger.plugin.ImConfigNames;
import org.awesomeapp.messenger.ImApp;
import org.awesomeapp.messenger.provider.Imps;
import org.awesomeapp.messenger.ui.widgets.RoundedAvatarDrawable;
import java.util.Map;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
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;
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 RoundedAvatarDrawable getAvatarFromCursor(Cursor cursor, int dataColumn, int width, int height) throws DecoderException {
String hexData = cursor.getString(dataColumn);
if (hexData.equals("NULL")) {
return null;
}
byte[] data = Hex.decodeHex(hexData.substring(2, hexData.length() - 1).toCharArray());
return decodeRoundAvatar(data, width, height);
}
public static BitmapDrawable getHeaderImageFromCursor(Cursor cursor, int dataColumn, int width, int height) throws DecoderException {
String hexData = cursor.getString(dataColumn);
if (hexData.equals("NULL")) {
return null;
}
byte[] data = Hex.decodeHex(hexData.substring(2, hexData.length() - 1).toCharArray());
return decodeSquareAvatar(data, width, height);
}
public static Drawable getAvatarFromAddress(ContentResolver cr, String address, int width, int height) throws DecoderException {
return getAvatarFromAddress(cr,address,width,height,true);
}
public static Drawable getAvatarFromAddress(ContentResolver cr, String address, int width, int height, boolean getRound) throws DecoderException {
byte[] data = getAvatarBytesFromAddress(cr, address);
if (data != null)
if (getRound)
return decodeRoundAvatar(data, width, height);
else
return decodeSquareAvatar(data, width, height);
else
return null;
}
public static byte[] getAvatarBytesFromAddress(ContentResolver cr, String address) throws DecoderException {
String[] projection = {Imps.Avatars.DATA};
String[] args = {address};
String query = Imps.Avatars.CONTACT + " LIKE ?";
Cursor cursor = cr.query(Imps.Avatars.CONTENT_URI, projection,
query, args, Imps.Avatars.DEFAULT_SORT_ORDER);
byte[] data = null;
if (cursor != null) {
if (cursor.moveToFirst())
data = cursor.getBlob(0);
cursor.close();
}
return data;
}
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 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);
}
public static boolean hasAvatarContact(ContentResolver resolver, Uri updateUri,
String username) {
ContentValues values = new ContentValues(3);
values.put(Imps.Avatars.CONTACT, username);
StringBuilder buf = new StringBuilder(Imps.Avatars.CONTACT);
buf.append("=?");
String[] selectionArgs = new String[] { username };
return resolver.update(updateUri, values, buf.toString(), selectionArgs) > 0;
}
public static boolean doesAvatarHashExist(ContentResolver resolver, Uri queryUri,
String jid, String hash) {
StringBuilder buf = new StringBuilder(Imps.Avatars.CONTACT);
buf.append("=?");
buf.append(" AND ");
buf.append(Imps.Avatars.HASH);
buf.append("=?");
String[] selectionArgs = new String[] { jid, hash };
Cursor cursor = resolver.query(queryUri, null, buf.toString(), selectionArgs, null);
if (cursor == null)
return false;
try {
return cursor.getCount() > 0;
} finally {
cursor.close();
}
}
public static void insertAvatarBlob(ContentResolver resolver, Uri updateUri, long providerId, long accountId, byte[] data, String hash,
String contact) {
ContentValues values = new ContentValues(5);
values.put(Imps.Avatars.CONTACT, contact);
values.put(Imps.Avatars.DATA, data);
values.put(Imps.Avatars.PROVIDER, providerId);
values.put(Imps.Avatars.ACCOUNT, accountId);
values.put(Imps.Avatars.HASH, hash);
resolver.insert(updateUri, values);
}
private static BitmapDrawable decodeSquareAvatar(byte[] data, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
options.inSampleSize = calculateInSampleSize(options, width, height);
options.inJustDecodeBounds = false;
Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length,options);
if (b != null)
{
return new BitmapDrawable(b);
}
else
return null;
}
private static RoundedAvatarDrawable decodeRoundAvatar(byte[] data, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length,options);
options.inSampleSize = calculateInSampleSize(options, width, height);
options.inJustDecodeBounds = false;
Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length,options);
if (b != null)
{
RoundedAvatarDrawable avatar = new RoundedAvatarDrawable(b);
return avatar;
}
else
return null;
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
/**
* 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);
}
}