1 /* 2 * Copyright (C) 2022 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.opp; 18 19 import static androidx.test.espresso.intent.Intents.intended; 20 import static androidx.test.espresso.intent.Intents.intending; 21 import static androidx.test.espresso.intent.matcher.IntentMatchers.anyIntent; 22 23 import static com.android.bluetooth.TestUtils.getTestDevice; 24 import static com.android.bluetooth.opp.BluetoothOppManager.ALLOWED_INSERT_SHARE_THREAD_NUMBER; 25 import static com.android.bluetooth.opp.BluetoothOppManager.OPP_PREFERENCE_FILE; 26 27 import static com.google.common.truth.Truth.assertThat; 28 29 import static org.mockito.Mockito.any; 30 import static org.mockito.Mockito.doReturn; 31 import static org.mockito.Mockito.eq; 32 import static org.mockito.Mockito.nullable; 33 import static org.mockito.Mockito.spy; 34 import static org.mockito.Mockito.timeout; 35 import static org.mockito.Mockito.verify; 36 37 import android.bluetooth.BluetoothDevice; 38 import android.content.ContentValues; 39 import android.content.Context; 40 import android.content.ContextWrapper; 41 import android.net.Uri; 42 43 import androidx.test.espresso.intent.Intents; 44 import androidx.test.platform.app.InstrumentationRegistry; 45 import androidx.test.runner.AndroidJUnit4; 46 47 import com.android.bluetooth.BluetoothMethodProxy; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Ignore; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 55 import java.util.ArrayList; 56 import java.util.List; 57 import java.util.concurrent.atomic.AtomicBoolean; 58 59 /** Test cases for {@link BluetoothOppManager}. */ 60 @RunWith(AndroidJUnit4.class) 61 public class BluetoothOppManagerTest { 62 Context mContext; 63 64 BluetoothMethodProxy mCallProxy; 65 66 @Before setUp()67 public void setUp() { 68 mContext = 69 spy( 70 new ContextWrapper( 71 InstrumentationRegistry.getInstrumentation().getTargetContext())); 72 73 mCallProxy = spy(BluetoothMethodProxy.getInstance()); 74 BluetoothMethodProxy.setInstanceForTesting(mCallProxy); 75 76 doReturn(null) 77 .when(mCallProxy) 78 .contentResolverInsert(any(), eq(BluetoothShare.CONTENT_URI), any()); 79 80 Intents.init(); 81 } 82 83 @After tearDown()84 public void tearDown() { 85 BluetoothMethodProxy.setInstanceForTesting(null); 86 BluetoothOppUtility.sSendFileMap.clear(); 87 mContext.getSharedPreferences(OPP_PREFERENCE_FILE, 0).edit().clear().apply(); 88 BluetoothOppManager.sInstance = null; 89 90 Intents.release(); 91 } 92 93 @Test 94 public void restoreApplicationData_afterSavingSingleSendingFileInfo_containsSendingFileInfoSaved()95 restoreApplicationData_afterSavingSingleSendingFileInfo_containsSendingFileInfoSaved() { 96 BluetoothOppManager bluetoothOppManager = BluetoothOppManager.getInstance(mContext); 97 bluetoothOppManager.mSendingFlag = true; 98 bluetoothOppManager.saveSendingFileInfo( 99 "text/plain", "content:///abc/xyz.txt", false, true); 100 101 BluetoothOppManager.sInstance = null; 102 BluetoothOppManager restartedBluetoothOppManager = 103 BluetoothOppManager.getInstance(mContext); 104 assertThat(bluetoothOppManager.mSendingFlag) 105 .isEqualTo(restartedBluetoothOppManager.mSendingFlag); 106 assertThat(bluetoothOppManager.mMultipleFlag) 107 .isEqualTo(restartedBluetoothOppManager.mMultipleFlag); 108 assertThat(bluetoothOppManager.mUriOfSendingFile) 109 .isEqualTo(restartedBluetoothOppManager.mUriOfSendingFile); 110 assertThat(bluetoothOppManager.mUrisOfSendingFiles) 111 .isEqualTo(restartedBluetoothOppManager.mUrisOfSendingFiles); 112 assertThat(bluetoothOppManager.mMimeTypeOfSendingFile) 113 .isEqualTo(restartedBluetoothOppManager.mMimeTypeOfSendingFile); 114 assertThat(bluetoothOppManager.mMimeTypeOfSendingFiles) 115 .isEqualTo(restartedBluetoothOppManager.mMimeTypeOfSendingFiles); 116 } 117 118 @Test 119 public void restoreApplicationData_afterSavingMultipleSendingFileInfo_containsSendingFileInfoSaved()120 restoreApplicationData_afterSavingMultipleSendingFileInfo_containsSendingFileInfoSaved() { 121 BluetoothOppManager bluetoothOppManager = BluetoothOppManager.getInstance(mContext); 122 bluetoothOppManager.mSendingFlag = true; 123 bluetoothOppManager.saveSendingFileInfo( 124 "text/plain", 125 new ArrayList<Uri>( 126 List.of( 127 Uri.parse("content:///abc/xyz.txt"), 128 Uri.parse("content:///123" + "/456.txt"))), 129 false, 130 true); 131 132 BluetoothOppManager.sInstance = null; 133 BluetoothOppManager restartedBluetoothOppManager = 134 BluetoothOppManager.getInstance(mContext); 135 assertThat(bluetoothOppManager.mSendingFlag) 136 .isEqualTo(restartedBluetoothOppManager.mSendingFlag); 137 assertThat(bluetoothOppManager.mMultipleFlag) 138 .isEqualTo(restartedBluetoothOppManager.mMultipleFlag); 139 assertThat(bluetoothOppManager.mUriOfSendingFile) 140 .isEqualTo(restartedBluetoothOppManager.mUriOfSendingFile); 141 assertThat(bluetoothOppManager.mUrisOfSendingFiles) 142 .isEqualTo(restartedBluetoothOppManager.mUrisOfSendingFiles); 143 assertThat(bluetoothOppManager.mMimeTypeOfSendingFile) 144 .isEqualTo(restartedBluetoothOppManager.mMimeTypeOfSendingFile); 145 assertThat(bluetoothOppManager.mMimeTypeOfSendingFiles) 146 .isEqualTo(restartedBluetoothOppManager.mMimeTypeOfSendingFiles); 147 } 148 149 @Test isAcceptedList_inAcceptList_returnsTrue()150 public void isAcceptedList_inAcceptList_returnsTrue() { 151 BluetoothOppManager bluetoothOppManager = BluetoothOppManager.getInstance(mContext); 152 String address1 = "AA:BB:CC:DD:EE:FF"; 153 String address2 = "00:11:22:33:44:55"; 154 155 bluetoothOppManager.addToAcceptlist(address1); 156 bluetoothOppManager.addToAcceptlist(address2); 157 assertThat(bluetoothOppManager.isAcceptListed(address1)).isTrue(); 158 assertThat(bluetoothOppManager.isAcceptListed(address2)).isTrue(); 159 } 160 161 @Test isAcceptedList_notInAcceptList_returnsFalse()162 public void isAcceptedList_notInAcceptList_returnsFalse() { 163 BluetoothOppManager bluetoothOppManager = BluetoothOppManager.getInstance(mContext); 164 String address = "01:23:45:67:89:AB"; 165 166 assertThat(bluetoothOppManager.isAcceptListed(address)).isFalse(); 167 168 bluetoothOppManager.addToAcceptlist(address); 169 assertThat(bluetoothOppManager.isAcceptListed(address)).isTrue(); 170 } 171 172 @Test startTransfer_withMultipleUris_contentResolverInsertMultipleTimes()173 public void startTransfer_withMultipleUris_contentResolverInsertMultipleTimes() { 174 BluetoothOppManager bluetoothOppManager = BluetoothOppManager.getInstance(mContext); 175 bluetoothOppManager.saveSendingFileInfo( 176 "text/plain", 177 new ArrayList<Uri>( 178 List.of( 179 Uri.parse("content:///abc/xyz.txt"), 180 Uri.parse("content:///a/b/c/d/x/y/z.docs"), 181 Uri.parse("content:///123/456.txt"))), 182 false, 183 true); 184 BluetoothDevice device = getTestDevice(56); 185 bluetoothOppManager.startTransfer(device); 186 // add 2 files 187 verify(mCallProxy, timeout(5_000).times(3)) 188 .contentResolverInsert(any(), nullable(Uri.class), nullable(ContentValues.class)); 189 } 190 191 @Test startTransfer_withOneUri_contentResolverInsertOnce()192 public void startTransfer_withOneUri_contentResolverInsertOnce() { 193 BluetoothOppManager bluetoothOppManager = BluetoothOppManager.getInstance(mContext); 194 bluetoothOppManager.saveSendingFileInfo( 195 "text/plain", "content:///abc/xyz.txt", false, true); 196 BluetoothDevice device = getTestDevice(34); 197 bluetoothOppManager.startTransfer(device); 198 verify(mCallProxy, timeout(5_000).times(1)) 199 .contentResolverInsert(any(), nullable(Uri.class), nullable(ContentValues.class)); 200 } 201 202 @Ignore("b/267270055") 203 @Test startTransferMoreThanAllowedInsertShareThreadNumberTimes_blockExceedingTransfer()204 public void startTransferMoreThanAllowedInsertShareThreadNumberTimes_blockExceedingTransfer() 205 throws InterruptedException { 206 BluetoothOppManager bluetoothOppManager = BluetoothOppManager.getInstance(mContext); 207 bluetoothOppManager.saveSendingFileInfo( 208 "text/plain", "content:///abc/xyz.txt", false, true); 209 BluetoothDevice device = getTestDevice(72); 210 211 AtomicBoolean intended = new AtomicBoolean(false); 212 intending(anyIntent()) 213 .respondWithFunction( 214 intent -> { 215 // verify that at least one exceeding thread is blocked 216 intended.set(true); 217 return null; 218 }); 219 220 // try flushing the transferring queue, 221 for (int i = 0; i < ALLOWED_INSERT_SHARE_THREAD_NUMBER + 15; i++) { 222 bluetoothOppManager.startTransfer(device); 223 } 224 225 // success at least ALLOWED_INSERT_SHARE_THREAD_NUMBER times 226 verify(mCallProxy, timeout(5_000).atLeast(ALLOWED_INSERT_SHARE_THREAD_NUMBER)) 227 .contentResolverInsert(any(), nullable(Uri.class), nullable(ContentValues.class)); 228 229 // there is at least a failed attempt 230 assertThat(intended.get()).isTrue(); 231 } 232 233 @Test isEnabled()234 public void isEnabled() { 235 BluetoothOppManager bluetoothOppManager = BluetoothOppManager.getInstance(mContext); 236 doReturn(true).when(mCallProxy).bluetoothAdapterIsEnabled(any()); 237 assertThat(bluetoothOppManager.isEnabled()).isTrue(); 238 doReturn(false).when(mCallProxy).bluetoothAdapterIsEnabled(any()); 239 assertThat(bluetoothOppManager.isEnabled()).isFalse(); 240 } 241 242 @Test cleanUpSendingFileInfo_fileInfoCleaned()243 public void cleanUpSendingFileInfo_fileInfoCleaned() { 244 BluetoothOppUtility.sSendFileMap.clear(); 245 Uri uri = Uri.parse("content:///a/new/folder/abc/xyz.txt"); 246 assertThat(BluetoothOppUtility.sSendFileMap).isEmpty(); 247 BluetoothOppManager.getInstance(mContext) 248 .saveSendingFileInfo("text/plain", uri.toString(), false, true); 249 assertThat(BluetoothOppUtility.sSendFileMap).hasSize(1); 250 251 BluetoothOppManager.getInstance(mContext).cleanUpSendingFileInfo(); 252 assertThat(BluetoothOppUtility.sSendFileMap).isEmpty(); 253 } 254 } 255