Merge "Add assets/carrier_list.pb in TelephonyProvider"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 224fe2f..38f9fc0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
<protected-broadcast android:name="android.provider.action.EXTERNAL_PROVIDER_CHANGE" />
<protected-broadcast android:name="android.intent.action.CONTENT_CHANGED" />
diff --git a/src/com/android/providers/telephony/CarrierIdProvider.java b/src/com/android/providers/telephony/CarrierIdProvider.java
index 91fdf21..7acea68 100644
--- a/src/com/android/providers/telephony/CarrierIdProvider.java
+++ b/src/com/android/providers/telephony/CarrierIdProvider.java
@@ -21,13 +21,13 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
-import android.os.FileUtils;
-import android.os.UserHandle;
+import android.os.Environment;
import android.provider.Telephony.CarrierIdentification;
import android.text.TextUtils;
import android.util.Log;
@@ -38,11 +38,8 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -73,9 +70,13 @@
private static final int DATABASE_VERSION = 3;
private static final String ASSETS_PB_FILE = "carrier_list.pb";
- private static final String ASSETS_FILE_CHECKSUM_PREF_KEY = "assets_checksum";
+ private static final String VERSION_PREF_KEY = "version";
+ private static final String OTA_UPDATED_PB_PATH = "misc/carrierid/" + ASSETS_PB_FILE;
private static final String PREF_FILE = CarrierIdProvider.class.getSimpleName();
+ private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ private static final int URL_UPDATE_FROM_PB = 1;
+
/**
* index 0: {@link CarrierIdentification#MCCMNC}
*/
@@ -160,7 +161,8 @@
Log.d(TAG, "onCreate");
mDbHelper = new CarrierIdDatabaseHelper(getContext());
mDbHelper.getReadableDatabase();
- updateFromAssetsIfNeeded(mDbHelper.getWritableDatabase());
+ s_urlMatcher.addURI(AUTHORITY, "update_db", URL_UPDATE_FROM_PB);
+ initDatabaseFromPb(mDbHelper.getWritableDatabase());
return true;
}
@@ -224,13 +226,21 @@
+ " selection=" + selection
+ " selectionArgs=" + Arrays.toString(selectionArgs));
}
- final int count = getWritableDatabase().update(CARRIER_ID_TABLE, values, selection,
- selectionArgs);
- Log.d(TAG, " update.count=" + count);
- if (count > 0) {
- getContext().getContentResolver().notifyChange(CarrierIdentification.CONTENT_URI, null);
+
+ final int match = s_urlMatcher.match(uri);
+ switch (match) {
+ case URL_UPDATE_FROM_PB:
+ return initDatabaseFromPb(getWritableDatabase());
+ default:
+ final int count = getWritableDatabase().update(CARRIER_ID_TABLE, values, selection,
+ selectionArgs);
+ Log.d(TAG, " update.count=" + count);
+ if (count > 0) {
+ getContext().getContentResolver().notifyChange(
+ CarrierIdentification.CONTENT_URI, null);
+ }
+ return count;
}
- return count;
}
/**
@@ -282,74 +292,40 @@
}
/**
- * use check sum to detect assets file update.
- * update database with data from assets only if checksum has been changed
- * and OTA update is unavailable.
+ * Parse and persist pb file as database default values.
+ * Use version number to detect file update.
+ * Update database with data from assets or ota only if version jumps.
*/
- private void updateFromAssetsIfNeeded(SQLiteDatabase db) {
- //TODO skip update from assets if OTA update is available.
- final File assets;
- OutputStream outputStream = null;
- InputStream inputStream = null;
- try {
- // create a temp file to compute check sum.
- assets = new File(getContext().getCacheDir(), ASSETS_PB_FILE);
- outputStream = new FileOutputStream(assets);
- inputStream = getContext().getAssets().open(ASSETS_PB_FILE);
- outputStream.write(readInputStreamToByteArray(inputStream));
- } catch (IOException ex) {
- Log.e(TAG, "assets file not found: " + ex);
- return;
- } finally {
- IoUtils.closeQuietly(outputStream);
- IoUtils.closeQuietly(inputStream);
- }
- long checkSum = getChecksum(assets);
- if (checkSum != getAssetsChecksum()) {
- initDatabaseFromPb(assets, db);
- setAssetsChecksum(checkSum);
- }
- }
-
- /**
- * parse and persist pb file as database default values.
- */
- private void initDatabaseFromPb(File pb, SQLiteDatabase db) {
+ private int initDatabaseFromPb(SQLiteDatabase db) {
Log.d(TAG, "init database from pb file");
- InputStream inputStream = null;
- try {
- inputStream = new FileInputStream(pb);
- byte[] bytes = readInputStreamToByteArray(inputStream);
- CarrierIdProto.CarrierList carrierList = CarrierIdProto.CarrierList.parseFrom(bytes);
- List<ContentValues> cvs = new ArrayList<>();
- for (CarrierIdProto.CarrierId id : carrierList.carrierId) {
- for (CarrierIdProto.CarrierAttribute attr: id.carrierAttribute) {
- ContentValues cv = new ContentValues();
- cv.put(CarrierIdentification.CID, id.canonicalId);
- cv.put(CarrierIdentification.NAME, id.carrierName);
- convertCarrierAttrToContentValues(cv, cvs, attr, 0);
- }
+ int rows = 0;
+ CarrierIdProto.CarrierList carrierList = getUpdateCarrierList();
+ if (carrierList == null) return rows;
+ setAppliedVersion(carrierList.version);
+ List<ContentValues> cvs = new ArrayList<>();
+ for (CarrierIdProto.CarrierId id : carrierList.carrierId) {
+ for (CarrierIdProto.CarrierAttribute attr : id.carrierAttribute) {
+ ContentValues cv = new ContentValues();
+ cv.put(CarrierIdentification.CID, id.canonicalId);
+ cv.put(CarrierIdentification.NAME, id.carrierName);
+ convertCarrierAttrToContentValues(cv, cvs, attr, 0);
}
- db.delete(CARRIER_ID_TABLE, null, null);
- int rows = 0;
- for (ContentValues cv : cvs) {
- if (db.insertOrThrow(CARRIER_ID_TABLE, null, cv) > 0) rows++;
- }
- Log.d(TAG, "init database from pb. inserted rows = " + rows);
- if (rows > 0) {
- // Notify listener of DB change
- getContext().getContentResolver().notifyChange(CarrierIdentification.CONTENT_URI,
- null);
- }
- } catch (IOException ex) {
- Log.e(TAG, "init database from pb failure: " + ex);
- } finally {
- IoUtils.closeQuietly(inputStream);
}
+ db.delete(CARRIER_ID_TABLE, null, null);
+ for (ContentValues cv : cvs) {
+ if (db.insertOrThrow(CARRIER_ID_TABLE, null, cv) > 0) rows++;
+ }
+ Log.d(TAG, "init database from pb. inserted rows = " + rows);
+ if (rows > 0) {
+ // Notify listener of DB change
+ getContext().getContentResolver().notifyChange(CarrierIdentification.CONTENT_URI,
+ null);
+ }
+ return rows;
}
/**
- * recursively loop through carrier attribute list to get all combinations.
+ * Recursively loop through carrier attribute list to get all combinations.
*/
private void convertCarrierAttrToContentValues(ContentValues cv, List<ContentValues> cvs,
CarrierIdProto.CarrierAttribute attr, int index) {
@@ -358,7 +334,7 @@
return;
}
boolean found = false;
- switch(index) {
+ switch (index) {
case MCCMNC_INDEX:
for (String str : attr.mccmncTuple) {
cv.put(CarrierIdentification.MCCMNC, str);
@@ -417,10 +393,10 @@
break;
case ICCID_PREFIX_INDEX:
for (String str : attr.iccidPrefix) {
- cv.put(CarrierIdentification.ICCID_PREFIX, str);
- convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
- cv.remove(CarrierIdentification.ICCID_PREFIX);
- found = true;
+ cv.put(CarrierIdentification.ICCID_PREFIX, str);
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ cv.remove(CarrierIdentification.ICCID_PREFIX);
+ found = true;
}
break;
default:
@@ -434,7 +410,62 @@
}
/**
- * util function to convert inputStream to byte array before parsing proto data.
+ * Return the update carrierList.
+ * Get the latest version from the last applied, assets and ota file. if the latest version
+ * is newer than the last applied, update is required. Otherwise no update is required and
+ * the returned carrierList will be null.
+ */
+ private CarrierIdProto.CarrierList getUpdateCarrierList() {
+ int version = getAppliedVersion();
+ CarrierIdProto.CarrierList carrierList = null;
+ CarrierIdProto.CarrierList assets = null;
+ CarrierIdProto.CarrierList ota = null;
+ InputStream is = null;
+
+ try {
+ is = getContext().getAssets().open(ASSETS_PB_FILE);
+ assets = CarrierIdProto.CarrierList.parseFrom(readInputStreamToByteArray(is));
+ } catch (IOException ex) {
+ Log.e(TAG, "read carrier list from assets pb failure: " + ex);
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ try {
+ is = new FileInputStream(new File(Environment.getDataDirectory(), OTA_UPDATED_PB_PATH));
+ ota = CarrierIdProto.CarrierList.parseFrom(readInputStreamToByteArray(is));
+ } catch (IOException ex) {
+ Log.e(TAG, "read carrier list from ota pb failure: " + ex);
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+
+ // compare version
+ if (assets != null && assets.version > version) {
+ carrierList = assets;
+ version = assets.version;
+ }
+ if (ota != null && ota.version > version) {
+ carrierList = ota;
+ version = ota.version;
+ }
+ Log.d(TAG, "latest version: " + version + " need update: " + (carrierList != null));
+ return carrierList;
+ }
+
+ private int getAppliedVersion() {
+ final SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
+ return sp.getInt(VERSION_PREF_KEY, -1);
+ }
+
+ private void setAppliedVersion(int version) {
+ final SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putInt(VERSION_PREF_KEY, version);
+ editor.apply();
+ }
+
+ /**
+ * Util function to convert inputStream to byte array before parsing proto data.
*/
private static byte[] readInputStreamToByteArray(InputStream inputStream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
@@ -447,32 +478,4 @@
buffer.flush();
return buffer.toByteArray();
}
-
- /**
- * util function to calculate checksum of a file
- */
- private long getChecksum(File file) {
- long checksum = -1;
- try {
- checksum = FileUtils.checksumCrc32(file);
- if (VDBG) Log.d(TAG, "Checksum for " + file.getAbsolutePath() + " is " + checksum);
- } catch (FileNotFoundException e) {
- Log.e(TAG, "FileNotFoundException for " + file.getAbsolutePath() + ":" + e);
- } catch (IOException e) {
- Log.e(TAG, "IOException for " + file.getAbsolutePath() + ":" + e);
- }
- return checksum;
- }
-
- private long getAssetsChecksum() {
- SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
- return sp.getLong(ASSETS_FILE_CHECKSUM_PREF_KEY, -1);
- }
-
- private void setAssetsChecksum(long checksum) {
- SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sp.edit();
- editor.putLong(ASSETS_FILE_CHECKSUM_PREF_KEY, checksum);
- editor.apply();
- }
}
\ No newline at end of file
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 9b893fe..cce9607 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -40,6 +40,7 @@
import static android.provider.Telephony.Carriers.MVNO_MATCH_DATA;
import static android.provider.Telephony.Carriers.MVNO_TYPE;
import static android.provider.Telephony.Carriers.NAME;
+import static android.provider.Telephony.Carriers.NETWORK_TYPE_BITMASK;
import static android.provider.Telephony.Carriers.NUMERIC;
import static android.provider.Telephony.Carriers.OWNED_BY;
import static android.provider.Telephony.Carriers.OWNED_BY_OTHERS;
@@ -126,7 +127,7 @@
private static final boolean DBG = true;
private static final boolean VDBG = false; // STOPSHIP if true
- private static final int DATABASE_VERSION = 23 << 16;
+ private static final int DATABASE_VERSION = 24 << 16;
private static final int URL_UNKNOWN = 0;
private static final int URL_TELEPHONY = 1;
private static final int URL_CURRENT = 2;
@@ -220,7 +221,7 @@
static {
// Columns not included in UNIQUE constraint: name, current, edited, user, server, password,
// authtype, type, protocol, roaming_protocol, sub_id, modem_cognitive, max_conns,
- // wait_time, max_conns_time, mtu, bearer_bitmask, user_visible
+ // wait_time, max_conns_time, mtu, bearer_bitmask, user_visible, network_type_bitmask
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(NUMERIC, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MCC, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MNC, "");
@@ -268,6 +269,7 @@
CARRIER_ENABLED + " BOOLEAN DEFAULT 1," +
BEARER + " INTEGER DEFAULT 0," +
BEARER_BITMASK + " INTEGER DEFAULT 0," +
+ NETWORK_TYPE_BITMASK + " INTEGER DEFAULT 0," +
MVNO_TYPE + " TEXT DEFAULT ''," +
MVNO_MATCH_DATA + " TEXT DEFAULT ''," +
SUBSCRIPTION_ID + " INTEGER DEFAULT "
@@ -286,7 +288,8 @@
// here it means we will accept both (user edited + new apn_conf definition)
// Columns not included in UNIQUE constraint: name, current, edited,
// user, server, password, authtype, type, sub_id, modem_cognitive, max_conns,
- // wait_time, max_conns_time, mtu, bearer_bitmask, user_visible.
+ // wait_time, max_conns_time, mtu, bearer_bitmask, user_visible,
+ // network_type_bitmask.
"UNIQUE (" + TextUtils.join(", ", CARRIERS_UNIQUE_FIELDS) + "));";
}
@@ -880,52 +883,9 @@
oldVersion = 18 << 16 | 6;
}
if (oldVersion < (19 << 16 | 6)) {
- // Upgrade steps from version 18 are:
- // 1. Create a temp table- done in createCarriersTable()
- // 2. copy over APNs from old table to new table - done in copyDataToTmpTable()
- // 3. Drop the existing table.
- // 4. Copy over the tmp table.
- Cursor c;
- String[] proj = {"_id"};
- if (VDBG) {
- c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
- log("dbh.onUpgrade:- before upgrading total number of rows: " + c.getCount());
- c.close();
- }
-
- c = db.query(CARRIERS_TABLE, null, null, null, null, null, null);
-
- if (VDBG) {
- log("dbh.onUpgrade:- starting data copy of existing rows: " +
- + ((c == null) ? 0 : c.getCount()));
- }
-
- db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE_TMP);
-
- createCarriersTable(db, CARRIERS_TABLE_TMP);
-
- copyDataToTmpTable(db, c);
- c.close();
-
- db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE);
-
- db.execSQL("ALTER TABLE " + CARRIERS_TABLE_TMP + " rename to " + CARRIERS_TABLE +
- ";");
-
- if (VDBG) {
- c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
- log("dbh.onUpgrade:- after upgrading total number of rows: " + c.getCount());
- c.close();
- c = db.query(CARRIERS_TABLE, proj, IS_UNEDITED, null, null, null, null);
- log("dbh.onUpgrade:- after upgrading total number of rows with " + IS_UNEDITED +
- ": " + c.getCount());
- c.close();
- c = db.query(CARRIERS_TABLE, proj, IS_EDITED, null, null, null, null);
- log("dbh.onUpgrade:- after upgrading total number of rows with " + IS_EDITED +
- ": " + c.getCount());
- c.close();
- }
- oldVersion = 19 << 16 | 6;
+ // Do nothing. This is to avoid recreating table twice. Table is anyway recreated
+ // for version 24 and that takes care of updates for this version as well.
+ // This version added more fields protocol and roaming protocol to the primary key.
}
if (oldVersion < (20 << 16 | 6)) {
try {
@@ -995,11 +955,57 @@
}
oldVersion = 23 << 16 | 6;
}
+ if (oldVersion < (24 << 16 | 6)) {
+ Cursor c = null;
+ String[] proj = {"_id"};
+ recreateDB(c, db, proj, /* version */24);
+ if (VDBG) {
+ c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
+ log("dbh.onUpgrade:- after upgrading total number of rows: " + c.getCount());
+ c.close();
+ c = db.query(CARRIERS_TABLE, proj, NETWORK_TYPE_BITMASK, null, null, null, null);
+ log("dbh.onUpgrade:- after upgrading total number of rows with "
+ + NETWORK_TYPE_BITMASK + ": " + c.getCount());
+ c.close();
+ }
+ oldVersion = 24 << 16 | 6;
+ }
if (DBG) {
log("dbh.onUpgrade:- db=" + db + " oldV=" + oldVersion + " newV=" + newVersion);
}
}
+ private void recreateDB(Cursor c, SQLiteDatabase db, String[] proj, int version) {
+ // Upgrade steps are:
+ // 1. Create a temp table- done in createCarriersTable()
+ // 2. copy over APNs from old table to new table - done in copyDataToTmpTable()
+ // 3. Drop the existing table.
+ // 4. Copy over the tmp table.
+ if (VDBG) {
+ c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
+ log("dbh.onUpgrade:- before upgrading total number of rows: " + c.getCount());
+ c.close();
+ }
+
+ c = db.query(CARRIERS_TABLE, null, null, null, null, null, null);
+
+ if (VDBG) {
+ log("dbh.onUpgrade:- starting data copy of existing rows: " +
+ + ((c == null) ? 0 : c.getCount()));
+ }
+
+ db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE_TMP);
+
+ createCarriersTable(db, CARRIERS_TABLE_TMP);
+
+ copyDataToTmpTable(db, c);
+ c.close();
+
+ db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE);
+
+ db.execSQL("ALTER TABLE " + CARRIERS_TABLE_TMP + " rename to " + CARRIERS_TABLE + ";");
+ }
+
private void preserveUserAndCarrierApns(SQLiteDatabase db) {
if (VDBG) log("preserveUserAndCarrierApns");
XmlPullParser confparser;
@@ -1194,6 +1200,8 @@
while (c.moveToNext()) {
ContentValues cv = new ContentValues();
copyApnValuesV17(cv, c);
+ // Sync bearer bitmask and network type bitmask
+ getNetworkTypeBitmaskFromCursor(cv, c);
try {
db.insertWithOnConflict(CARRIERS_TABLE_TMP, null, cv,
SQLiteDatabase.CONFLICT_ABORT);
@@ -1270,6 +1278,11 @@
int bearer_bitmask = ServiceState.getBitmaskForTech(
Integer.parseInt(bearerStr));
cv.put(BEARER_BITMASK, bearer_bitmask);
+
+ int networkTypeBitmask = ServiceState.getBitmaskForTech(
+ ServiceState.rilRadioTechnologyToNetworkType(
+ Integer.parseInt(bearerStr)));
+ cv.put(NETWORK_TYPE_BITMASK, networkTypeBitmask);
}
int userEditedColumnIdx = c.getColumnIndex("user_edited");
@@ -1339,6 +1352,37 @@
}
}
+ /**
+ * If NETWORK_TYPE_BITMASK does not exist (upgrade from version 23 to version 24), generate
+ * NETWORK_TYPE_BITMASK with the use of BEARER_BITMASK. If NETWORK_TYPE_BITMASK existed
+ * (upgrade from version 24 to forward), always map NETWORK_TYPE_BITMASK to BEARER_BITMASK.
+ */
+ private void getNetworkTypeBitmaskFromCursor(ContentValues cv, Cursor c) {
+ int columnIndex = c.getColumnIndex(NETWORK_TYPE_BITMASK);
+ if (columnIndex != -1) {
+ getStringValueFromCursor(cv, c, NETWORK_TYPE_BITMASK);
+ // Map NETWORK_TYPE_BITMASK to BEARER_BITMASK if NETWORK_TYPE_BITMASK existed;
+ String fromCursor = c.getString(columnIndex);
+ if (!TextUtils.isEmpty(fromCursor) && fromCursor.matches("\\d+")) {
+ int networkBitmask = Integer.valueOf(fromCursor);
+ int bearerBitmask = ServiceState.convertNetworkTypeBitmaskToBearerBitmask(
+ networkBitmask);
+ cv.put(BEARER_BITMASK, String.valueOf(bearerBitmask));
+ }
+ return;
+ }
+ columnIndex = c.getColumnIndex(BEARER_BITMASK);
+ if (columnIndex != -1) {
+ String fromCursor = c.getString(columnIndex);
+ if (!TextUtils.isEmpty(fromCursor) && fromCursor.matches("\\d+")) {
+ int bearerBitmask = Integer.valueOf(fromCursor);
+ int networkBitmask = ServiceState.convertBearerBitmaskToNetworkTypeBitmask(
+ bearerBitmask);
+ cv.put(NETWORK_TYPE_BITMASK, String.valueOf(networkBitmask));
+ }
+ }
+ }
+
private void getIntValueFromCursor(ContentValues cv, Cursor c, String key) {
int columnIndex = c.getColumnIndex(key);
if (columnIndex != -1) {
@@ -1410,10 +1454,26 @@
addBoolAttribute(parser, "user_visible", map, USER_VISIBLE);
addBoolAttribute(parser, "user_editable", map, USER_EDITABLE);
+ int networkTypeBitmask = 0;
+ String networkTypeList = parser.getAttributeValue(null, "network_type_bitmask");
+ if (networkTypeList != null) {
+ networkTypeBitmask = ServiceState.getBitmaskFromString(networkTypeList);
+ }
+ map.put(NETWORK_TYPE_BITMASK, networkTypeBitmask);
+
int bearerBitmask = 0;
- String bearerList = parser.getAttributeValue(null, "bearer_bitmask");
- if (bearerList != null) {
- bearerBitmask = ServiceState.getBitmaskFromString(bearerList);
+ if (networkTypeList != null) {
+ bearerBitmask =
+ ServiceState.convertNetworkTypeBitmaskToBearerBitmask(networkTypeBitmask);
+ } else {
+ String bearerList = parser.getAttributeValue(null, "bearer_bitmask");
+ if (bearerList != null) {
+ bearerBitmask = ServiceState.getBitmaskFromString(bearerList);
+ }
+ // Update the network type bitmask to keep them sync.
+ networkTypeBitmask = ServiceState.convertBearerBitmaskToNetworkTypeBitmask(
+ bearerBitmask);
+ map.put(NETWORK_TYPE_BITMASK, networkTypeBitmask);
}
map.put(BEARER_BITMASK, bearerBitmask);
@@ -1556,10 +1616,10 @@
if (VDBG) {
log("mergeFieldsAndUpdateDb: Calling separateRowsNeeded() oldType=" +
oldType + " old bearer=" + oldRow.getInt(oldRow.getColumnIndex(
- BEARER_BITMASK)) +
+ BEARER_BITMASK)) + " old networkType=" +
+ oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK)) +
" old profile_id=" + oldRow.getInt(oldRow.getColumnIndex(
- PROFILE_ID)) +
- " newRow " + newRow);
+ PROFILE_ID)) + " newRow " + newRow);
}
// If separate rows are needed, do not need to merge any further
@@ -1585,8 +1645,7 @@
newRow.put(TYPE, mergedType.toString());
}
}
- mergedValues.put(TYPE, newRow.getAsString(
- TYPE));
+ mergedValues.put(TYPE, newRow.getAsString(TYPE));
}
if (newRow.containsKey(BEARER_BITMASK)) {
@@ -1602,7 +1661,38 @@
mergedValues.put(BEARER_BITMASK, newRow.getAsInteger(BEARER_BITMASK));
}
+ if (newRow.containsKey(NETWORK_TYPE_BITMASK)) {
+ int oldBitmask = oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK));
+ int newBitmask = newRow.getAsInteger(NETWORK_TYPE_BITMASK);
+ if (oldBitmask != newBitmask) {
+ if (oldBitmask == 0 || newBitmask == 0) {
+ newRow.put(NETWORK_TYPE_BITMASK, 0);
+ } else {
+ newRow.put(NETWORK_TYPE_BITMASK, (oldBitmask | newBitmask));
+ }
+ }
+ mergedValues.put(NETWORK_TYPE_BITMASK, newRow.getAsInteger(NETWORK_TYPE_BITMASK));
+ }
+
+ if (newRow.containsKey(BEARER_BITMASK)
+ && newRow.containsKey(NETWORK_TYPE_BITMASK)) {
+ syncBearerBitmaskAndNetworkTypeBitmask(mergedValues);
+ }
+
if (!onUpgrade) {
+ // Do not overwrite a carrier or user edit with EDITED=UNEDITED
+ if (newRow.containsKey(EDITED)) {
+ int oldEdited = oldRow.getInt(oldRow.getColumnIndex(EDITED));
+ int newEdited = newRow.getAsInteger(EDITED);
+ if (newEdited == UNEDITED && (oldEdited == CARRIER_EDITED
+ || oldEdited == CARRIER_DELETED
+ || oldEdited == CARRIER_DELETED_BUT_PRESENT_IN_XML
+ || oldEdited == USER_EDITED
+ || oldEdited == USER_DELETED
+ || oldEdited == USER_DELETED_BUT_PRESENT_IN_XML)) {
+ newRow.remove(EDITED);
+ }
+ }
mergedValues.putAll(newRow);
}
@@ -1719,6 +1809,7 @@
TYPE,
EDITED,
BEARER_BITMASK,
+ NETWORK_TYPE_BITMASK,
PROFILE_ID };
String selection = TextUtils.join("=? AND ", CARRIERS_UNIQUE_FIELDS) + "=?";
int i = 0;
@@ -2352,6 +2443,7 @@
int subId = SubscriptionManager.getDefaultSubscriptionId();
checkPermission();
+ syncBearerBitmaskAndNetworkTypeBitmask(initialValues);
boolean notify = false;
SQLiteDatabase db = getWritableDatabase();
@@ -2656,6 +2748,7 @@
int subId = SubscriptionManager.getDefaultSubscriptionId();
checkPermission();
+ syncBearerBitmaskAndNetworkTypeBitmask(values);
SQLiteDatabase db = getWritableDatabase();
int match = s_urlMatcher.match(url);
@@ -2911,6 +3004,31 @@
}
/**
+ * Sync the bearer bitmask and network type bitmask when inserting and updating.
+ * Since bearerBitmask is deprecating, map the networkTypeBitmask to bearerBitmask if
+ * networkTypeBitmask was provided. But if networkTypeBitmask was not provided, map the
+ * bearerBitmask to networkTypeBitmask.
+ */
+ private static void syncBearerBitmaskAndNetworkTypeBitmask(ContentValues values) {
+ if (values.containsKey(NETWORK_TYPE_BITMASK)) {
+ int convertedBitmask = ServiceState.convertNetworkTypeBitmaskToBearerBitmask(
+ values.getAsInteger(NETWORK_TYPE_BITMASK));
+ if (values.containsKey(BEARER_BITMASK)
+ && convertedBitmask != values.getAsInteger(BEARER_BITMASK)) {
+ loge("Network type bitmask and bearer bitmask are not compatible.");
+ }
+ values.put(BEARER_BITMASK, ServiceState.convertNetworkTypeBitmaskToBearerBitmask(
+ values.getAsInteger(NETWORK_TYPE_BITMASK)));
+ } else {
+ if (values.containsKey(BEARER_BITMASK)) {
+ int convertedBitmask = ServiceState.convertBearerBitmaskToNetworkTypeBitmask(
+ values.getAsInteger(BEARER_BITMASK));
+ values.put(NETWORK_TYPE_BITMASK, convertedBitmask);
+ }
+ }
+ }
+
+ /**
* Log with debug
*
* @param s is string log
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index b935a31..7fd7f61 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -815,4 +815,133 @@
// Should catch SecurityException.
}
}
+
+ /**
+ * Verify that user/carrier edited/deleted APNs have priority in the EDITED field over
+ * insertions which set EDITED=UNEDITED. In these cases instead of merging the APNs using the
+ * new APN's value we keep the old value.
+ */
+ @Test
+ @SmallTest
+ public void testPreserveEdited() {
+ preserveEditedValueInMerge(Carriers.USER_EDITED);
+ }
+
+ @Test
+ @SmallTest
+ public void testPreserveUserDeleted() {
+ preserveDeletedValueInMerge(Carriers.USER_DELETED);
+ }
+
+ @Test
+ @SmallTest
+ public void testPreserveUserDeletedButPresentInXml() {
+ preserveDeletedValueInMerge(Carriers.USER_DELETED_BUT_PRESENT_IN_XML);
+ }
+
+ @Test
+ @SmallTest
+ public void testPreserveCarrierEdited() {
+ preserveEditedValueInMerge(Carriers.CARRIER_EDITED);
+ }
+
+ @Test
+ @SmallTest
+ public void testPreserveCarrierDeleted() {
+ preserveDeletedValueInMerge(Carriers.CARRIER_DELETED);
+ }
+
+ @Test
+ @SmallTest
+ public void testPreserveCarrierDeletedButPresentInXml() {
+ preserveDeletedValueInMerge(Carriers.CARRIER_DELETED_BUT_PRESENT_IN_XML);
+ }
+
+ private void preserveEditedValueInMerge(int value) {
+ // insert user deleted APN
+ String carrierName1 = "carrier1";
+ String numeric1 = "123234";
+ String mcc1 = "123";
+ String mnc1 = "234";
+ ContentValues editedValue = new ContentValues();
+ editedValue.put(Carriers.NAME, carrierName1);
+ editedValue.put(Carriers.NUMERIC, numeric1);
+ editedValue.put(Carriers.MCC, mcc1);
+ editedValue.put(Carriers.MNC, mnc1);
+ editedValue.put(Carriers.EDITED, value);
+ assertNotNull(mContentResolver.insert(URI_TELEPHONY, editedValue));
+
+ Cursor cur = mContentResolver.query(URI_TELEPHONY, null, null, null, null);
+ assertEquals(1, cur.getCount());
+
+ // insert APN that conflicts with edited APN
+ String carrierName2 = "carrier2";
+ ContentValues values = new ContentValues();
+ values.put(Carriers.NAME, carrierName2);
+ values.put(Carriers.NUMERIC, numeric1);
+ values.put(Carriers.MCC, mcc1);
+ values.put(Carriers.MNC, mnc1);
+ values.put(Carriers.EDITED, Carriers.UNEDITED);
+ mContentResolver.insert(URI_TELEPHONY, values);
+
+ String[] testProjection = {
+ Carriers.NAME,
+ Carriers.APN,
+ Carriers.EDITED,
+ Carriers.TYPE,
+ Carriers.PROTOCOL,
+ Carriers.BEARER_BITMASK,
+ };
+ final int indexOfName = 0;
+ final int indexOfEdited = 2;
+
+ // Assert that the conflicting APN is merged into the existing user-edited APN, so only 1
+ // APN exists in the db
+ cur = mContentResolver.query(URI_TELEPHONY, testProjection, null, null, null);
+ assertEquals(1, cur.getCount());
+ cur.moveToFirst();
+ assertEquals(carrierName2, cur.getString(indexOfName));
+ assertEquals(value, cur.getInt(indexOfEdited));
+ }
+
+ private void preserveDeletedValueInMerge(int value) {
+ // insert user deleted APN
+ String carrierName1 = "carrier1";
+ String numeric1 = "123234";
+ String mcc1 = "123";
+ String mnc1 = "234";
+ ContentValues editedValue = new ContentValues();
+ editedValue.put(Carriers.NAME, carrierName1);
+ editedValue.put(Carriers.NUMERIC, numeric1);
+ editedValue.put(Carriers.MCC, mcc1);
+ editedValue.put(Carriers.MNC, mnc1);
+ editedValue.put(Carriers.EDITED, value);
+ assertNotNull(mContentResolver.insert(URI_TELEPHONY, editedValue));
+
+ // insert APN that conflicts with edited APN
+ String carrierName2 = "carrier2";
+ ContentValues values = new ContentValues();
+ values.put(Carriers.NAME, carrierName2);
+ values.put(Carriers.NUMERIC, numeric1);
+ values.put(Carriers.MCC, mcc1);
+ values.put(Carriers.MNC, mnc1);
+ values.put(Carriers.EDITED, Carriers.UNEDITED);
+ mContentResolver.insert(URI_TELEPHONY, values);
+
+ String[] testProjection = {
+ Carriers.NAME,
+ Carriers.APN,
+ Carriers.EDITED,
+ Carriers.TYPE,
+ Carriers.PROTOCOL,
+ Carriers.BEARER_BITMASK,
+ };
+ final int indexOfEdited = 2;
+
+ // Assert that the conflicting APN is merged into the existing user-deleted APN.
+ // Entries marked deleted will not show up in queries so we verify that no APNs can
+ // be seen
+ Cursor cur = mContentResolver.query(URI_TELEPHONY, testProjection, null, null, null);
+ assertEquals(0, cur.getCount());
+ }
}