Loading android/app/src/com/android/bluetooth/pbap/BluetoothPbapConfig.java +6 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.util.Log; import com.android.bluetooth.R; import com.android.internal.annotations.VisibleForTesting; public class BluetoothPbapConfig { private static boolean sUseProfileForOwnerVcard = true; Loading Loading @@ -57,4 +58,9 @@ public class BluetoothPbapConfig { public static boolean includePhotosInVcard() { return sIncludePhotosInVcard; } @VisibleForTesting public static void setIncludePhotosInVcard(boolean includePhotosInVcard) { sIncludePhotosInVcard = includePhotosInVcard; } } android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java +33 −28 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.util.Log; import com.android.bluetooth.R; import com.android.bluetooth.util.DevicePolicyUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.obex.Operation; import com.android.obex.ResponseCodes; import com.android.obex.ServerOperation; Loading Loading @@ -140,7 +141,6 @@ public class BluetoothPbapVcardManager { } //End enhancement BluetoothPbapCallLogComposer composer = new BluetoothPbapCallLogComposer(mContext); String name = BluetoothPbapService.getLocalPhoneName(); String number = BluetoothPbapService.getLocalPhoneNum(); String vcard = BluetoothPbapCallLogComposer.composeVCardForPhoneOwnNumber( Loading Loading @@ -174,7 +174,7 @@ public class BluetoothPbapVcardManager { * @param type specifies which phonebook object, e.g., pb, fav * @return */ public final int getContactsSize(final int type) { private int getContactsSize(final int type) { final Uri myUri = DevicePolicyUtils.getEnterprisePhoneUri(mContext); Cursor contactCursor = null; String selectionClause = null; Loading @@ -182,8 +182,8 @@ public class BluetoothPbapVcardManager { selectionClause = Phone.STARRED + " = 1"; } try { contactCursor = mResolver.query(myUri, new String[]{Phone.CONTACT_ID}, selectionClause, contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, new String[]{Phone.CONTACT_ID}, selectionClause, null, Phone.CONTACT_ID); if (contactCursor == null) { return 0; Loading @@ -203,14 +203,14 @@ public class BluetoothPbapVcardManager { return 0; } public final int getCallHistorySize(final int type) { private int getCallHistorySize(final int type) { final Uri myUri = CallLog.Calls.CONTENT_URI; String selection = BluetoothPbapObexServer.createSelectionPara(type); int size = 0; Cursor callCursor = null; try { callCursor = mResolver.query(myUri, null, selection, null, CallLog.Calls.DEFAULT_SORT_ORDER); callCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, null, selection, null, CallLog.Calls.DEFAULT_SORT_ORDER); if (callCursor != null) { size = callCursor.getCount(); } Loading @@ -225,9 +225,12 @@ public class BluetoothPbapVcardManager { return size; } private static final int CALLS_NUMBER_COLUMN_INDEX = 0; private static final int CALLS_NAME_COLUMN_INDEX = 1; private static final int CALLS_NUMBER_PRESENTATION_COLUMN_INDEX = 2; @VisibleForTesting static final int CALLS_NUMBER_COLUMN_INDEX = 0; @VisibleForTesting static final int CALLS_NAME_COLUMN_INDEX = 1; @VisibleForTesting static final int CALLS_NUMBER_PRESENTATION_COLUMN_INDEX = 2; public final ArrayList<String> loadCallHistoryList(final int type) { final Uri myUri = CallLog.Calls.CONTENT_URI; Loading @@ -240,7 +243,8 @@ public class BluetoothPbapVcardManager { Cursor callCursor = null; ArrayList<String> list = new ArrayList<String>(); try { callCursor = mResolver.query(myUri, projection, selection, null, CALLLOG_SORT_ORDER); callCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, projection, selection, null, CALLLOG_SORT_ORDER); if (callCursor != null) { for (callCursor.moveToFirst(); !callCursor.isAfterLast(); callCursor.moveToNext()) { String name = callCursor.getString(CALLS_NAME_COLUMN_INDEX); Loading Loading @@ -291,7 +295,8 @@ public class BluetoothPbapVcardManager { if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) { orderBy = Phone.DISPLAY_NAME; } contactCursor = mResolver.query(myUri, PHONES_CONTACTS_PROJECTION, null, null, orderBy); contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, PHONES_CONTACTS_PROJECTION, null, null, orderBy); if (contactCursor != null) { appendDistinctNameIdList(nameList, mContext.getString(android.R.string.unknownName), contactCursor); Loading Loading @@ -349,7 +354,8 @@ public class BluetoothPbapVcardManager { final Uri myUri = DevicePolicyUtils.getEnterprisePhoneUri(mContext); Cursor contactCursor = null; try { contactCursor = mResolver.query(myUri, PHONES_CONTACTS_PROJECTION, null, null, contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, PHONES_CONTACTS_PROJECTION, null, null, Phone.CONTACT_ID); ArrayList<String> contactNameIdList = new ArrayList<String>(); Loading Loading @@ -423,7 +429,6 @@ public class BluetoothPbapVcardManager { public final ArrayList<String> getContactNamesByNumber(final String phoneNumber) { ArrayList<String> nameList = new ArrayList<String>(); ArrayList<String> tempNameList = new ArrayList<String>(); Cursor contactCursor = null; Uri uri = null; Loading @@ -438,7 +443,8 @@ public class BluetoothPbapVcardManager { } try { contactCursor = mResolver.query(uri, projection, null, null, Phone.CONTACT_ID); contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, uri, projection, null, null, Phone.CONTACT_ID); if (contactCursor != null) { appendDistinctNameIdList(nameList, mContext.getString(android.R.string.unknownName), Loading @@ -457,13 +463,6 @@ public class BluetoothPbapVcardManager { contactCursor = null; } } int tempListSize = tempNameList.size(); for (int index = 0; index < tempListSize; index++) { String object = tempNameList.get(index); if (!nameList.contains(object)) { nameList.add(object); } } return nameList; } Loading @@ -479,7 +478,8 @@ public class BluetoothPbapVcardManager { long primaryVcMsb = 0; ArrayList<String> list = new ArrayList<String>(); try { callCursor = mResolver.query(myUri, null, selection, null, null); callCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, null, selection, null, null); while (callCursor != null && callCursor.moveToNext()) { count = count + 1; } Loading Loading @@ -522,7 +522,8 @@ public class BluetoothPbapVcardManager { long endPointId = 0; try { // Need test to see if order by _ID is ok here, or by date? callsCursor = mResolver.query(myUri, CALLLOG_PROJECTION, typeSelection, null, callsCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, CALLLOG_PROJECTION, typeSelection, null, CALLLOG_SORT_ORDER); if (callsCursor != null) { callsCursor.moveToPosition(startPoint - 1); Loading Loading @@ -595,7 +596,8 @@ public class BluetoothPbapVcardManager { } try { contactCursor = mResolver.query(myUri, PHONES_CONTACTS_PROJECTION, selectionClause, contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, PHONES_CONTACTS_PROJECTION, selectionClause, null, Phone.CONTACT_ID); if (contactCursor != null) { contactIdCursor = Loading Loading @@ -638,7 +640,8 @@ public class BluetoothPbapVcardManager { if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) { orderBy = Phone.DISPLAY_NAME; } contactCursor = mResolver.query(myUri, PHONES_CONTACTS_PROJECTION, null, null, orderBy); contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, PHONES_CONTACTS_PROJECTION, null, null, orderBy); } catch (CursorWindowAllocationException e) { Log.e(TAG, "CursorWindowAllocationException while composing phonebook one vcard"); } finally { Loading Loading @@ -1013,7 +1016,8 @@ public class BluetoothPbapVcardManager { } public String stripTelephoneNumber(String vCard) { String[] attr = vCard.split(System.getProperty("line.separator")); String separator = System.getProperty("line.separator"); String[] attr = vCard.split(separator); String stripedVCard = ""; for (int i = 0; i < attr.length; i++) { if (attr[i].startsWith("TEL")) { Loading @@ -1036,7 +1040,7 @@ public class BluetoothPbapVcardManager { for (int i = 0; i < attr.length; i++) { if (!attr[i].isEmpty()) { stripedVCard = stripedVCard.concat(attr[i] + "\n"); stripedVCard = stripedVCard.concat(attr[i] + separator); } } if (V) { Loading @@ -1045,6 +1049,7 @@ public class BluetoothPbapVcardManager { return stripedVCard; } // TODO: Merge this class with BluetoothPbapSimVcardManager.HandlerForStringBuffer /** * Handler to emit vCards to PCE. */ Loading android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManagerTest.java +8 −8 Original line number Diff line number Diff line Loading @@ -204,8 +204,8 @@ public class BluetoothPbapSimVcardManagerTest { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { currentPosition.getAndAdd(1); return true; int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(anyInt())).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); Loading Loading @@ -254,8 +254,8 @@ public class BluetoothPbapSimVcardManagerTest { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { currentPosition.getAndAdd(1); return true; int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(anyInt())).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); Loading Loading @@ -289,8 +289,8 @@ public class BluetoothPbapSimVcardManagerTest { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { currentPosition.getAndAdd(1); return true; int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(anyInt())).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); Loading Loading @@ -328,8 +328,8 @@ public class BluetoothPbapSimVcardManagerTest { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { currentPosition.getAndAdd(1); return true; int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(BluetoothPbapSimVcardManager.NAME_COLUMN_INDEX)).then( (Answer<String>) i -> { Loading android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapVcardManagerTest.java 0 → 100644 +336 −0 Original line number Diff line number Diff line /* * Copyright 2022 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.bluetooth.pbap; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.provider.CallLog; import android.provider.ContactsContract; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.R; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import org.mockito.stubbing.Answer; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @SmallTest @RunWith(AndroidJUnit4.class) public class BluetoothPbapVcardManagerTest { private static final String TAG = BluetoothPbapVcardManagerTest.class.getSimpleName(); @Spy BluetoothPbapMethodProxy mPbapMethodProxy = BluetoothPbapMethodProxy.getInstance(); Context mContext; BluetoothPbapVcardManager mManager; @Before public void setUp() { MockitoAnnotations.initMocks(this); BluetoothPbapMethodProxy.setInstanceForTesting(mPbapMethodProxy); mContext = InstrumentationRegistry.getTargetContext(); mManager = new BluetoothPbapVcardManager(mContext); } @After public void tearDown() { BluetoothPbapMethodProxy.setInstanceForTesting(null); } @Test public void testGetOwnerPhoneNumberVcard_whenUseProfileForOwnerVcard() { BluetoothPbapConfig.setIncludePhotosInVcard(true); assertThat(mManager.getOwnerPhoneNumberVcard(/*vcardType21=*/true, /*filter=*/null)) .isNotNull(); } @Test public void testGetOwnerPhoneNumberVcard_whenNotUseProfileForOwnerVcard() { BluetoothPbapConfig.setIncludePhotosInVcard(false); assertThat(mManager.getOwnerPhoneNumberVcard(/*vcardType21=*/true, /*filter=*/null)) .isNotNull(); } @Test public void testGetPhonebookSize_whenTypeIsPhonebook() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); // 5 distinct contact IDs. final List<Integer> contactIdsWithDuplicates = Arrays.asList(0, 1, 1, 2, 2, 3, 3, 4, 4); // Implement Cursor iteration final int size = contactIdsWithDuplicates.size(); AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToPosition(anyInt())).then((Answer<Boolean>) i -> { int position = i.getArgument(0); currentPosition.set(position); return true; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getLong(anyInt())).then((Answer<Long>) i -> { return (long) contactIdsWithDuplicates.get(currentPosition.get()); }); // 5 distinct contact IDs + self (which is only included for phonebook) final int expectedSize = 5 + 1; assertThat(mManager.getPhonebookSize(BluetoothPbapObexServer.ContentType.PHONEBOOK, null)) .isEqualTo(expectedSize); } @Test public void testGetPhonebookSize_whenTypeIsFavorites() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); // 5 distinct contact IDs. final List<Integer> contactIdsWithDuplicates = Arrays.asList( 0, 1, 1, 2, // starred 2, 3, 3, 4, 4 // not starred ); // Implement Cursor iteration final int starredSize = 4; AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToPosition(anyInt())).then((Answer<Boolean>) i -> { int position = i.getArgument(0); currentPosition.set(position); return true; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < starredSize; }); when(cursor.getLong(anyInt())).then((Answer<Long>) i -> { return (long) contactIdsWithDuplicates.get(currentPosition.get()); }); // Among 4 starred contact Ids, there are 3 distinct contact IDs final int expectedSize = 3; assertThat(mManager.getPhonebookSize(BluetoothPbapObexServer.ContentType.FAVORITES, null)) .isEqualTo(expectedSize); } @Test public void testGetPhonebookSize_whenTypeIsSimPhonebook() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); final int expectedSize = 10; when(cursor.getCount()).thenReturn(expectedSize); BluetoothPbapSimVcardManager simVcardManager = mock(BluetoothPbapSimVcardManager.class); assertThat(mManager.getPhonebookSize(BluetoothPbapObexServer.ContentType.SIM_PHONEBOOK, simVcardManager)).isEqualTo(expectedSize); verify(simVcardManager).getSIMContactsSize(); } @Test public void testGetPhonebookSize_whenTypeIsHistory() { final int historySize = 10; Cursor cursor = mock(Cursor.class); when(cursor.getCount()).thenReturn(historySize); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); assertThat(mManager.getPhonebookSize( BluetoothPbapObexServer.ContentType.INCOMING_CALL_HISTORY, null)) .isEqualTo(historySize); } @Test public void testLoadCallHistoryList() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); List<String> nameList = Arrays.asList("A", "B", "", ""); List<String> numberList = Arrays.asList("0000", "1111", "2222", "3333"); List<Integer> presentationAllowedList = Arrays.asList( CallLog.Calls.PRESENTATION_ALLOWED, CallLog.Calls.PRESENTATION_ALLOWED, CallLog.Calls.PRESENTATION_ALLOWED, CallLog.Calls.PRESENTATION_UNKNOWN); // The number "3333" should not be shown. List<String> expectedResult = Arrays.asList( "A", "B", "2222", mContext.getString(R.string.unknownNumber)); // Implement Cursor iteration final int size = nameList.size(); AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToFirst()).then((Answer<Boolean>) i -> { currentPosition.set(0); return true; }); when(cursor.isAfterLast()).then((Answer<Boolean>) i -> { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(BluetoothPbapVcardManager.CALLS_NAME_COLUMN_INDEX)) .then((Answer<String>) i -> { return nameList.get(currentPosition.get()); }); when(cursor.getString(BluetoothPbapVcardManager.CALLS_NUMBER_COLUMN_INDEX)) .then((Answer<String>) i -> { return numberList.get(currentPosition.get()); }); when(cursor.getInt(BluetoothPbapVcardManager.CALLS_NUMBER_PRESENTATION_COLUMN_INDEX)) .then((Answer<Integer>) i -> { return presentationAllowedList.get(currentPosition.get()); }); assertThat(mManager.loadCallHistoryList( BluetoothPbapObexServer.ContentType.INCOMING_CALL_HISTORY)) .isEqualTo(expectedResult); } @Test public void testGetPhonebookNameList() { final String localPhoneName = "test_local_phone_name"; BluetoothPbapService.setLocalPhoneName(localPhoneName); Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); List<String> nameList = Arrays.asList("A", "B", "C", ""); List<Integer> contactIdList = Arrays.asList(0, 1, 2, 3); List<String> expectedResult = Arrays.asList( localPhoneName, "A,0", "B,1", "C,2", mContext.getString(android.R.string.unknownName) + ",3"); // Implement Cursor iteration final int size = nameList.size(); AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToPosition(anyInt())).then((Answer<Boolean>) i -> { int position = i.getArgument(0); currentPosition.set(position); return true; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < size; }); final int contactIdColumn = 0; final int nameColumn = 1; when(cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID)).thenReturn(contactIdColumn); when(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)).thenReturn(nameColumn); when(cursor.getLong(contactIdColumn)).then((Answer<Long>) i -> { return (long) contactIdList.get(currentPosition.get()); }); when(cursor.getString(nameColumn)).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); }); assertThat(mManager.getPhonebookNameList(BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL)) .isEqualTo(expectedResult); } @Test public void testGetContactNamesByNumber_whenNumberIsNull() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); List<String> nameList = Arrays.asList("A", "B", "C", ""); List<Integer> contactIdList = Arrays.asList(0, 1, 2, 3); List<String> expectedResult = Arrays.asList( "A,0", "B,1", "C,2", mContext.getString(android.R.string.unknownName) + ",3"); // Implement Cursor iteration final int size = nameList.size(); AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToPosition(anyInt())).then((Answer<Boolean>) i -> { int position = i.getArgument(0); currentPosition.set(position); return true; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < size; }); final int contactIdColumn = 0; final int nameColumn = 1; when(cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID)).thenReturn(contactIdColumn); when(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)).thenReturn(nameColumn); when(cursor.getLong(contactIdColumn)).then((Answer<Long>) i -> { return (long) contactIdList.get(currentPosition.get()); }); when(cursor.getString(nameColumn)).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); }); assertThat(mManager.getContactNamesByNumber(null)) .isEqualTo(expectedResult); } @Test public void testStripTelephoneNumber() { final String separator = System.getProperty("line.separator"); final String vCard = "SomeRandomLine" + separator + "TEL:+1-(588)-328-382" + separator; final String expectedResult = "SomeRandomLine" + separator + "TEL:+1588328382" + separator; assertThat(mManager.stripTelephoneNumber(vCard)).isEqualTo(expectedResult); } } Loading
android/app/src/com/android/bluetooth/pbap/BluetoothPbapConfig.java +6 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.util.Log; import com.android.bluetooth.R; import com.android.internal.annotations.VisibleForTesting; public class BluetoothPbapConfig { private static boolean sUseProfileForOwnerVcard = true; Loading Loading @@ -57,4 +58,9 @@ public class BluetoothPbapConfig { public static boolean includePhotosInVcard() { return sIncludePhotosInVcard; } @VisibleForTesting public static void setIncludePhotosInVcard(boolean includePhotosInVcard) { sIncludePhotosInVcard = includePhotosInVcard; } }
android/app/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java +33 −28 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.util.Log; import com.android.bluetooth.R; import com.android.bluetooth.util.DevicePolicyUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.obex.Operation; import com.android.obex.ResponseCodes; import com.android.obex.ServerOperation; Loading Loading @@ -140,7 +141,6 @@ public class BluetoothPbapVcardManager { } //End enhancement BluetoothPbapCallLogComposer composer = new BluetoothPbapCallLogComposer(mContext); String name = BluetoothPbapService.getLocalPhoneName(); String number = BluetoothPbapService.getLocalPhoneNum(); String vcard = BluetoothPbapCallLogComposer.composeVCardForPhoneOwnNumber( Loading Loading @@ -174,7 +174,7 @@ public class BluetoothPbapVcardManager { * @param type specifies which phonebook object, e.g., pb, fav * @return */ public final int getContactsSize(final int type) { private int getContactsSize(final int type) { final Uri myUri = DevicePolicyUtils.getEnterprisePhoneUri(mContext); Cursor contactCursor = null; String selectionClause = null; Loading @@ -182,8 +182,8 @@ public class BluetoothPbapVcardManager { selectionClause = Phone.STARRED + " = 1"; } try { contactCursor = mResolver.query(myUri, new String[]{Phone.CONTACT_ID}, selectionClause, contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, new String[]{Phone.CONTACT_ID}, selectionClause, null, Phone.CONTACT_ID); if (contactCursor == null) { return 0; Loading @@ -203,14 +203,14 @@ public class BluetoothPbapVcardManager { return 0; } public final int getCallHistorySize(final int type) { private int getCallHistorySize(final int type) { final Uri myUri = CallLog.Calls.CONTENT_URI; String selection = BluetoothPbapObexServer.createSelectionPara(type); int size = 0; Cursor callCursor = null; try { callCursor = mResolver.query(myUri, null, selection, null, CallLog.Calls.DEFAULT_SORT_ORDER); callCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, null, selection, null, CallLog.Calls.DEFAULT_SORT_ORDER); if (callCursor != null) { size = callCursor.getCount(); } Loading @@ -225,9 +225,12 @@ public class BluetoothPbapVcardManager { return size; } private static final int CALLS_NUMBER_COLUMN_INDEX = 0; private static final int CALLS_NAME_COLUMN_INDEX = 1; private static final int CALLS_NUMBER_PRESENTATION_COLUMN_INDEX = 2; @VisibleForTesting static final int CALLS_NUMBER_COLUMN_INDEX = 0; @VisibleForTesting static final int CALLS_NAME_COLUMN_INDEX = 1; @VisibleForTesting static final int CALLS_NUMBER_PRESENTATION_COLUMN_INDEX = 2; public final ArrayList<String> loadCallHistoryList(final int type) { final Uri myUri = CallLog.Calls.CONTENT_URI; Loading @@ -240,7 +243,8 @@ public class BluetoothPbapVcardManager { Cursor callCursor = null; ArrayList<String> list = new ArrayList<String>(); try { callCursor = mResolver.query(myUri, projection, selection, null, CALLLOG_SORT_ORDER); callCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, projection, selection, null, CALLLOG_SORT_ORDER); if (callCursor != null) { for (callCursor.moveToFirst(); !callCursor.isAfterLast(); callCursor.moveToNext()) { String name = callCursor.getString(CALLS_NAME_COLUMN_INDEX); Loading Loading @@ -291,7 +295,8 @@ public class BluetoothPbapVcardManager { if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) { orderBy = Phone.DISPLAY_NAME; } contactCursor = mResolver.query(myUri, PHONES_CONTACTS_PROJECTION, null, null, orderBy); contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, PHONES_CONTACTS_PROJECTION, null, null, orderBy); if (contactCursor != null) { appendDistinctNameIdList(nameList, mContext.getString(android.R.string.unknownName), contactCursor); Loading Loading @@ -349,7 +354,8 @@ public class BluetoothPbapVcardManager { final Uri myUri = DevicePolicyUtils.getEnterprisePhoneUri(mContext); Cursor contactCursor = null; try { contactCursor = mResolver.query(myUri, PHONES_CONTACTS_PROJECTION, null, null, contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, PHONES_CONTACTS_PROJECTION, null, null, Phone.CONTACT_ID); ArrayList<String> contactNameIdList = new ArrayList<String>(); Loading Loading @@ -423,7 +429,6 @@ public class BluetoothPbapVcardManager { public final ArrayList<String> getContactNamesByNumber(final String phoneNumber) { ArrayList<String> nameList = new ArrayList<String>(); ArrayList<String> tempNameList = new ArrayList<String>(); Cursor contactCursor = null; Uri uri = null; Loading @@ -438,7 +443,8 @@ public class BluetoothPbapVcardManager { } try { contactCursor = mResolver.query(uri, projection, null, null, Phone.CONTACT_ID); contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, uri, projection, null, null, Phone.CONTACT_ID); if (contactCursor != null) { appendDistinctNameIdList(nameList, mContext.getString(android.R.string.unknownName), Loading @@ -457,13 +463,6 @@ public class BluetoothPbapVcardManager { contactCursor = null; } } int tempListSize = tempNameList.size(); for (int index = 0; index < tempListSize; index++) { String object = tempNameList.get(index); if (!nameList.contains(object)) { nameList.add(object); } } return nameList; } Loading @@ -479,7 +478,8 @@ public class BluetoothPbapVcardManager { long primaryVcMsb = 0; ArrayList<String> list = new ArrayList<String>(); try { callCursor = mResolver.query(myUri, null, selection, null, null); callCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, null, selection, null, null); while (callCursor != null && callCursor.moveToNext()) { count = count + 1; } Loading Loading @@ -522,7 +522,8 @@ public class BluetoothPbapVcardManager { long endPointId = 0; try { // Need test to see if order by _ID is ok here, or by date? callsCursor = mResolver.query(myUri, CALLLOG_PROJECTION, typeSelection, null, callsCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, CALLLOG_PROJECTION, typeSelection, null, CALLLOG_SORT_ORDER); if (callsCursor != null) { callsCursor.moveToPosition(startPoint - 1); Loading Loading @@ -595,7 +596,8 @@ public class BluetoothPbapVcardManager { } try { contactCursor = mResolver.query(myUri, PHONES_CONTACTS_PROJECTION, selectionClause, contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, PHONES_CONTACTS_PROJECTION, selectionClause, null, Phone.CONTACT_ID); if (contactCursor != null) { contactIdCursor = Loading Loading @@ -638,7 +640,8 @@ public class BluetoothPbapVcardManager { if (orderByWhat == BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL) { orderBy = Phone.DISPLAY_NAME; } contactCursor = mResolver.query(myUri, PHONES_CONTACTS_PROJECTION, null, null, orderBy); contactCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(mResolver, myUri, PHONES_CONTACTS_PROJECTION, null, null, orderBy); } catch (CursorWindowAllocationException e) { Log.e(TAG, "CursorWindowAllocationException while composing phonebook one vcard"); } finally { Loading Loading @@ -1013,7 +1016,8 @@ public class BluetoothPbapVcardManager { } public String stripTelephoneNumber(String vCard) { String[] attr = vCard.split(System.getProperty("line.separator")); String separator = System.getProperty("line.separator"); String[] attr = vCard.split(separator); String stripedVCard = ""; for (int i = 0; i < attr.length; i++) { if (attr[i].startsWith("TEL")) { Loading @@ -1036,7 +1040,7 @@ public class BluetoothPbapVcardManager { for (int i = 0; i < attr.length; i++) { if (!attr[i].isEmpty()) { stripedVCard = stripedVCard.concat(attr[i] + "\n"); stripedVCard = stripedVCard.concat(attr[i] + separator); } } if (V) { Loading @@ -1045,6 +1049,7 @@ public class BluetoothPbapVcardManager { return stripedVCard; } // TODO: Merge this class with BluetoothPbapSimVcardManager.HandlerForStringBuffer /** * Handler to emit vCards to PCE. */ Loading
android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapSimVcardManagerTest.java +8 −8 Original line number Diff line number Diff line Loading @@ -204,8 +204,8 @@ public class BluetoothPbapSimVcardManagerTest { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { currentPosition.getAndAdd(1); return true; int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(anyInt())).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); Loading Loading @@ -254,8 +254,8 @@ public class BluetoothPbapSimVcardManagerTest { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { currentPosition.getAndAdd(1); return true; int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(anyInt())).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); Loading Loading @@ -289,8 +289,8 @@ public class BluetoothPbapSimVcardManagerTest { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { currentPosition.getAndAdd(1); return true; int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(anyInt())).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); Loading Loading @@ -328,8 +328,8 @@ public class BluetoothPbapSimVcardManagerTest { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { currentPosition.getAndAdd(1); return true; int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(BluetoothPbapSimVcardManager.NAME_COLUMN_INDEX)).then( (Answer<String>) i -> { Loading
android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapVcardManagerTest.java 0 → 100644 +336 −0 Original line number Diff line number Diff line /* * Copyright 2022 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.bluetooth.pbap; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.provider.CallLog; import android.provider.ContactsContract; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.R; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import org.mockito.stubbing.Answer; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @SmallTest @RunWith(AndroidJUnit4.class) public class BluetoothPbapVcardManagerTest { private static final String TAG = BluetoothPbapVcardManagerTest.class.getSimpleName(); @Spy BluetoothPbapMethodProxy mPbapMethodProxy = BluetoothPbapMethodProxy.getInstance(); Context mContext; BluetoothPbapVcardManager mManager; @Before public void setUp() { MockitoAnnotations.initMocks(this); BluetoothPbapMethodProxy.setInstanceForTesting(mPbapMethodProxy); mContext = InstrumentationRegistry.getTargetContext(); mManager = new BluetoothPbapVcardManager(mContext); } @After public void tearDown() { BluetoothPbapMethodProxy.setInstanceForTesting(null); } @Test public void testGetOwnerPhoneNumberVcard_whenUseProfileForOwnerVcard() { BluetoothPbapConfig.setIncludePhotosInVcard(true); assertThat(mManager.getOwnerPhoneNumberVcard(/*vcardType21=*/true, /*filter=*/null)) .isNotNull(); } @Test public void testGetOwnerPhoneNumberVcard_whenNotUseProfileForOwnerVcard() { BluetoothPbapConfig.setIncludePhotosInVcard(false); assertThat(mManager.getOwnerPhoneNumberVcard(/*vcardType21=*/true, /*filter=*/null)) .isNotNull(); } @Test public void testGetPhonebookSize_whenTypeIsPhonebook() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); // 5 distinct contact IDs. final List<Integer> contactIdsWithDuplicates = Arrays.asList(0, 1, 1, 2, 2, 3, 3, 4, 4); // Implement Cursor iteration final int size = contactIdsWithDuplicates.size(); AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToPosition(anyInt())).then((Answer<Boolean>) i -> { int position = i.getArgument(0); currentPosition.set(position); return true; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getLong(anyInt())).then((Answer<Long>) i -> { return (long) contactIdsWithDuplicates.get(currentPosition.get()); }); // 5 distinct contact IDs + self (which is only included for phonebook) final int expectedSize = 5 + 1; assertThat(mManager.getPhonebookSize(BluetoothPbapObexServer.ContentType.PHONEBOOK, null)) .isEqualTo(expectedSize); } @Test public void testGetPhonebookSize_whenTypeIsFavorites() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); // 5 distinct contact IDs. final List<Integer> contactIdsWithDuplicates = Arrays.asList( 0, 1, 1, 2, // starred 2, 3, 3, 4, 4 // not starred ); // Implement Cursor iteration final int starredSize = 4; AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToPosition(anyInt())).then((Answer<Boolean>) i -> { int position = i.getArgument(0); currentPosition.set(position); return true; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < starredSize; }); when(cursor.getLong(anyInt())).then((Answer<Long>) i -> { return (long) contactIdsWithDuplicates.get(currentPosition.get()); }); // Among 4 starred contact Ids, there are 3 distinct contact IDs final int expectedSize = 3; assertThat(mManager.getPhonebookSize(BluetoothPbapObexServer.ContentType.FAVORITES, null)) .isEqualTo(expectedSize); } @Test public void testGetPhonebookSize_whenTypeIsSimPhonebook() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); final int expectedSize = 10; when(cursor.getCount()).thenReturn(expectedSize); BluetoothPbapSimVcardManager simVcardManager = mock(BluetoothPbapSimVcardManager.class); assertThat(mManager.getPhonebookSize(BluetoothPbapObexServer.ContentType.SIM_PHONEBOOK, simVcardManager)).isEqualTo(expectedSize); verify(simVcardManager).getSIMContactsSize(); } @Test public void testGetPhonebookSize_whenTypeIsHistory() { final int historySize = 10; Cursor cursor = mock(Cursor.class); when(cursor.getCount()).thenReturn(historySize); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); assertThat(mManager.getPhonebookSize( BluetoothPbapObexServer.ContentType.INCOMING_CALL_HISTORY, null)) .isEqualTo(historySize); } @Test public void testLoadCallHistoryList() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); List<String> nameList = Arrays.asList("A", "B", "", ""); List<String> numberList = Arrays.asList("0000", "1111", "2222", "3333"); List<Integer> presentationAllowedList = Arrays.asList( CallLog.Calls.PRESENTATION_ALLOWED, CallLog.Calls.PRESENTATION_ALLOWED, CallLog.Calls.PRESENTATION_ALLOWED, CallLog.Calls.PRESENTATION_UNKNOWN); // The number "3333" should not be shown. List<String> expectedResult = Arrays.asList( "A", "B", "2222", mContext.getString(R.string.unknownNumber)); // Implement Cursor iteration final int size = nameList.size(); AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToFirst()).then((Answer<Boolean>) i -> { currentPosition.set(0); return true; }); when(cursor.isAfterLast()).then((Answer<Boolean>) i -> { return currentPosition.get() >= size; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < size; }); when(cursor.getString(BluetoothPbapVcardManager.CALLS_NAME_COLUMN_INDEX)) .then((Answer<String>) i -> { return nameList.get(currentPosition.get()); }); when(cursor.getString(BluetoothPbapVcardManager.CALLS_NUMBER_COLUMN_INDEX)) .then((Answer<String>) i -> { return numberList.get(currentPosition.get()); }); when(cursor.getInt(BluetoothPbapVcardManager.CALLS_NUMBER_PRESENTATION_COLUMN_INDEX)) .then((Answer<Integer>) i -> { return presentationAllowedList.get(currentPosition.get()); }); assertThat(mManager.loadCallHistoryList( BluetoothPbapObexServer.ContentType.INCOMING_CALL_HISTORY)) .isEqualTo(expectedResult); } @Test public void testGetPhonebookNameList() { final String localPhoneName = "test_local_phone_name"; BluetoothPbapService.setLocalPhoneName(localPhoneName); Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); List<String> nameList = Arrays.asList("A", "B", "C", ""); List<Integer> contactIdList = Arrays.asList(0, 1, 2, 3); List<String> expectedResult = Arrays.asList( localPhoneName, "A,0", "B,1", "C,2", mContext.getString(android.R.string.unknownName) + ",3"); // Implement Cursor iteration final int size = nameList.size(); AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToPosition(anyInt())).then((Answer<Boolean>) i -> { int position = i.getArgument(0); currentPosition.set(position); return true; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < size; }); final int contactIdColumn = 0; final int nameColumn = 1; when(cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID)).thenReturn(contactIdColumn); when(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)).thenReturn(nameColumn); when(cursor.getLong(contactIdColumn)).then((Answer<Long>) i -> { return (long) contactIdList.get(currentPosition.get()); }); when(cursor.getString(nameColumn)).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); }); assertThat(mManager.getPhonebookNameList(BluetoothPbapObexServer.ORDER_BY_ALPHABETICAL)) .isEqualTo(expectedResult); } @Test public void testGetContactNamesByNumber_whenNumberIsNull() { Cursor cursor = mock(Cursor.class); doReturn(cursor).when(mPbapMethodProxy) .contentResolverQuery(any(), any(), any(), any(), any(), any()); List<String> nameList = Arrays.asList("A", "B", "C", ""); List<Integer> contactIdList = Arrays.asList(0, 1, 2, 3); List<String> expectedResult = Arrays.asList( "A,0", "B,1", "C,2", mContext.getString(android.R.string.unknownName) + ",3"); // Implement Cursor iteration final int size = nameList.size(); AtomicInteger currentPosition = new AtomicInteger(0); when(cursor.moveToPosition(anyInt())).then((Answer<Boolean>) i -> { int position = i.getArgument(0); currentPosition.set(position); return true; }); when(cursor.moveToNext()).then((Answer<Boolean>) i -> { int pos = currentPosition.addAndGet(1); return pos < size; }); final int contactIdColumn = 0; final int nameColumn = 1; when(cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID)).thenReturn(contactIdColumn); when(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME)).thenReturn(nameColumn); when(cursor.getLong(contactIdColumn)).then((Answer<Long>) i -> { return (long) contactIdList.get(currentPosition.get()); }); when(cursor.getString(nameColumn)).then((Answer<String>) i -> { return nameList.get(currentPosition.get()); }); assertThat(mManager.getContactNamesByNumber(null)) .isEqualTo(expectedResult); } @Test public void testStripTelephoneNumber() { final String separator = System.getProperty("line.separator"); final String vCard = "SomeRandomLine" + separator + "TEL:+1-(588)-328-382" + separator; final String expectedResult = "SomeRandomLine" + separator + "TEL:+1588328382" + separator; assertThat(mManager.stripTelephoneNumber(vCard)).isEqualTo(expectedResult); } }