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.settings.bluetooth; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyBoolean; 23 import static org.mockito.ArgumentMatchers.anyInt; 24 import static org.mockito.ArgumentMatchers.anyString; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.view.View; 30 import android.widget.Button; 31 32 import androidx.fragment.app.FragmentManager; 33 import androidx.fragment.app.FragmentTransaction; 34 35 import com.android.settings.R; 36 import com.android.settingslib.widget.ActionButtonsPreference; 37 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 import org.mockito.ArgumentCaptor; 41 import org.robolectric.RobolectricTestRunner; 42 import org.robolectric.RuntimeEnvironment; 43 44 @RunWith(RobolectricTestRunner.class) 45 public class BluetoothDetailsButtonsControllerTest extends BluetoothDetailsControllerTestBase { 46 private BluetoothDetailsButtonsController mController; 47 private ActionButtonsPreference mButtonsPref; 48 private Button mConnectButton; 49 private Button mForgetButton; 50 51 @Override setUp()52 public void setUp() { 53 super.setUp(); 54 final View buttons = View.inflate( 55 RuntimeEnvironment.application, R.layout.settingslib_action_buttons, 56 null /* parent */); 57 mConnectButton = buttons.findViewById(R.id.button2); 58 mForgetButton = buttons.findViewById(R.id.button1); 59 mController = 60 new BluetoothDetailsButtonsController(mContext, mFragment, mCachedDevice, 61 mLifecycle); 62 mButtonsPref = createMock(); 63 when(mButtonsPref.getKey()).thenReturn(mController.getPreferenceKey()); 64 when(mButtonsPref.setButton2OnClickListener(any(View.OnClickListener.class))) 65 .thenAnswer(invocation -> { 66 final Object[] args = invocation.getArguments(); 67 mConnectButton.setOnClickListener((View.OnClickListener) args[0]); 68 return mButtonsPref; 69 }); 70 when(mButtonsPref.setButton1OnClickListener(any(View.OnClickListener.class))) 71 .thenAnswer(invocation -> { 72 final Object[] args = invocation.getArguments(); 73 mForgetButton.setOnClickListener((View.OnClickListener) args[0]); 74 return mButtonsPref; 75 }); 76 mScreen.addPreference(mButtonsPref); 77 setupDevice(mDeviceConfig); 78 when(mCachedDevice.isBusy()).thenReturn(false); 79 } 80 81 @Test connected()82 public void connected() { 83 showScreen(mController); 84 85 verify(mButtonsPref).setButton2Text(R.string.bluetooth_device_context_disconnect); 86 verify(mButtonsPref).setButton1Text(R.string.forget); 87 } 88 89 @Test clickOnDisconnect()90 public void clickOnDisconnect() { 91 showScreen(mController); 92 mConnectButton.callOnClick(); 93 94 verify(mCachedDevice).disconnect(); 95 } 96 97 @Test clickOnConnect()98 public void clickOnConnect() { 99 when(mCachedDevice.isConnected()).thenReturn(false); 100 showScreen(mController); 101 102 verify(mButtonsPref).setButton2Text(R.string.bluetooth_device_context_connect); 103 104 mConnectButton.callOnClick(); 105 verify(mCachedDevice).connect(); 106 } 107 108 @Test becomeDisconnected()109 public void becomeDisconnected() { 110 showScreen(mController); 111 // By default we start out with the device connected. 112 verify(mButtonsPref).setButton2Text(R.string.bluetooth_device_context_disconnect); 113 114 // Now make the device appear to have changed to disconnected. 115 when(mCachedDevice.isConnected()).thenReturn(false); 116 mController.onDeviceAttributesChanged(); 117 verify(mButtonsPref).setButton2Text(R.string.bluetooth_device_context_connect); 118 119 // Click the button and make sure that connect (not disconnect) gets called. 120 mConnectButton.callOnClick(); 121 verify(mCachedDevice).connect(); 122 } 123 124 @Test becomeConnected()125 public void becomeConnected() { 126 // Start out with the device disconnected. 127 when(mCachedDevice.isConnected()).thenReturn(false); 128 showScreen(mController); 129 130 verify(mButtonsPref).setButton2Text(R.string.bluetooth_device_context_connect); 131 132 133 // Now make the device appear to have changed to connected. 134 when(mCachedDevice.isConnected()).thenReturn(true); 135 mController.onDeviceAttributesChanged(); 136 verify(mButtonsPref).setButton2Text(R.string.bluetooth_device_context_disconnect); 137 138 // Click the button and make sure that disconnect (not connect) gets called. 139 mConnectButton.callOnClick(); 140 verify(mCachedDevice).disconnect(); 141 } 142 143 @Test forgetDialog()144 public void forgetDialog() { 145 showScreen(mController); 146 FragmentManager fragmentManager = mock(FragmentManager.class); 147 when(mFragment.getFragmentManager()).thenReturn(fragmentManager); 148 FragmentTransaction ft = mock(FragmentTransaction.class); 149 when(fragmentManager.beginTransaction()).thenReturn(ft); 150 mForgetButton.callOnClick(); 151 152 ArgumentCaptor<ForgetDeviceDialogFragment> dialogCaptor = 153 ArgumentCaptor.forClass(ForgetDeviceDialogFragment.class); 154 verify(ft).add(dialogCaptor.capture(), anyString()); 155 156 ForgetDeviceDialogFragment dialogFragment = dialogCaptor.getValue(); 157 assertThat(dialogFragment).isNotNull(); 158 } 159 160 @Test startsOutBusy()161 public void startsOutBusy() { 162 when(mCachedDevice.isBusy()).thenReturn(true); 163 showScreen(mController); 164 165 verify(mButtonsPref).setButton2Text(R.string.bluetooth_device_context_disconnect); 166 verify(mButtonsPref).setButton2Enabled(false); 167 verify(mButtonsPref).setButton1Text(R.string.forget); 168 169 // Now pretend the device became non-busy. 170 when(mCachedDevice.isBusy()).thenReturn(false); 171 mController.onDeviceAttributesChanged(); 172 173 verify(mButtonsPref).setButton2Enabled(true); 174 } 175 176 @Test becomesBusy()177 public void becomesBusy() { 178 showScreen(mController); 179 verify(mButtonsPref).setButton2Enabled(true); 180 181 // Now pretend the device became busy. 182 when(mCachedDevice.isBusy()).thenReturn(true); 183 mController.onDeviceAttributesChanged(); 184 185 verify(mButtonsPref).setButton2Enabled(false); 186 } 187 createMock()188 private ActionButtonsPreference createMock() { 189 final ActionButtonsPreference pref = mock(ActionButtonsPreference.class); 190 when(pref.setButton1Text(anyInt())).thenReturn(pref); 191 when(pref.setButton1Icon(anyInt())).thenReturn(pref); 192 when(pref.setButton1Enabled(anyBoolean())).thenReturn(pref); 193 when(pref.setButton1Visible(anyBoolean())).thenReturn(pref); 194 when(pref.setButton1OnClickListener(any(View.OnClickListener.class))).thenReturn(pref); 195 196 when(pref.setButton2Text(anyInt())).thenReturn(pref); 197 when(pref.setButton2Icon(anyInt())).thenReturn(pref); 198 when(pref.setButton2Enabled(anyBoolean())).thenReturn(pref); 199 when(pref.setButton2Visible(anyBoolean())).thenReturn(pref); 200 when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref); 201 202 return pref; 203 } 204 } 205