aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTa-wei Yen <twyen@google.com>2017-01-17 18:31:59 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-01-17 18:32:00 +0000
commit8e796d593de3fac9249b2bf744d699b129ab3e90 (patch)
tree50c490178a87fc603811054f9647a288884d41b5
parent640e0827443fbdaed0e402b8af53cdad97d04bc6 (diff)
parent687bef960a8309410ee1ba0da06a012914bef88e (diff)
downloadContactsProvider-8e796d593de3fac9249b2bf744d699b129ab3e90.tar.gz
Merge "Prevent LAST_MODIFIED from changing after deletion" into nyc-mr2-dev
-rw-r--r--src/com/android/providers/contacts/CallLogProvider.java42
-rw-r--r--src/com/android/providers/contacts/DbModifierWithNotification.java33
-rw-r--r--tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java18
-rw-r--r--tests/src/com/android/providers/contacts/CallLogProviderTest.java10
-rw-r--r--tests/src/com/android/providers/contacts/VoicemailProviderTest.java35
5 files changed, 119 insertions, 19 deletions
diff --git a/src/com/android/providers/contacts/CallLogProvider.java b/src/com/android/providers/contacts/CallLogProvider.java
index a3bed8c3..9a5b7c48 100644
--- a/src/com/android/providers/contacts/CallLogProvider.java
+++ b/src/com/android/providers/contacts/CallLogProvider.java
@@ -46,11 +46,11 @@ import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.providers.contacts.CallLogDatabaseHelper.DbProperties;
import com.android.providers.contacts.CallLogDatabaseHelper.Tables;
import com.android.providers.contacts.util.SelectionBuilder;
import com.android.providers.contacts.util.UserUtils;
-import com.google.common.annotations.VisibleForTesting;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -153,6 +153,19 @@ public class CallLogProvider extends ContentProvider {
sCallsProjectionMap.put(Calls.LAST_MODIFIED, Calls.LAST_MODIFIED);
}
+ private static final String ALLOWED_PACKAGE_FOR_TESTING = "com.android.providers.contacts";
+
+ @VisibleForTesting
+ static final String PARAM_KEY_QUERY_FOR_TESTING = "query_for_testing";
+
+ /**
+ * A long to override the clock used for timestamps, or "null" to reset to the system clock.
+ */
+ @VisibleForTesting
+ static final String PARAM_KEY_SET_TIME_FOR_TESTING = "set_time_for_testing";
+
+ private static Long sTimeForTestMillis;
+
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private volatile CountDownLatch mReadAccessLatch;
@@ -223,6 +236,9 @@ public class CallLogProvider extends ContentProvider {
" order=[" + sortOrder + "] CPID=" + Binder.getCallingPid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}
+
+ queryForTesting(uri);
+
waitForAccess(mReadAccessLatch);
final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(Tables.CALLS);
@@ -278,6 +294,30 @@ public class CallLogProvider extends ContentProvider {
return c;
}
+ private void queryForTesting(Uri uri) {
+ if (!uri.getBooleanQueryParameter(PARAM_KEY_QUERY_FOR_TESTING, false)) {
+ return;
+ }
+ if (!getCallingPackage().equals(ALLOWED_PACKAGE_FOR_TESTING)) {
+ throw new IllegalArgumentException("query_for_testing set from foreign package "
+ + getCallingPackage());
+ }
+
+ String timeString = uri.getQueryParameter(PARAM_KEY_SET_TIME_FOR_TESTING);
+ if (timeString != null) {
+ if (timeString.equals("null")) {
+ sTimeForTestMillis = null;
+ } else {
+ sTimeForTestMillis = Long.parseLong(timeString);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static Long getTimeForTestMillis() {
+ return sTimeForTestMillis;
+ }
+
/**
* Gets an integer query parameter from a given uri.
*
diff --git a/src/com/android/providers/contacts/DbModifierWithNotification.java b/src/com/android/providers/contacts/DbModifierWithNotification.java
index ef1b847b..b3cf0ef4 100644
--- a/src/com/android/providers/contacts/DbModifierWithNotification.java
+++ b/src/com/android/providers/contacts/DbModifierWithNotification.java
@@ -63,7 +63,8 @@ public class DbModifierWithNotification implements DatabaseModifier {
private static final int SOURCE_PACKAGE_COLUMN_INDEX = 0;
private static final String NON_NULL_SOURCE_PACKAGE_SELECTION =
VoicemailContract.SOURCE_PACKAGE_FIELD + " IS NOT NULL";
-
+ private static final String NOT_DELETED_SELECTION =
+ Voicemails.DELETED + " == 0";
private final String mTableName;
private final SQLiteDatabase mDb;
private final InsertHelper mInsertHelper;
@@ -98,7 +99,7 @@ public class DbModifierWithNotification implements DatabaseModifier {
public long insert(String table, String nullColumnHack, ContentValues values) {
Set<String> packagesModified = getModifiedPackages(values);
if (mIsCallsTable) {
- values.put(Calls.LAST_MODIFIED, System.currentTimeMillis());
+ values.put(Calls.LAST_MODIFIED, getTimeMillis());
}
long rowId = mDb.insert(table, nullColumnHack, values);
if (rowId > 0 && packagesModified.size() != 0) {
@@ -115,7 +116,7 @@ public class DbModifierWithNotification implements DatabaseModifier {
public long insert(ContentValues values) {
Set<String> packagesModified = getModifiedPackages(values);
if (mIsCallsTable) {
- values.put(Calls.LAST_MODIFIED, System.currentTimeMillis());
+ values.put(Calls.LAST_MODIFIED, getTimeMillis());
}
long rowId = mInsertHelper.insert(values);
if (rowId > 0 && packagesModified.size() != 0) {
@@ -160,8 +161,12 @@ public class DbModifierWithNotification implements DatabaseModifier {
boolean hasMarkedRead = false;
if (mIsCallsTable) {
- values.put(Calls.LAST_MODIFIED, System.currentTimeMillis());
-
+ if (values.containsKey(Voicemails.DELETED)
+ && !values.getAsBoolean(Voicemails.DELETED)) {
+ values.put(Calls.LAST_MODIFIED, getTimeMillis());
+ } else {
+ updateLastModified(table, whereClause, whereArgs);
+ }
if (isVoicemail) {
// If a calling package is modifying its own entries, it means that the change came
// from the server and thus is synced or "clean". Otherwise, it means that a local
@@ -199,6 +204,15 @@ public class DbModifierWithNotification implements DatabaseModifier {
return count;
}
+ private void updateLastModified(String table, String whereClause, String[] whereArgs) {
+ ContentValues values = new ContentValues();
+ values.put(Calls.LAST_MODIFIED, getTimeMillis());
+
+ mDb.update(table, values,
+ DbQueryUtils.concatenateClauses(NOT_DELETED_SELECTION, whereClause),
+ whereArgs);
+ }
+
@Override
public int delete(String table, String whereClause, String[] whereArgs) {
Set<String> packagesModified = getModifiedPackages(whereClause, whereArgs);
@@ -217,7 +231,7 @@ public class DbModifierWithNotification implements DatabaseModifier {
ContentValues values = new ContentValues();
values.put(VoicemailContract.Voicemails.DIRTY, 1);
values.put(VoicemailContract.Voicemails.DELETED, 1);
- values.put(VoicemailContract.Voicemails.LAST_MODIFIED, System.currentTimeMillis());
+ values.put(VoicemailContract.Voicemails.LAST_MODIFIED, getTimeMillis());
count = mDb.update(table, values, whereClause, whereArgs);
} else {
count = mDb.delete(table, whereClause, whereArgs);
@@ -363,4 +377,11 @@ public class DbModifierWithNotification implements DatabaseModifier {
}
return values.getAsBoolean(key);
}
+
+ private long getTimeMillis() {
+ if (CallLogProvider.getTimeForTestMillis() == null) {
+ return System.currentTimeMillis();
+ }
+ return CallLogProvider.getTimeForTestMillis();
+ }
}
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
index 86dff66a..09241549 100644
--- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
@@ -31,6 +31,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.CallLog;
+import android.provider.CallLog.Calls;
import android.provider.ContactsContract;
import android.provider.ContactsContract.AggregationExceptions;
import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -1355,16 +1356,21 @@ public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase {
}
}
- protected void assertLastModified(Uri uri) {
- assertLastModified(uri, System.currentTimeMillis(), 1000);
- }
-
- protected void assertLastModified(Uri uri, long time, long tolerance) {
+ protected void assertLastModified(Uri uri, long time) {
Cursor c = mResolver.query(uri, null, null, null, null);
c.moveToFirst();
int index = c.getColumnIndex(CallLog.Calls.LAST_MODIFIED);
long timeStamp = c.getLong(index);
- assertTrue(Math.abs(time - timeStamp) < tolerance);
+ assertEquals(timeStamp, time);
+ }
+
+ protected void setTimeForTest(Long time) {
+ Uri uri = Calls.CONTENT_URI.buildUpon()
+ .appendQueryParameter(CallLogProvider.PARAM_KEY_QUERY_FOR_TESTING, "1")
+ .appendQueryParameter(CallLogProvider.PARAM_KEY_SET_TIME_FOR_TESTING,
+ time == null ? "null" : time.toString())
+ .build();
+ mResolver.query(uri, null, null, null, null);
}
/**
* A contact in the database, and the attributes used to create it. Construct using
diff --git a/tests/src/com/android/providers/contacts/CallLogProviderTest.java b/tests/src/com/android/providers/contacts/CallLogProviderTest.java
index f492e736..8ee7a5be 100644
--- a/tests/src/com/android/providers/contacts/CallLogProviderTest.java
+++ b/tests/src/com/android/providers/contacts/CallLogProviderTest.java
@@ -85,16 +85,18 @@ public class CallLogProviderTest extends BaseContactsProvider2Test {
protected void tearDown() throws Exception {
setUpWithVoicemailPermissions();
mResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL, null, null);
+ setTimeForTest(null);
super.tearDown();
}
public void testInsert_RegularCallRecord() {
+ setTimeForTest(1000L);
ContentValues values = getDefaultCallValues();
Uri uri = mResolver.insert(Calls.CONTENT_URI, values);
values.put(Calls.COUNTRY_ISO, "us");
assertStoredValues(uri, values);
assertSelection(uri, values, Calls._ID, ContentUris.parseId(uri));
- assertLastModified(uri);
+ assertLastModified(uri, 1000);
}
private void setUpWithVoicemailPermissions() {
@@ -105,6 +107,7 @@ public class CallLogProviderTest extends BaseContactsProvider2Test {
public void testInsert_VoicemailCallRecord() {
setUpWithVoicemailPermissions();
+ setTimeForTest(1000L);
final ContentValues values = getDefaultCallValues();
values.put(Calls.TYPE, Calls.VOICEMAIL_TYPE);
values.put(Calls.VOICEMAIL_URI, "content://foo/voicemail/2");
@@ -121,10 +124,11 @@ public class CallLogProviderTest extends BaseContactsProvider2Test {
Uri uri = mResolver.insert(Calls.CONTENT_URI_WITH_VOICEMAIL, values);
assertStoredValues(uri, values);
assertSelection(uri, values, Calls._ID, ContentUris.parseId(uri));
- assertLastModified(uri);
+ assertLastModified(uri, 1000);
}
public void testUpdate() {
+ setTimeForTest(1000L);
Uri uri = insertCallRecord();
ContentValues values = new ContentValues();
values.put(Calls.TYPE, Calls.OUTGOING_TYPE);
@@ -139,7 +143,7 @@ public class CallLogProviderTest extends BaseContactsProvider2Test {
int count = mResolver.update(uri, values, null, null);
assertEquals(1, count);
assertStoredValues(uri, values);
- assertLastModified(uri);
+ assertLastModified(uri, 1000);
}
public void testDelete() {
diff --git a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
index b4c9e049..72667314 100644
--- a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
+++ b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
@@ -20,8 +20,10 @@ import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
+import android.os.BatteryStats.Uid.Proc;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.provider.VoicemailContract;
import android.provider.VoicemailContract.Status;
@@ -65,6 +67,7 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
protected void setUp() throws Exception {
super.setUp();
setUpForOwnPermission();
+ addProvider(CallLogProviderTestable.class, CallLog.AUTHORITY);
}
/** Returns the appropriate /voicemail URI. */
@@ -80,6 +83,7 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
}
public void testInsert() throws Exception {
+ setTimeForTest(1000L);
Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues());
// We create on purpose a new set of ContentValues here, because the code above modifies
// the copy it gets.
@@ -87,7 +91,7 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
assertSelection(uri, getTestVoicemailValues(), Voicemails._ID, ContentUris.parseId(uri));
assertEquals(1, countFilesInTestDirectory());
- assertLastModified(uri);
+ assertLastModified(uri, 1000);
}
public void testInsertReadMessageIsNotNew() throws Exception {
@@ -131,6 +135,7 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
}
public void testUpdate() {
+ setTimeForTest(1000L);
Uri uri = insertVoicemail();
ContentValues values = new ContentValues();
values.put(Voicemails.NUMBER, "1-800-263-7643");
@@ -145,7 +150,7 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
int count = mResolver.update(uri, values, null, null);
assertEquals(1, count);
assertStoredValues(uri, values);
- assertLastModified(uri);
+ assertLastModified(uri, 1000);
}
public void testUpdateOwnPackageVoicemail_NotDirty() {
@@ -182,6 +187,7 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
public void testDeleteOtherPackageVoicemail_SetsDirtyStatus() {
setUpForFullPermission();
+ setTimeForTest(1000L);
final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package");
assertEquals(1, getCount(voicemailUri(), null, null));
@@ -195,7 +201,7 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
assertEquals(1, getCount(anotherVoicemail, null, null));
assertStoredValues(anotherVoicemail, values);
- assertLastModified(anotherVoicemail);
+ assertLastModified(anotherVoicemail, 1000);
}
public void testDelete() {
@@ -206,6 +212,29 @@ public class VoicemailProviderTest extends BaseVoicemailProviderTest {
assertEquals(0, getCount(uri, null, null));
}
+ public void testUpdateAfterDelete_lastModifiedNotChanged() {
+ setUpForFullPermission();
+ setTimeForTest(1000L);
+ final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package");
+ assertEquals(1, getCount(voicemailUri(), null, null));
+
+ // Clear the mapping for our own UID so that this doesn't look like an internal transaction.
+ mPackageManager.removePackage(Process.myUid());
+ mResolver.delete(anotherVoicemail, null, null);
+ assertLastModified(anotherVoicemail, 1000);
+
+ mPackageManager.addPackage(Process.myUid(), mActor.packageName);
+ setTimeForTest(2000L);
+ mResolver.update(anotherVoicemail, new ContentValues(), null, null);
+ assertLastModified(anotherVoicemail, 1000);
+
+ setTimeForTest(3000L);
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.DELETED, "0");
+ mResolver.update(anotherVoicemail, values, null, null);
+ assertLastModified(anotherVoicemail, 3000);
+ }
+
public void testGetType_ItemUri() throws Exception {
// Random item uri.
assertEquals(Voicemails.ITEM_TYPE,