401622cc22
-Added new Gradle build system, as it is the required build system
511 lines
18 KiB
Java
Executable file
511 lines
18 KiB
Java
Executable file
/*
|
|
* Copyright (C) 2012 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.google.android.vending.expansion.downloader.impl;
|
|
|
|
import android.content.ContentValues;
|
|
import android.content.Context;
|
|
import android.database.Cursor;
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
import android.database.sqlite.SQLiteDoneException;
|
|
import android.database.sqlite.SQLiteOpenHelper;
|
|
import android.database.sqlite.SQLiteStatement;
|
|
import android.provider.BaseColumns;
|
|
import android.util.Log;
|
|
|
|
public class DownloadsDB {
|
|
private static final String DATABASE_NAME = "DownloadsDB";
|
|
private static final int DATABASE_VERSION = 7;
|
|
public static final String LOG_TAG = DownloadsDB.class.getName();
|
|
final SQLiteOpenHelper mHelper;
|
|
SQLiteStatement mGetDownloadByIndex;
|
|
SQLiteStatement mUpdateCurrentBytes;
|
|
private static DownloadsDB mDownloadsDB;
|
|
long mMetadataRowID = -1;
|
|
int mVersionCode = -1;
|
|
int mStatus = -1;
|
|
int mFlags;
|
|
|
|
static public synchronized DownloadsDB getDB(Context paramContext) {
|
|
if (null == mDownloadsDB) {
|
|
return new DownloadsDB(paramContext);
|
|
}
|
|
return mDownloadsDB;
|
|
}
|
|
|
|
private SQLiteStatement getDownloadByIndexStatement() {
|
|
if (null == mGetDownloadByIndex) {
|
|
mGetDownloadByIndex = mHelper.getReadableDatabase().compileStatement(
|
|
"SELECT " + BaseColumns._ID + " FROM "
|
|
+ DownloadColumns.TABLE_NAME + " WHERE "
|
|
+ DownloadColumns.INDEX + " = ?");
|
|
}
|
|
return mGetDownloadByIndex;
|
|
}
|
|
|
|
private SQLiteStatement getUpdateCurrentBytesStatement() {
|
|
if (null == mUpdateCurrentBytes) {
|
|
mUpdateCurrentBytes = mHelper.getReadableDatabase().compileStatement(
|
|
"UPDATE " + DownloadColumns.TABLE_NAME + " SET " + DownloadColumns.CURRENTBYTES
|
|
+ " = ?" +
|
|
" WHERE " + DownloadColumns.INDEX + " = ?");
|
|
}
|
|
return mUpdateCurrentBytes;
|
|
}
|
|
|
|
private DownloadsDB(Context paramContext) {
|
|
this.mHelper = new DownloadsContentDBHelper(paramContext);
|
|
final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
|
|
// Query for the version code, the row ID of the metadata (for future
|
|
// updating) the status and the flags
|
|
Cursor cur = sqldb.rawQuery("SELECT " +
|
|
MetadataColumns.APKVERSION + "," +
|
|
BaseColumns._ID + "," +
|
|
MetadataColumns.DOWNLOAD_STATUS + "," +
|
|
MetadataColumns.FLAGS +
|
|
" FROM "
|
|
+ MetadataColumns.TABLE_NAME + " LIMIT 1", null);
|
|
if (null != cur && cur.moveToFirst()) {
|
|
mVersionCode = cur.getInt(0);
|
|
mMetadataRowID = cur.getLong(1);
|
|
mStatus = cur.getInt(2);
|
|
mFlags = cur.getInt(3);
|
|
cur.close();
|
|
}
|
|
mDownloadsDB = this;
|
|
}
|
|
|
|
protected DownloadInfo getDownloadInfoByFileName(String fileName) {
|
|
final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
|
|
Cursor itemcur = null;
|
|
try {
|
|
itemcur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION,
|
|
DownloadColumns.FILENAME + " = ?",
|
|
new String[] {
|
|
fileName
|
|
}, null, null, null);
|
|
if (null != itemcur && itemcur.moveToFirst()) {
|
|
return getDownloadInfoFromCursor(itemcur);
|
|
}
|
|
} finally {
|
|
if (null != itemcur)
|
|
itemcur.close();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public long getIDForDownloadInfo(final DownloadInfo di) {
|
|
return getIDByIndex(di.mIndex);
|
|
}
|
|
|
|
public long getIDByIndex(int index) {
|
|
SQLiteStatement downloadByIndex = getDownloadByIndexStatement();
|
|
downloadByIndex.clearBindings();
|
|
downloadByIndex.bindLong(1, index);
|
|
try {
|
|
return downloadByIndex.simpleQueryForLong();
|
|
} catch (SQLiteDoneException e) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public void updateDownloadCurrentBytes(final DownloadInfo di) {
|
|
SQLiteStatement downloadCurrentBytes = getUpdateCurrentBytesStatement();
|
|
downloadCurrentBytes.clearBindings();
|
|
downloadCurrentBytes.bindLong(1, di.mCurrentBytes);
|
|
downloadCurrentBytes.bindLong(2, di.mIndex);
|
|
downloadCurrentBytes.execute();
|
|
}
|
|
|
|
public void close() {
|
|
this.mHelper.close();
|
|
}
|
|
|
|
protected static class DownloadsContentDBHelper extends SQLiteOpenHelper {
|
|
DownloadsContentDBHelper(Context paramContext) {
|
|
super(paramContext, DATABASE_NAME, null, DATABASE_VERSION);
|
|
}
|
|
|
|
private String createTableQueryFromArray(String paramString,
|
|
String[][] paramArrayOfString) {
|
|
StringBuilder localStringBuilder = new StringBuilder();
|
|
localStringBuilder.append("CREATE TABLE ");
|
|
localStringBuilder.append(paramString);
|
|
localStringBuilder.append(" (");
|
|
int i = paramArrayOfString.length;
|
|
for (int j = 0;; j++) {
|
|
if (j >= i) {
|
|
localStringBuilder
|
|
.setLength(localStringBuilder.length() - 1);
|
|
localStringBuilder.append(");");
|
|
return localStringBuilder.toString();
|
|
}
|
|
String[] arrayOfString = paramArrayOfString[j];
|
|
localStringBuilder.append(' ');
|
|
localStringBuilder.append(arrayOfString[0]);
|
|
localStringBuilder.append(' ');
|
|
localStringBuilder.append(arrayOfString[1]);
|
|
localStringBuilder.append(',');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* These two arrays must match and have the same order. For every Schema
|
|
* there must be a corresponding table name.
|
|
*/
|
|
static final private String[][][] sSchemas = {
|
|
DownloadColumns.SCHEMA, MetadataColumns.SCHEMA
|
|
};
|
|
|
|
static final private String[] sTables = {
|
|
DownloadColumns.TABLE_NAME, MetadataColumns.TABLE_NAME
|
|
};
|
|
|
|
/**
|
|
* Goes through all of the tables in sTables and drops each table if it
|
|
* exists. Altered to no longer make use of reflection.
|
|
*/
|
|
private void dropTables(SQLiteDatabase paramSQLiteDatabase) {
|
|
for (String table : sTables) {
|
|
try {
|
|
paramSQLiteDatabase.execSQL("DROP TABLE IF EXISTS " + table);
|
|
} catch (Exception localException) {
|
|
localException.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Goes through all of the tables in sTables and creates a database with
|
|
* the corresponding schema described in sSchemas. Altered to no longer
|
|
* make use of reflection.
|
|
*/
|
|
public void onCreate(SQLiteDatabase paramSQLiteDatabase) {
|
|
int numSchemas = sSchemas.length;
|
|
for (int i = 0; i < numSchemas; i++) {
|
|
try {
|
|
String[][] schema = (String[][]) sSchemas[i];
|
|
paramSQLiteDatabase.execSQL(createTableQueryFromArray(
|
|
sTables[i], schema));
|
|
} catch (Exception localException) {
|
|
while (true)
|
|
localException.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void onUpgrade(SQLiteDatabase paramSQLiteDatabase,
|
|
int paramInt1, int paramInt2) {
|
|
Log.w(DownloadsContentDBHelper.class.getName(),
|
|
"Upgrading database from version " + paramInt1 + " to "
|
|
+ paramInt2 + ", which will destroy all old data");
|
|
dropTables(paramSQLiteDatabase);
|
|
onCreate(paramSQLiteDatabase);
|
|
}
|
|
}
|
|
|
|
public static class MetadataColumns implements BaseColumns {
|
|
public static final String APKVERSION = "APKVERSION";
|
|
public static final String DOWNLOAD_STATUS = "DOWNLOADSTATUS";
|
|
public static final String FLAGS = "DOWNLOADFLAGS";
|
|
|
|
public static final String[][] SCHEMA = {
|
|
{
|
|
BaseColumns._ID, "INTEGER PRIMARY KEY"
|
|
},
|
|
{
|
|
APKVERSION, "INTEGER"
|
|
}, {
|
|
DOWNLOAD_STATUS, "INTEGER"
|
|
},
|
|
{
|
|
FLAGS, "INTEGER"
|
|
}
|
|
};
|
|
public static final String TABLE_NAME = "MetadataColumns";
|
|
public static final String _ID = "MetadataColumns._id";
|
|
}
|
|
|
|
public static class DownloadColumns implements BaseColumns {
|
|
public static final String INDEX = "FILEIDX";
|
|
public static final String URI = "URI";
|
|
public static final String FILENAME = "FN";
|
|
public static final String ETAG = "ETAG";
|
|
|
|
public static final String TOTALBYTES = "TOTALBYTES";
|
|
public static final String CURRENTBYTES = "CURRENTBYTES";
|
|
public static final String LASTMOD = "LASTMOD";
|
|
|
|
public static final String STATUS = "STATUS";
|
|
public static final String CONTROL = "CONTROL";
|
|
public static final String NUM_FAILED = "FAILCOUNT";
|
|
public static final String RETRY_AFTER = "RETRYAFTER";
|
|
public static final String REDIRECT_COUNT = "REDIRECTCOUNT";
|
|
|
|
public static final String[][] SCHEMA = {
|
|
{
|
|
BaseColumns._ID, "INTEGER PRIMARY KEY"
|
|
},
|
|
{
|
|
INDEX, "INTEGER UNIQUE"
|
|
}, {
|
|
URI, "TEXT"
|
|
},
|
|
{
|
|
FILENAME, "TEXT UNIQUE"
|
|
}, {
|
|
ETAG, "TEXT"
|
|
},
|
|
{
|
|
TOTALBYTES, "INTEGER"
|
|
}, {
|
|
CURRENTBYTES, "INTEGER"
|
|
},
|
|
{
|
|
LASTMOD, "INTEGER"
|
|
}, {
|
|
STATUS, "INTEGER"
|
|
},
|
|
{
|
|
CONTROL, "INTEGER"
|
|
}, {
|
|
NUM_FAILED, "INTEGER"
|
|
},
|
|
{
|
|
RETRY_AFTER, "INTEGER"
|
|
}, {
|
|
REDIRECT_COUNT, "INTEGER"
|
|
}
|
|
};
|
|
public static final String TABLE_NAME = "DownloadColumns";
|
|
public static final String _ID = "DownloadColumns._id";
|
|
}
|
|
|
|
private static final String[] DC_PROJECTION = {
|
|
DownloadColumns.FILENAME,
|
|
DownloadColumns.URI, DownloadColumns.ETAG,
|
|
DownloadColumns.TOTALBYTES, DownloadColumns.CURRENTBYTES,
|
|
DownloadColumns.LASTMOD, DownloadColumns.STATUS,
|
|
DownloadColumns.CONTROL, DownloadColumns.NUM_FAILED,
|
|
DownloadColumns.RETRY_AFTER, DownloadColumns.REDIRECT_COUNT,
|
|
DownloadColumns.INDEX
|
|
};
|
|
|
|
private static final int FILENAME_IDX = 0;
|
|
private static final int URI_IDX = 1;
|
|
private static final int ETAG_IDX = 2;
|
|
private static final int TOTALBYTES_IDX = 3;
|
|
private static final int CURRENTBYTES_IDX = 4;
|
|
private static final int LASTMOD_IDX = 5;
|
|
private static final int STATUS_IDX = 6;
|
|
private static final int CONTROL_IDX = 7;
|
|
private static final int NUM_FAILED_IDX = 8;
|
|
private static final int RETRY_AFTER_IDX = 9;
|
|
private static final int REDIRECT_COUNT_IDX = 10;
|
|
private static final int INDEX_IDX = 11;
|
|
|
|
/**
|
|
* This function will add a new file to the database if it does not exist.
|
|
*
|
|
* @param di DownloadInfo that we wish to store
|
|
* @return the row id of the record to be updated/inserted, or -1
|
|
*/
|
|
public boolean updateDownload(DownloadInfo di) {
|
|
ContentValues cv = new ContentValues();
|
|
cv.put(DownloadColumns.INDEX, di.mIndex);
|
|
cv.put(DownloadColumns.FILENAME, di.mFileName);
|
|
cv.put(DownloadColumns.URI, di.mUri);
|
|
cv.put(DownloadColumns.ETAG, di.mETag);
|
|
cv.put(DownloadColumns.TOTALBYTES, di.mTotalBytes);
|
|
cv.put(DownloadColumns.CURRENTBYTES, di.mCurrentBytes);
|
|
cv.put(DownloadColumns.LASTMOD, di.mLastMod);
|
|
cv.put(DownloadColumns.STATUS, di.mStatus);
|
|
cv.put(DownloadColumns.CONTROL, di.mControl);
|
|
cv.put(DownloadColumns.NUM_FAILED, di.mNumFailed);
|
|
cv.put(DownloadColumns.RETRY_AFTER, di.mRetryAfter);
|
|
cv.put(DownloadColumns.REDIRECT_COUNT, di.mRedirectCount);
|
|
return updateDownload(di, cv);
|
|
}
|
|
|
|
public boolean updateDownload(DownloadInfo di, ContentValues cv) {
|
|
long id = di == null ? -1 : getIDForDownloadInfo(di);
|
|
try {
|
|
final SQLiteDatabase sqldb = mHelper.getWritableDatabase();
|
|
if (id != -1) {
|
|
if (1 != sqldb.update(DownloadColumns.TABLE_NAME,
|
|
cv, DownloadColumns._ID + " = " + id, null)) {
|
|
return false;
|
|
}
|
|
} else {
|
|
return -1 != sqldb.insert(DownloadColumns.TABLE_NAME,
|
|
DownloadColumns.URI, cv);
|
|
}
|
|
} catch (android.database.sqlite.SQLiteException ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public int getLastCheckedVersionCode() {
|
|
return mVersionCode;
|
|
}
|
|
|
|
public boolean isDownloadRequired() {
|
|
final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
|
|
Cursor cur = sqldb.rawQuery("SELECT Count(*) FROM "
|
|
+ DownloadColumns.TABLE_NAME + " WHERE "
|
|
+ DownloadColumns.STATUS + " <> 0", null);
|
|
try {
|
|
if (null != cur && cur.moveToFirst()) {
|
|
return 0 == cur.getInt(0);
|
|
}
|
|
} finally {
|
|
if (null != cur)
|
|
cur.close();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public int getFlags() {
|
|
return mFlags;
|
|
}
|
|
|
|
public boolean updateFlags(int flags) {
|
|
if (mFlags != flags) {
|
|
ContentValues cv = new ContentValues();
|
|
cv.put(MetadataColumns.FLAGS, flags);
|
|
if (updateMetadata(cv)) {
|
|
mFlags = flags;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
public boolean updateStatus(int status) {
|
|
if (mStatus != status) {
|
|
ContentValues cv = new ContentValues();
|
|
cv.put(MetadataColumns.DOWNLOAD_STATUS, status);
|
|
if (updateMetadata(cv)) {
|
|
mStatus = status;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
public boolean updateMetadata(ContentValues cv) {
|
|
final SQLiteDatabase sqldb = mHelper.getWritableDatabase();
|
|
if (-1 == this.mMetadataRowID) {
|
|
long newID = sqldb.insert(MetadataColumns.TABLE_NAME,
|
|
MetadataColumns.APKVERSION, cv);
|
|
if (-1 == newID)
|
|
return false;
|
|
mMetadataRowID = newID;
|
|
} else {
|
|
if (0 == sqldb.update(MetadataColumns.TABLE_NAME, cv,
|
|
BaseColumns._ID + " = " + mMetadataRowID, null))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public boolean updateMetadata(int apkVersion, int downloadStatus) {
|
|
ContentValues cv = new ContentValues();
|
|
cv.put(MetadataColumns.APKVERSION, apkVersion);
|
|
cv.put(MetadataColumns.DOWNLOAD_STATUS, downloadStatus);
|
|
if (updateMetadata(cv)) {
|
|
mVersionCode = apkVersion;
|
|
mStatus = downloadStatus;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
public boolean updateFromDb(DownloadInfo di) {
|
|
final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
|
|
Cursor cur = null;
|
|
try {
|
|
cur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION,
|
|
DownloadColumns.FILENAME + "= ?",
|
|
new String[] {
|
|
di.mFileName
|
|
}, null, null, null);
|
|
if (null != cur && cur.moveToFirst()) {
|
|
setDownloadInfoFromCursor(di, cur);
|
|
return true;
|
|
}
|
|
return false;
|
|
} finally {
|
|
if (null != cur) {
|
|
cur.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setDownloadInfoFromCursor(DownloadInfo di, Cursor cur) {
|
|
di.mUri = cur.getString(URI_IDX);
|
|
di.mETag = cur.getString(ETAG_IDX);
|
|
di.mTotalBytes = cur.getLong(TOTALBYTES_IDX);
|
|
di.mCurrentBytes = cur.getLong(CURRENTBYTES_IDX);
|
|
di.mLastMod = cur.getLong(LASTMOD_IDX);
|
|
di.mStatus = cur.getInt(STATUS_IDX);
|
|
di.mControl = cur.getInt(CONTROL_IDX);
|
|
di.mNumFailed = cur.getInt(NUM_FAILED_IDX);
|
|
di.mRetryAfter = cur.getInt(RETRY_AFTER_IDX);
|
|
di.mRedirectCount = cur.getInt(REDIRECT_COUNT_IDX);
|
|
}
|
|
|
|
public DownloadInfo getDownloadInfoFromCursor(Cursor cur) {
|
|
DownloadInfo di = new DownloadInfo(cur.getInt(INDEX_IDX),
|
|
cur.getString(FILENAME_IDX), this.getClass().getPackage()
|
|
.getName());
|
|
setDownloadInfoFromCursor(di, cur);
|
|
return di;
|
|
}
|
|
|
|
public DownloadInfo[] getDownloads() {
|
|
final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
|
|
Cursor cur = null;
|
|
try {
|
|
cur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION, null,
|
|
null, null, null, null);
|
|
if (null != cur && cur.moveToFirst()) {
|
|
DownloadInfo[] retInfos = new DownloadInfo[cur.getCount()];
|
|
int idx = 0;
|
|
do {
|
|
DownloadInfo di = getDownloadInfoFromCursor(cur);
|
|
retInfos[idx++] = di;
|
|
} while (cur.moveToNext());
|
|
return retInfos;
|
|
}
|
|
return null;
|
|
} finally {
|
|
if (null != cur) {
|
|
cur.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|