1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.pbapclient; 18 19 import android.accounts.Account; 20 import android.content.Context; 21 import android.content.pm.PackageManager; 22 import android.content.res.Resources; 23 import android.database.Cursor; 24 import android.net.Uri; 25 import android.provider.CallLog.Calls; 26 import android.provider.ContactsContract; 27 28 import androidx.test.InstrumentationRegistry; 29 import androidx.test.filters.MediumTest; 30 import androidx.test.runner.AndroidJUnit4; 31 32 import com.android.bluetooth.R; 33 34 import org.junit.Assert; 35 import org.junit.Assume; 36 import org.junit.Before; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.io.IOException; 41 import java.io.InputStream; 42 import java.util.HashMap; 43 import java.util.TimeZone; 44 45 @MediumTest 46 @RunWith(AndroidJUnit4.class) 47 public class PbapParserTest { 48 private Account mAccount; 49 private Resources mTestResources; 50 private Context mTargetContext; 51 private static final String TEST_ACCOUNT_NAME = "PBAPTESTACCOUNT"; 52 private static final String TEST_PACKAGE_NAME = "com.android.bluetooth.tests"; 53 54 @Before setUp()55 public void setUp() { 56 mTargetContext = InstrumentationRegistry.getTargetContext(); 57 Assume.assumeTrue("Ignore test when PbapClientService is not enabled", 58 mTargetContext.getResources().getBoolean(R.bool.profile_supported_pbapclient)); 59 mAccount = new Account(TEST_ACCOUNT_NAME, 60 mTargetContext.getString(com.android.bluetooth.R.string.pbap_account_type)); 61 try { 62 mTestResources = mTargetContext.getPackageManager() 63 .getResourcesForApplication(TEST_PACKAGE_NAME); 64 } catch (PackageManager.NameNotFoundException e) { 65 Assert.fail("Setup Failure Unable to get resources" + e.toString()); 66 } 67 cleanupCallLog(); 68 cleanupPhonebook(); 69 } 70 71 // testNoTimestamp should parse 1 poorly formed vcard and not crash. 72 @Test testNoTimestamp()73 public void testNoTimestamp() throws IOException { 74 InputStream fileStream; 75 fileStream = mTestResources.openRawResource( 76 com.android.bluetooth.tests.R.raw.no_timestamp_call_log); 77 BluetoothPbapVcardList pbapVCardList = new BluetoothPbapVcardList(mAccount, fileStream, 78 PbapClientConnectionHandler.VCARD_TYPE_30); 79 Assert.assertEquals(1, pbapVCardList.getCount()); 80 CallLogPullRequest processor = 81 new CallLogPullRequest(mTargetContext, PbapClientConnectionHandler.MCH_PATH, 82 new HashMap<>(), mAccount); 83 processor.setResults(pbapVCardList.getList()); 84 85 // Verify that these entries aren't in the call log to start. 86 Assert.assertFalse(verifyCallLog("555-0001", null, "3")); 87 88 // Finish processing the data and verify entries were added to the call log. 89 processor.onPullComplete(); 90 Assert.assertTrue(verifyCallLog("555-0001", null, "3")); 91 } 92 93 // testMissedCall should parse one phonecall correctly. 94 @Test testMissedCall()95 public void testMissedCall() throws IOException { 96 InputStream fileStream; 97 fileStream = mTestResources.openRawResource( 98 com.android.bluetooth.tests.R.raw.single_missed_call); 99 BluetoothPbapVcardList pbapVCardList = new BluetoothPbapVcardList(mAccount, fileStream, 100 PbapClientConnectionHandler.VCARD_TYPE_30); 101 Assert.assertEquals(1, pbapVCardList.getCount()); 102 CallLogPullRequest processor = 103 new CallLogPullRequest(mTargetContext, PbapClientConnectionHandler.MCH_PATH, 104 new HashMap<>(), mAccount); 105 processor.setResults(pbapVCardList.getList()); 106 107 // Verify that these entries aren't in the call log to start. 108 Assert.assertFalse(verifyCallLog("555-0002", "1483232460000", "3")); 109 // Finish processing the data and verify entries were added to the call log. 110 processor.onPullComplete(); 111 Assert.assertTrue(verifyCallLog("555-0002", "1483232460000", "3")); 112 } 113 114 // testUnknownCall should parse two calls with no phone number. 115 @Test testUnknownCall()116 public void testUnknownCall() throws IOException { 117 InputStream fileStream; 118 fileStream = mTestResources.openRawResource( 119 com.android.bluetooth.tests.R.raw.unknown_number_call); 120 BluetoothPbapVcardList pbapVCardList = new BluetoothPbapVcardList(mAccount, fileStream, 121 PbapClientConnectionHandler.VCARD_TYPE_30); 122 Assert.assertEquals(2, pbapVCardList.getCount()); 123 CallLogPullRequest processor = 124 new CallLogPullRequest(mTargetContext, PbapClientConnectionHandler.MCH_PATH, 125 new HashMap<>(), mAccount); 126 processor.setResults(pbapVCardList.getList()); 127 128 // Verify that these entries aren't in the call log to start. 129 Assert.assertFalse(verifyCallLog("", "1483232520000", "3")); 130 Assert.assertFalse(verifyCallLog("", "1483232580000", "3")); 131 132 // Finish processing the data and verify entries were added to the call log. 133 processor.onPullComplete(); 134 Assert.assertTrue(verifyCallLog("", "1483232520000", "3")); 135 Assert.assertTrue(verifyCallLog("", "1483232580000", "3")); 136 } 137 138 @Test testPullPhoneBook()139 public void testPullPhoneBook() throws IOException { 140 InputStream fileStream; 141 fileStream = mTestResources.openRawResource( 142 com.android.bluetooth.tests.R.raw.v30_simple); 143 BluetoothPbapVcardList pbapVCardList = new BluetoothPbapVcardList(mAccount, fileStream, 144 PbapClientConnectionHandler.VCARD_TYPE_30); 145 Assert.assertEquals(1, pbapVCardList.getCount()); 146 PhonebookPullRequest processor = new PhonebookPullRequest(mTargetContext, mAccount); 147 processor.setResults(pbapVCardList.getList()); 148 Assert.assertFalse(verifyPhonebook("Roid And", "0300000000")); 149 processor.onPullComplete(); 150 Assert.assertTrue(verifyPhonebook("Roid And", "0300000000")); 151 } 152 cleanupCallLog()153 private void cleanupCallLog() { 154 mTargetContext.getContentResolver().delete(Calls.CONTENT_URI, null, null); 155 } 156 cleanupPhonebook()157 private void cleanupPhonebook() { 158 mTargetContext.getContentResolver().delete(ContactsContract.RawContacts.CONTENT_URI, 159 null, null); 160 } 161 162 // Find Entries in call log with type matching number and date. 163 // If number or date is null it will match any number or date respectively. verifyCallLog(String number, String date, String type)164 private boolean verifyCallLog(String number, String date, String type) { 165 String[] query = new String[]{Calls.NUMBER, Calls.DATE, Calls.TYPE}; 166 Cursor cursor = mTargetContext.getContentResolver() 167 .query(Calls.CONTENT_URI, query, Calls.TYPE + "= " + type, null, 168 Calls.DATE + ", " + Calls.NUMBER); 169 if (date != null) { 170 date = adjDate(date); 171 } 172 if (cursor != null) { 173 while (cursor.moveToNext()) { 174 String foundNumber = cursor.getString(cursor.getColumnIndex(Calls.NUMBER)); 175 String foundDate = cursor.getString(cursor.getColumnIndex(Calls.DATE)); 176 if ((number == null || number.equals(foundNumber)) && (date == null || date.equals( 177 foundDate))) { 178 return true; 179 } 180 } 181 cursor.close(); 182 } 183 return false; 184 } 185 186 // Get time zone from device and adjust date to the device's time zone. adjDate(String date)187 private static String adjDate(String date) { 188 TimeZone tz = TimeZone.getDefault(); 189 long dt = Long.valueOf(date) - tz.getRawOffset(); 190 return Long.toString(dt); 191 } 192 verifyPhonebook(String name, String number)193 private boolean verifyPhonebook(String name, String number) { 194 Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, 195 Uri.encode(number)); 196 Cursor c = mTargetContext.getContentResolver().query(uri, null, null, null); 197 if (c != null && c.getCount() > 0) { 198 c.moveToNext(); 199 String displayName = c.getString( 200 c.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME)); 201 if (displayName.equals(name)) { 202 return true; 203 } 204 } 205 return false; 206 } 207 208 } 209