From cabd7cf832f5b160c30bff9c7b975bbf21a95d8e Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Thu, 4 Jun 2015 10:47:08 -0700 Subject: Fix NPE in enterprise API & fix unit tests. Bug 21632829 Bug 21634841 Change-Id: Ic18f44e8de31fe48b1d3b7f3a49c355a4865aeca --- .../providers/contacts/ContactsProvider2.java | 13 +++- .../providers/contacts/ContactsProvider2Test.java | 86 ++++++++++++++++++++++ .../contacts/util/NullContentProvider.java | 55 ++++++++++++++ 3 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 tests/src/com/android/providers/contacts/util/NullContentProvider.java diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java index 6cf6d98..7e91192 100644 --- a/src/com/android/providers/contacts/ContactsProvider2.java +++ b/src/com/android/providers/contacts/ContactsProvider2.java @@ -6771,6 +6771,10 @@ public class ContactsProvider2 extends AbstractContactsProvider final Uri remoteUri = maybeAddUserId(localUri, corpUserId); final Cursor managedCursor = getContext().getContentResolver().query(remoteUri, projection, selection, selectionArgs, sortOrder, null); + if (managedCursor == null) { + // No corp results. Just return the local result. + return primaryCursor; + } final Cursor[] cursorArray = new Cursor[] { primaryCursor, new EnterprisePhoneCursorWrapper(managedCursor) }; @@ -6814,10 +6818,7 @@ public class ContactsProvider2 extends AbstractContactsProvider local.close(); throw th; } - - if (local != null) { - local.close(); - } + // "local" is still open. If we fail the managed CP2 query, we'll still return it. // Step 2. No rows found in the local db, and there is a corp profile. Look at the corp // DB. @@ -6831,7 +6832,11 @@ public class ContactsProvider2 extends AbstractContactsProvider // Note in order to re-write the cursor correctly, we need all columns from the corp cp2. final Cursor corp = getContext().getContentResolver().query(remoteUri, null, selection, selectionArgs, sortOrder, /* cancellationsignal */null); + if (corp == null) { + return local; + } try { + local.close(); if (VERBOSE_LOGGING) { MoreDatabaseUtils.dumpCursor(TAG, "corp raw", corp); } diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java index 73d0083..d75996c 100644 --- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java +++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java @@ -97,6 +97,7 @@ import com.android.providers.contacts.testutil.DeletedContactUtil; import com.android.providers.contacts.testutil.RawContactUtil; import com.android.providers.contacts.testutil.TestUtil; import com.android.providers.contacts.tests.R; +import com.android.providers.contacts.util.NullContentProvider; import com.google.android.collect.Lists; import com.google.android.collect.Sets; @@ -1784,6 +1785,35 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test { } /** + * Test for enterprise caller-id. Corp profile exists, but it returns a null cursor. + */ + public void testPhoneLookupEnterprise_withCorpProfile_nullResult() throws Exception { + setUpNullCorpProvider(); + + Uri uri1 = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, "408-111-1111"); + + // No contacts profile, no data. + assertEquals(0, getCount(uri1)); + + // Insert a contact into the primary CP2. + long rawContactId = ContentUris.parseId( + mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); + DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Doe"); + insertPhoneNumber(rawContactId, "408-111-1111"); + + // Do the query again and check the result. + Cursor c = mResolver.query(uri1, null, null, null, null); + try { + assertEquals(1, c.getCount()); + c.moveToPosition(0); + long contactId = c.getLong(c.getColumnIndex(PhoneLookup._ID)); + assertFalse(Contacts.isEnterpriseContactId(contactId)); // Make sure it's not rewritten. + } finally { + c.close(); + } + } + + /** * Set up the corp user / CP2 and returns the corp CP2 instance. * * Create a second instance of CP2, and add it to the resolver, with the "user-id@" authority. @@ -1802,12 +1832,27 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test { } /** + * Similar to {@link setUpCorpProvider}, but the corp CP2 set up with this will always return + * null from query(). + */ + private void setUpNullCorpProvider() throws Exception { + mActor.mockUserManager.setUsers(MockUserManager.PRIMARY_USER, MockUserManager.CORP_USER); + + mActor.addProvider( + NullContentProvider.class, + "" + MockUserManager.CORP_USER.id + "@com.android.contacts", + new AlteringUserContext(mActor.getProviderContext(), MockUserManager.CORP_USER.id)); + } + + /** * Test for query of merged primary and work contacts. *

* Note: in this test, we add one more provider instance for the authority * "10@com.android.contacts" and use it as the corp cp2. */ public void testQueryMergedDataPhones() throws Exception { + mActor.addPermissions("android.permission.INTERACT_ACROSS_USERS"); + // Insert a contact to the primary CP2. long rawContactId = ContentUris.parseId( mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); @@ -1880,6 +1925,43 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test { } /** + * Test for query of merged primary and work contacts. + *

+ * Note: in this test, we add one more provider instance for the authority + * "10@com.android.contacts" and use it as the corp cp2. + */ + public void testQueryMergedDataPhones_nullCorp() throws Exception { + mActor.addPermissions("android.permission.INTERACT_ACROSS_USERS"); + + // Insert a contact to the primary CP2. + long rawContactId = ContentUris.parseId( + mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); + DataUtil.insertStructuredName(mResolver, rawContactId, "Contact1", "Primary"); + + insertPhoneNumber(rawContactId, "111-111-1111", false, false, Phone.TYPE_MOBILE); + + // Insert a contact to the corp CP2, with different name and phone number. + setUpNullCorpProvider(); + + // Execute the query to get the merged result. + Cursor c = mResolver.query(Phone.ENTERPRISE_CONTENT_URI, new String[]{Phone.CONTACT_ID, + Phone.DISPLAY_NAME, Phone.NUMBER}, Phone.TYPE + " = ?", + new String[]{String.valueOf(Phone.TYPE_MOBILE)}, null); + try { + // Verify the primary contact. + assertEquals(1, c.getCount()); + assertEquals(3, c.getColumnCount()); + c.moveToPosition(0); + assertEquals("Contact1 Primary", c.getString(c.getColumnIndex(Phone.DISPLAY_NAME))); + assertEquals("111-111-1111", c.getString(c.getColumnIndex(Phone.NUMBER))); + long contactId = c.getLong(c.getColumnIndex(Phone.CONTACT_ID)); + assertFalse(Contacts.isEnterpriseContactId(contactId)); + } finally { + c.close(); + } + } + + /** * Test for enterprise caller-id, with the corp profile. * * Note: in this test, we add one more provider instance for the authority @@ -1976,6 +2058,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test { } public void testQueryRawContactEntitiesCorp_noCorpProfile() { + mActor.addPermissions("android.permission.INTERACT_ACROSS_USERS"); + // Insert a contact into the primary CP2. long rawContactId = ContentUris.parseId( mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); @@ -1987,6 +2071,8 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test { } public void testQueryRawContactEntitiesCorp_withCorpProfile() throws Exception { + mActor.addPermissions("android.permission.INTERACT_ACROSS_USERS"); + // Insert a contact into the primary CP2. long rawContactId = ContentUris.parseId( mResolver.insert(RawContacts.CONTENT_URI, new ContentValues())); diff --git a/tests/src/com/android/providers/contacts/util/NullContentProvider.java b/tests/src/com/android/providers/contacts/util/NullContentProvider.java new file mode 100644 index 0000000..1f39b18 --- /dev/null +++ b/tests/src/com/android/providers/contacts/util/NullContentProvider.java @@ -0,0 +1,55 @@ +/* + * 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.providers.contacts.util; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; + +public class NullContentProvider extends ContentProvider { + + @Override + public boolean onCreate() { + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return null; + } + + @Override + public String getType(Uri uri) { + return null; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } +} -- cgit v1.1