Initial checkin of AOSP Messaging app.
b/23110861 Change-Id: I9aa980d7569247d6b2ca78f5dcb4502e1eaadb8a
This commit is contained in:
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.messaging.sms;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.provider.Telephony;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.messaging.R;
|
||||
import com.android.messaging.datamodel.data.ParticipantData;
|
||||
import com.android.messaging.util.LogUtil;
|
||||
import com.android.messaging.util.PhoneUtils;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* Database helper class for looking up APNs. This database has a single table
|
||||
* which stores the APNs that are initially created from an xml file.
|
||||
*/
|
||||
public class ApnDatabase extends SQLiteOpenHelper {
|
||||
private static final int DB_VERSION = 3; // added sub_id columns
|
||||
|
||||
private static final String TAG = LogUtil.BUGLE_TAG;
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static Context sContext;
|
||||
private static ApnDatabase sApnDatabase;
|
||||
|
||||
private static final String APN_DATABASE_NAME = "apn.db";
|
||||
|
||||
/** table for carrier APN's */
|
||||
public static final String APN_TABLE = "apn";
|
||||
|
||||
// APN table
|
||||
private static final String APN_TABLE_SQL =
|
||||
"CREATE TABLE " + APN_TABLE +
|
||||
"(_id INTEGER PRIMARY KEY," +
|
||||
Telephony.Carriers.NAME + " TEXT," +
|
||||
Telephony.Carriers.NUMERIC + " TEXT," +
|
||||
Telephony.Carriers.MCC + " TEXT," +
|
||||
Telephony.Carriers.MNC + " TEXT," +
|
||||
Telephony.Carriers.APN + " TEXT," +
|
||||
Telephony.Carriers.USER + " TEXT," +
|
||||
Telephony.Carriers.SERVER + " TEXT," +
|
||||
Telephony.Carriers.PASSWORD + " TEXT," +
|
||||
Telephony.Carriers.PROXY + " TEXT," +
|
||||
Telephony.Carriers.PORT + " TEXT," +
|
||||
Telephony.Carriers.MMSPROXY + " TEXT," +
|
||||
Telephony.Carriers.MMSPORT + " TEXT," +
|
||||
Telephony.Carriers.MMSC + " TEXT," +
|
||||
Telephony.Carriers.AUTH_TYPE + " INTEGER," +
|
||||
Telephony.Carriers.TYPE + " TEXT," +
|
||||
Telephony.Carriers.CURRENT + " INTEGER," +
|
||||
Telephony.Carriers.PROTOCOL + " TEXT," +
|
||||
Telephony.Carriers.ROAMING_PROTOCOL + " TEXT," +
|
||||
Telephony.Carriers.CARRIER_ENABLED + " BOOLEAN," +
|
||||
Telephony.Carriers.BEARER + " INTEGER," +
|
||||
Telephony.Carriers.MVNO_TYPE + " TEXT," +
|
||||
Telephony.Carriers.MVNO_MATCH_DATA + " TEXT," +
|
||||
Telephony.Carriers.SUBSCRIPTION_ID + " INTEGER DEFAULT " +
|
||||
ParticipantData.DEFAULT_SELF_SUB_ID + ");";
|
||||
|
||||
public static final String[] APN_PROJECTION = {
|
||||
Telephony.Carriers.TYPE, // 0
|
||||
Telephony.Carriers.MMSC, // 1
|
||||
Telephony.Carriers.MMSPROXY, // 2
|
||||
Telephony.Carriers.MMSPORT, // 3
|
||||
Telephony.Carriers._ID, // 4
|
||||
Telephony.Carriers.CURRENT, // 5
|
||||
Telephony.Carriers.NUMERIC, // 6
|
||||
Telephony.Carriers.NAME, // 7
|
||||
Telephony.Carriers.MCC, // 8
|
||||
Telephony.Carriers.MNC, // 9
|
||||
Telephony.Carriers.APN, // 10
|
||||
Telephony.Carriers.SUBSCRIPTION_ID // 11
|
||||
};
|
||||
|
||||
public static final int COLUMN_TYPE = 0;
|
||||
public static final int COLUMN_MMSC = 1;
|
||||
public static final int COLUMN_MMSPROXY = 2;
|
||||
public static final int COLUMN_MMSPORT = 3;
|
||||
public static final int COLUMN_ID = 4;
|
||||
public static final int COLUMN_CURRENT = 5;
|
||||
public static final int COLUMN_NUMERIC = 6;
|
||||
public static final int COLUMN_NAME = 7;
|
||||
public static final int COLUMN_MCC = 8;
|
||||
public static final int COLUMN_MNC = 9;
|
||||
public static final int COLUMN_APN = 10;
|
||||
public static final int COLUMN_SUB_ID = 11;
|
||||
|
||||
public static final String[] APN_FULL_PROJECTION = {
|
||||
Telephony.Carriers.NAME,
|
||||
Telephony.Carriers.MCC,
|
||||
Telephony.Carriers.MNC,
|
||||
Telephony.Carriers.APN,
|
||||
Telephony.Carriers.USER,
|
||||
Telephony.Carriers.SERVER,
|
||||
Telephony.Carriers.PASSWORD,
|
||||
Telephony.Carriers.PROXY,
|
||||
Telephony.Carriers.PORT,
|
||||
Telephony.Carriers.MMSC,
|
||||
Telephony.Carriers.MMSPROXY,
|
||||
Telephony.Carriers.MMSPORT,
|
||||
Telephony.Carriers.AUTH_TYPE,
|
||||
Telephony.Carriers.TYPE,
|
||||
Telephony.Carriers.PROTOCOL,
|
||||
Telephony.Carriers.ROAMING_PROTOCOL,
|
||||
Telephony.Carriers.CARRIER_ENABLED,
|
||||
Telephony.Carriers.BEARER,
|
||||
Telephony.Carriers.MVNO_TYPE,
|
||||
Telephony.Carriers.MVNO_MATCH_DATA,
|
||||
Telephony.Carriers.CURRENT,
|
||||
Telephony.Carriers.SUBSCRIPTION_ID,
|
||||
};
|
||||
|
||||
private static final String CURRENT_SELECTION = Telephony.Carriers.CURRENT + " NOT NULL";
|
||||
|
||||
/**
|
||||
* ApnDatabase is initialized asynchronously from the application.onCreate
|
||||
* To ensure that it works in a testing environment it needs to never access the factory context
|
||||
*/
|
||||
public static void initializeAppContext(final Context context) {
|
||||
sContext = context;
|
||||
}
|
||||
|
||||
private ApnDatabase() {
|
||||
super(sContext, APN_DATABASE_NAME, null, DB_VERSION);
|
||||
if (DEBUG) {
|
||||
LogUtil.d(TAG, "ApnDatabase constructor");
|
||||
}
|
||||
}
|
||||
|
||||
public static ApnDatabase getApnDatabase() {
|
||||
if (sApnDatabase == null) {
|
||||
sApnDatabase = new ApnDatabase();
|
||||
}
|
||||
return sApnDatabase;
|
||||
}
|
||||
|
||||
public static boolean doesDatabaseExist() {
|
||||
final File dbFile = sContext.getDatabasePath(APN_DATABASE_NAME);
|
||||
return dbFile.exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final SQLiteDatabase db) {
|
||||
if (DEBUG) {
|
||||
LogUtil.d(TAG, "ApnDatabase onCreate");
|
||||
}
|
||||
// Build the table using defaults (apn info bundled with the app)
|
||||
rebuildTables(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy of user changes in the old table
|
||||
*
|
||||
* @return The list of user changed apns
|
||||
*/
|
||||
public static List<ContentValues> loadUserDataFromOldTable(final SQLiteDatabase db) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = db.query(APN_TABLE,
|
||||
APN_FULL_PROJECTION, CURRENT_SELECTION,
|
||||
null/*selectionArgs*/,
|
||||
null/*groupBy*/, null/*having*/, null/*orderBy*/);
|
||||
if (cursor != null) {
|
||||
final List<ContentValues> result = Lists.newArrayList();
|
||||
while (cursor.moveToNext()) {
|
||||
final ContentValues row = cursorToValues(cursor);
|
||||
if (row != null) {
|
||||
result.add(row);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} catch (final SQLiteException e) {
|
||||
LogUtil.w(TAG, "ApnDatabase.loadUserDataFromOldTable: no old user data: " + e, e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final String[] ID_PROJECTION = new String[]{Telephony.Carriers._ID};
|
||||
|
||||
private static final String ID_SELECTION = Telephony.Carriers._ID + "=?";
|
||||
|
||||
/**
|
||||
* Store use changes of old table into the new apn table
|
||||
*
|
||||
* @param data The user changes
|
||||
*/
|
||||
public static void saveUserDataFromOldTable(
|
||||
final SQLiteDatabase db, final List<ContentValues> data) {
|
||||
if (data == null || data.size() < 1) {
|
||||
return;
|
||||
}
|
||||
for (final ContentValues row : data) {
|
||||
// Build query from the row data. It is an exact match, column by column,
|
||||
// except the CURRENT column
|
||||
final StringBuilder selectionBuilder = new StringBuilder();
|
||||
final ArrayList<String> selectionArgs = Lists.newArrayList();
|
||||
for (final String key : row.keySet()) {
|
||||
if (!Telephony.Carriers.CURRENT.equals(key)) {
|
||||
if (selectionBuilder.length() > 0) {
|
||||
selectionBuilder.append(" AND ");
|
||||
}
|
||||
final String value = row.getAsString(key);
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
selectionBuilder.append(key).append(" IS NULL");
|
||||
} else {
|
||||
selectionBuilder.append(key).append("=?");
|
||||
selectionArgs.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = db.query(APN_TABLE,
|
||||
ID_PROJECTION,
|
||||
selectionBuilder.toString(),
|
||||
selectionArgs.toArray(new String[0]),
|
||||
null/*groupBy*/, null/*having*/, null/*orderBy*/);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
db.update(APN_TABLE, row, ID_SELECTION, new String[]{cursor.getString(0)});
|
||||
} else {
|
||||
// User APN does not exist, insert into the new table
|
||||
row.put(Telephony.Carriers.NUMERIC,
|
||||
PhoneUtils.canonicalizeMccMnc(
|
||||
row.getAsString(Telephony.Carriers.MCC),
|
||||
row.getAsString(Telephony.Carriers.MNC))
|
||||
);
|
||||
db.insert(APN_TABLE, null/*nullColumnHack*/, row);
|
||||
}
|
||||
} catch (final SQLiteException e) {
|
||||
LogUtil.e(TAG, "ApnDatabase.saveUserDataFromOldTable: query error " + e, e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert Cursor to ContentValues
|
||||
private static ContentValues cursorToValues(final Cursor cursor) {
|
||||
final int columnCount = cursor.getColumnCount();
|
||||
if (columnCount > 0) {
|
||||
final ContentValues result = new ContentValues();
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
final String name = cursor.getColumnName(i);
|
||||
final String value = cursor.getString(i);
|
||||
result.put(name, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(final SQLiteDatabase db) {
|
||||
super.onOpen(db);
|
||||
if (DEBUG) {
|
||||
LogUtil.d(TAG, "ApnDatabase onOpen");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
if (DEBUG) {
|
||||
LogUtil.d(TAG, "ApnDatabase close");
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuildTables(final SQLiteDatabase db) {
|
||||
if (DEBUG) {
|
||||
LogUtil.d(TAG, "ApnDatabase rebuildTables");
|
||||
}
|
||||
db.execSQL("DROP TABLE IF EXISTS " + APN_TABLE + ";");
|
||||
db.execSQL(APN_TABLE_SQL);
|
||||
loadApnTable(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
if (DEBUG) {
|
||||
LogUtil.d(TAG, "ApnDatabase onUpgrade");
|
||||
}
|
||||
rebuildTables(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
if (DEBUG) {
|
||||
LogUtil.d(TAG, "ApnDatabase onDowngrade");
|
||||
}
|
||||
rebuildTables(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load APN table from app resources
|
||||
*/
|
||||
private static void loadApnTable(final SQLiteDatabase db) {
|
||||
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
|
||||
LogUtil.v(TAG, "ApnDatabase loadApnTable");
|
||||
}
|
||||
final Resources r = sContext.getResources();
|
||||
final XmlResourceParser parser = r.getXml(R.xml.apns);
|
||||
final ApnsXmlProcessor processor = ApnsXmlProcessor.get(parser);
|
||||
processor.setApnHandler(new ApnsXmlProcessor.ApnHandler() {
|
||||
@Override
|
||||
public void process(final ContentValues apnValues) {
|
||||
db.insert(APN_TABLE, null/*nullColumnHack*/, apnValues);
|
||||
}
|
||||
});
|
||||
try {
|
||||
processor.process();
|
||||
} catch (final Exception e) {
|
||||
Log.e(TAG, "Got exception while loading APN database.", e);
|
||||
} finally {
|
||||
parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void forceBuildAndLoadApnTables() {
|
||||
final SQLiteDatabase db = getApnDatabase().getWritableDatabase();
|
||||
db.execSQL("DROP TABLE IF EXISTS " + APN_TABLE);
|
||||
// Table(s) always need for JB MR1 for APN support for MMS because JB MR1 throws
|
||||
// a SecurityException when trying to access the carriers table (which holds the
|
||||
// APNs). Some JB MR2 devices also throw the security exception, so we're building
|
||||
// the table for JB MR2, too.
|
||||
db.execSQL(APN_TABLE_SQL);
|
||||
|
||||
loadApnTable(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all tables
|
||||
*/
|
||||
public static void clearTables() {
|
||||
final SQLiteDatabase db = getApnDatabase().getWritableDatabase();
|
||||
db.execSQL("DROP TABLE IF EXISTS " + APN_TABLE);
|
||||
db.execSQL(APN_TABLE_SQL);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user