/*
* Copyright (C) 2010 mAPPn.Inc
*
* 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.mappn.gfan.common.util;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.text.TextUtils;
import com.mappn.gfan.Session;
import com.mappn.gfan.common.download.DownloadProvider;
/**
* aMarket Content Provider
*
* @author andrew
* @date 2011-4-25
* @since Version 0.7.0
*/
public class MarketProvider extends ContentProvider {
/** The database that lies underneath this content provider */
private SQLiteOpenHelper mOpenHelper = null;
/** Database filename */
private static final String DB_NAME = "market.db";
/** Current database version */
private static final int DB_VERSION = 70;
/** Name of search history table in the database */
public static final String TABLE_SEARCH_HISTORY = "search_history";
/** Name of product table in the database */
public static final String TABLE_PRODUCTS = "products";
/** Name of update table in the database */
public static final String TABLE_UPDATES = "updates";
/** Name of buy table in the database */
public static final String TABLE_BUY = "buy";
/** Name of card table in the database */
public static final String TABLE_CARD = "card";
/** MIME type for the entire list */
private static final String LIST_TYPE = "vnd.android.cursor.dir/";
/** MIME type for an individual item */
private static final String ITEM_TYPE = "vnd.android.cursor.item/";
/** URI matcher used to recognize URIs sent by applications */
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
/** URI matcher constant for the URI of an search_history */
private static final int SEARCH_HISTORY = 1;
private static final int SEARCH_HISTORY_ID = 2;
private static final int PRODUCTS = 3;
private static final int UPDATE_PRODUCT = 4;
private static final int BUY_PRODUCT = 5;
private static final int CARD = 6;
static {
sURIMatcher.addURI("gfan", "search_history", SEARCH_HISTORY);
sURIMatcher.addURI("gfan", "search_history/#", SEARCH_HISTORY_ID);
sURIMatcher.addURI("gfan", "products", PRODUCTS);
sURIMatcher.addURI("gfan", "updates", UPDATE_PRODUCT);
sURIMatcher.addURI("gfan", "buy", BUY_PRODUCT);
sURIMatcher.addURI("gfan", "card", CARD);
}
/**
* The content:// URI to access search history
*/
public static final Uri SEARCH_CONTENT_URI = Uri.parse("content://gfan/search_history");
/**
* The content:// URI to access cached products
*/
public static final Uri PRODUCTS_CONTENT_URI = Uri.parse("content://gfan/products");
/**
* The content:// URI to access update products
*/
public static final Uri UPDATE_CONTENT_URI = Uri.parse("content://gfan/updates");
/**
* The content:// URI to access purchased products
*/
public static final Uri BUY_CONTENT_URI = Uri.parse("content://gfan/buy");
/**
* The content:// URI to access card
*/
public static final Uri CARD_CONTENT_URI = Uri.parse("content://gfan/card");
/** Table ID */
public static final String COLUMN_ID = "_id";
/** 搜索关键词 */
public static final String COLUMN_SEARCH_KEY_WORD = "keyword";
/** 产品表 */
public static final String COLUMN_P_ID = "p_id";
public static final String COLUMN_P_NAME = "p_name";
public static final String COLUMN_P_PACKAGE_NAME = "p_package_name";
public static final String COLUMN_P_CATEGORY = "p_category";
public static final String COLUMN_P_PAYMENT_TYPE = "p_payment_type";
public static final String COLUMN_P_PRICE = "p_price";
public static final String COLUMN_P_SIZE = "p_size";
public static final String COLUMN_P_ICON_URL = "p_icon_url";
public static final String COLUMN_P_IS_RECOMMEND = "p_is_recommend";
/** 可更新产品表(产品ID、包名、更新版本) */
public static final String COLUMN_P_NEW_VERSION_NAME = "p_new_version_name";
public static final String COLUMN_P_NEW_VERSION_CODE = "p_new_version_code";
public static final String COLUMN_P_IGNORE = "p_update_ingore";
public static final String COLUMN_CARD_NAME = "card_name";
public static final String COLUMN_CARD_PAY_TYPE = "card_pay_type";
public static final String COLUMN_CARD_ACCOUNTNUM = "card_account_num";
public static final String COLUMN_CARD_PASSWORDNUM = "card_password_num";
public static final String COLUMN_CARD_CREDIT = "card_credit";
/**
* This class encapsulates a SQL where clause and its parameters. It makes it possible for
* shared methods (like {@link DownloadProvider#getWhereClause(Uri, String, String[], int)}) to
* return both pieces of information, and provides some utility logic to ease piece-by-piece
* construction of selections.
*/
private static class SqlSelection {
public StringBuilder mWhereClause = new StringBuilder();
public List<String> mParameters = new ArrayList<String>();
public <T> void appendClause(String newClause, final T... parameters) {
if (TextUtils.isEmpty(newClause)) {
return;
}
if (mWhereClause.length() != 0) {
mWhereClause.append(" AND ");
}
mWhereClause.append("(");
mWhereClause.append(newClause);
mWhereClause.append(")");
if (parameters != null) {
for (Object parameter : parameters) {
mParameters.add(parameter.toString());
}
}
}
public String getSelection() {
return mWhereClause.toString();
}
public String[] getParameters() {
String[] array = new String[mParameters.size()];
return mParameters.toArray(array);
}
}
/**
* Creates and updated database on demand when opening it.
* Helper class to create database the first time the provider is
* initialized and upgrade it when a new version of the provider needs
* an updated version of the database.
*/
private final class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(final Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
Utils.D("create the new database...");
onUpgrade(db, 0, DB_VERSION);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Utils.D("update the database...");
if (oldVersion < newVersion) {
// 删除0.7.0版本之前的设置
Session.get(getContext()).setUpdataCheckTime(0);
Session.get(getContext()).setUpgradeNumber(0);
db.execSQL("DROP TABLE IF EXISTS installed");
}
createSearchHistoryTable(db);
createProductTable(db);
createUpdateTable(db);
createPurchesdTable(db);
createCardTable(db);
}
/*
* 创建搜索历史表
*/
private void createSearchHistoryTable(SQLiteDatabase db) {
try {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_SEARCH_HISTORY);
db.execSQL("CREATE TABLE " + TABLE_SEARCH_HISTORY + "(" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_SEARCH_KEY_WORD + " TEXT);");
} catch (SQLException ex) {
Utils.D("couldn't create " + TABLE_SEARCH_HISTORY + " table in market database");
throw ex;
}
}
/*
* 创建产品缓存表
*/
private void createProductTable(SQLiteDatabase db) {
try {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_PRODUCTS);
db.execSQL("CREATE TABLE " + TABLE_PRODUCTS + "(" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_P_ID + " TEXT, " +
COLUMN_P_NAME + " TEXT, " +
COLUMN_P_PACKAGE_NAME + " TEXT, " +
COLUMN_P_CATEGORY + " TEXT, " +
COLUMN_P_PAYMENT_TYPE + " TEXT, " +
COLUMN_P_SIZE + " TEXT, " +
COLUMN_P_PRICE + " TEXT, " +
COLUMN_P_ICON_URL + " TEXT, " +
COLUMN_P_IS_RECOMMEND + " TEXT);");
} catch (SQLException ex) {
Utils.D("couldn't create " + TABLE_PRODUCTS + " table in market database");
throw ex;
}
}
/*
* 创建更新产品表
*/
private void createUpdateTable(SQLiteDatabase db) {
try {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_UPDATES);
db.execSQL("CREATE TABLE " + TABLE_UPDATES + "(" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_P_ID + " TEXT, " +
COLUMN_P_PACKAGE_NAME + " TEXT, " +
COLUMN_P_NEW_VERSION_NAME + " TEXT, " +
COLUMN_P_NEW_VERSION_CODE + " TEXT, " +
COLUMN_P_IGNORE + " INTEGER);");
} catch (SQLException ex) {
Utils.D("couldn't create " + TABLE_UPDATES + " table in market database");
throw ex;
}
}
/*
* 创建产品购买历史表
*/
private void createPurchesdTable(SQLiteDatabase db) {
try {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_BUY);
db.execSQL("CREATE TABLE " + TABLE_BUY + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT ," +
COLUMN_P_ID + " TEXT ," +
COLUMN_P_PACKAGE_NAME + " TEXT);");
} catch (SQLException ex) {
Utils.D("couldn't create " + TABLE_BUY + " table in market database");
throw ex;
}
}
/*
* 创建充值卡表
*/
private void createCardTable(SQLiteDatabase db) {
try {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_CARD);
db.execSQL("CREATE TABLE " + TABLE_CARD + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
COLUMN_CARD_NAME + " TEXT," +
COLUMN_CARD_PAY_TYPE + " TEXT," +
COLUMN_CARD_ACCOUNTNUM + " INTEGER," +
COLUMN_CARD_PASSWORDNUM + " INTEGER," +
COLUMN_CARD_CREDIT + " TEXT);");
} catch (SQLException ex) {
Utils.D("couldn't create " + TABLE_CARD + " table in market database");
throw ex;
}
}
}
/* (non-Javadoc)
* @see android.content.ContentProvider#onCreate()
*/
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
return true;
}
/* (non-Javadoc)
* @see android.content.ContentProvider#getType(android.net.Uri)
*/
@Override
public String getType(Uri uri) {
int match = sURIMatcher.match(uri);
switch (match) {
case SEARCH_HISTORY:
return LIST_TYPE + TABLE_SEARCH_HISTORY;
case SEARCH_HISTORY_ID:
return ITEM_TYPE + TABLE_SEARCH_HISTORY;
case PRODUCTS:
return LIST_TYPE + TABLE_PRODUCTS;
case UPDATE_PRODUCT:
return LIST_TYPE + TABLE_UPDATES;
case BUY_PRODUCT:
return LIST_TYPE + TABLE_BUY;
case CARD:
return LIST_TYPE + TABLE_CARD;
default:
break;
}
return null;
}
/* (non-Javadoc)
* @see android.content.ContentProvider#insert(android.net.Uri, android.content.ContentValues)
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
int match = sURIMatcher.match(uri);
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final String table = getTableFromUri(uri);
long rowID = db.insert(table, null, values);
if (rowID == -1) {
Utils.D("couldn't insert into " + table + " database");
return null;
}
Uri inserResult = ContentUris.withAppendedId(uri, rowID);
notifyContentChanged(uri, match);
return inserResult;
}
/* (non-Javadoc)
* @see android.content.ContentProvider#delete(android.net.Uri, java.lang.String, java.lang.String[])
*/
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
int match = sURIMatcher.match(uri);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final String table = getTableFromUri(uri);
SqlSelection selection = getWhereClause(uri, where, whereArgs);
int count = db.delete(table, selection.getSelection(), selection.getParameters());
if (count == 0) {
Utils.D("couldn't delete URI " + uri);
return count;
}
notifyContentChanged(uri, match);
return count;
}
/* (non-Javadoc)
* @see android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[])
*/
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
int match = sURIMatcher.match(uri);
if (match == -1) {
Utils.D("updating unknown URI: " + uri);
throw new IllegalArgumentException("Unknown URI: " + uri);
}
final String table = getTableFromUri(uri);
return db.update(table, values, selection, selectionArgs);
}
/* (non-Javadoc)
* @see android.content.ContentProvider#query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String)
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
int match = sURIMatcher.match(uri);
if (match == -1) {
Utils.D("querying unknown URI: " + uri);
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SqlSelection fullSelection = getWhereClause(uri, selection, selectionArgs);
logVerboseQueryInfo(projection, selection, selectionArgs, sortOrder, db);
final String table = getTableFromUri(uri);
Cursor ret = db.query(table, projection, fullSelection.getSelection(),
fullSelection.getParameters(), null, null, sortOrder);
if (ret == null) {
Utils.D("query failed in market database");
}
return ret;
}
/**
* Notify of a change through both URIs
*/
private void notifyContentChanged(final Uri uri, int uriMatch) {
getContext().getContentResolver().notifyChange(uri, null);
}
// /**
// * 从URI中获取ID
// */
// private static String getIdFromUri(final Uri uri) {
// return uri.getPathSegments().get(1);
// }
/**
* 从URI中获取表名
* @param uri 目标Uri
* @return 操作目标的表名
*/
private static String getTableFromUri(final Uri uri) {
return uri.getPathSegments().get(0);
}
/**
* 获取SQL条件的工具方法
* @param uri Content URI
* @param where 条件
* @param whereArgs 参数
* @param uriMatch 类型
* @return 合成的SqlSelection对象
*/
private static SqlSelection getWhereClause(final Uri uri, final String where,
final String[] whereArgs) {
SqlSelection selection = new SqlSelection();
selection.appendClause(where, whereArgs);
// if (uriMatch == SEARCH_HISTORY_ID) {
// selection.appendClause(COLUMN_ID + " = ?", getIdFromUri(uri));
// } else if(uriMatch == PRODUCTS) {
// selection.appendClause(COLUMN_ID + " = ?", getIdFromUri(uri));
// }
return selection;
}
/**
* 打印 【查询SQL】 详细信息
*/
private static void logVerboseQueryInfo(String[] projection, final String selection,
final String[] selectionArgs, final String sort, SQLiteDatabase db) {
StringBuilder sb = new StringBuilder();
sb.append("starting query, database is ");
if (db != null) {
sb.append("not ");
}
sb.append("null; ");
if (projection == null) {
sb.append("projection is null; ");
} else if (projection.length == 0) {
sb.append("projection is empty; ");
} else {
for (int i = 0; i < projection.length; ++i) {
sb.append("projection[");
sb.append(i);
sb.append("] is ");
sb.append(projection[i]);
sb.append("; ");
}
}
sb.append("selection is ");
sb.append(selection);
sb.append("; ");
if (selectionArgs == null) {
sb.append("selectionArgs is null; ");
} else if (selectionArgs.length == 0) {
sb.append("selectionArgs is empty; ");
} else {
for (int i = 0; i < selectionArgs.length; ++i) {
sb.append("selectionArgs[");
sb.append(i);
sb.append("] is ");
sb.append(selectionArgs[i]);
sb.append("; ");
}
}
sb.append("sort is ");
sb.append(sort);
sb.append(".");
Utils.D(sb.toString());
}
}