1 /* 2 * Copyright (C) 2021 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.car.settings.common; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.annotation.Nullable; 22 import android.car.drivingstate.CarUxRestrictions; 23 24 import androidx.fragment.app.Fragment; 25 import androidx.preference.Preference; 26 import androidx.test.platform.app.InstrumentationRegistry; 27 import androidx.test.rule.ActivityTestRule; 28 29 import com.android.car.settings.R; 30 import com.android.car.settings.testutils.BaseTestSettingsFragment; 31 import com.android.car.settings.testutils.DualPaneTestActivity; 32 import com.android.car.settings.testutils.EmptySettingsFragment; 33 import com.android.car.settings.testutils.TestTopLevelMenuFragment; 34 import com.android.car.ui.toolbar.Toolbar; 35 import com.android.car.ui.toolbar.ToolbarController; 36 37 import org.junit.Rule; 38 import org.junit.Test; 39 40 import java.util.concurrent.atomic.AtomicReference; 41 42 public class DualPaneBaseCarSettingsActivityTest 43 extends BaseCarSettingsActivityTestCase<DualPaneTestActivity> { 44 45 @Rule 46 public ActivityTestRule<DualPaneTestActivity> mActivityTestRule = 47 new ActivityTestRule<>(DualPaneTestActivity.class); 48 49 @Override getActivityTestRule()50 ActivityTestRule<DualPaneTestActivity> getActivityTestRule() { 51 return mActivityTestRule; 52 } 53 54 @Test onPreferenceStartFragment_launchesFragment()55 public void onPreferenceStartFragment_launchesFragment() throws Throwable { 56 Preference pref = new Preference(mContext); 57 pref.setFragment(BaseTestSettingsFragment.class.getName()); 58 59 mActivityTestRule.runOnUiThread(() -> 60 mActivity.onPreferenceStartFragment(/* caller= */ null, pref)); 61 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 62 63 assertThat(mActivity.getSupportFragmentManager().findFragmentById( 64 R.id.fragment_container)).isInstanceOf(BaseTestSettingsFragment.class); 65 } 66 67 @Test onUxRestrictionsChanged_topFragmentInBackStackHasUpdatedUxRestrictions()68 public void onUxRestrictionsChanged_topFragmentInBackStackHasUpdatedUxRestrictions() 69 throws Throwable { 70 CarUxRestrictions oldUxRestrictions = new CarUxRestrictions.Builder( 71 /* reqOpt= */ true, 72 CarUxRestrictions.UX_RESTRICTIONS_BASELINE, 73 /* timestamp= */ 0 74 ).build(); 75 76 CarUxRestrictions newUxRestrictions = new CarUxRestrictions.Builder( 77 /* reqOpt= */ true, 78 CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, 79 /* timestamp= */ 0 80 ).build(); 81 82 AtomicReference<BaseTestSettingsFragment> fragmentA = new AtomicReference<>(); 83 AtomicReference<BaseTestSettingsFragment> fragmentB = new AtomicReference<>(); 84 85 mActivityTestRule.runOnUiThread(() -> { 86 fragmentA.set(new BaseTestSettingsFragment()); 87 fragmentB.set(new BaseTestSettingsFragment()); 88 mActivity.launchFragment(fragmentA.get()); 89 mActivity.onUxRestrictionsChanged(oldUxRestrictions); 90 mActivity.launchFragment(fragmentB.get()); 91 mActivity.onUxRestrictionsChanged(newUxRestrictions); 92 }); 93 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 94 95 assertThat( 96 fragmentB.get().getUxRestrictions().isSameRestrictions(newUxRestrictions)).isTrue(); 97 } 98 99 @Test onBackStackChanged_uxRestrictionsChanged_currentFragmentHasUpdatedUxRestrictions()100 public void onBackStackChanged_uxRestrictionsChanged_currentFragmentHasUpdatedUxRestrictions() 101 throws Throwable { 102 CarUxRestrictions oldUxRestrictions = new CarUxRestrictions.Builder( 103 /* reqOpt= */ true, 104 CarUxRestrictions.UX_RESTRICTIONS_BASELINE, 105 /* timestamp= */ 0 106 ).build(); 107 108 CarUxRestrictions newUxRestrictions = new CarUxRestrictions.Builder( 109 /* reqOpt= */ true, 110 CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, 111 /* timestamp= */ 0 112 ).build(); 113 114 AtomicReference<BaseTestSettingsFragment> fragmentA = new AtomicReference<>(); 115 AtomicReference<BaseTestSettingsFragment> fragmentB = new AtomicReference<>(); 116 117 mActivityTestRule.runOnUiThread(() -> { 118 fragmentA.set(new BaseTestSettingsFragment()); 119 fragmentB.set(new BaseTestSettingsFragment()); 120 mActivity.launchFragment(fragmentA.get()); 121 mActivity.onUxRestrictionsChanged(oldUxRestrictions); 122 mActivity.launchFragment(fragmentB.get()); 123 mActivity.onUxRestrictionsChanged(newUxRestrictions); 124 mActivity.goBack(); 125 }); 126 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 127 128 assertThat( 129 fragmentA.get().getUxRestrictions().isSameRestrictions(newUxRestrictions)).isTrue(); 130 } 131 132 @Test onBackStackChanged_toolbarUpdated()133 public void onBackStackChanged_toolbarUpdated() throws Throwable { 134 ToolbarController toolbar = mActivity.getToolbar(); 135 136 mActivityTestRule.runOnUiThread(() -> { 137 BaseTestSettingsFragment fragment1 = new BaseTestSettingsFragment(); 138 mActivity.launchFragment(fragment1); 139 }); 140 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 141 142 assertThat(toolbar.getNavButtonMode()).isEquivalentAccordingToCompareTo( 143 Toolbar.NavButtonMode.DISABLED); 144 145 mActivityTestRule.runOnUiThread(() -> { 146 BaseTestSettingsFragment fragment2 = new BaseTestSettingsFragment(); 147 mActivity.launchFragment(fragment2); 148 }); 149 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 150 151 assertThat(toolbar.getNavButtonMode()).isEqualTo(Toolbar.NavButtonMode.BACK); 152 153 mActivityTestRule.runOnUiThread(() -> mActivity.goBack()); 154 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 155 156 assertThat(toolbar.getNavButtonMode()).isEquivalentAccordingToCompareTo( 157 Toolbar.NavButtonMode.DISABLED); 158 } 159 160 @Test onActivityCreated_noFragment_topLevelMenuFocused()161 public void onActivityCreated_noFragment_topLevelMenuFocused() throws Throwable { 162 assertThat(mActivity.findViewById(R.id.top_level_menu).hasFocus()).isTrue(); 163 } 164 165 @Test onActivityCreated_homepage_topLevelMenuFocused()166 public void onActivityCreated_homepage_topLevelMenuFocused() throws Throwable { 167 ActivityTestRule<TestDualPaneHomepageActivity> activityTestRule = 168 new ActivityTestRule<>(TestDualPaneHomepageActivity.class); 169 activityTestRule.launchActivity(null); 170 mActivity = activityTestRule.getActivity(); 171 mFragmentManager = activityTestRule.getActivity().getSupportFragmentManager(); 172 173 assertThat(mActivity.findViewById(R.id.top_level_menu).hasFocus()).isTrue(); 174 } 175 176 @Test onActivityCreated_hasFragment_contentFocused()177 public void onActivityCreated_hasFragment_contentFocused() throws Throwable { 178 ActivityTestRule<TestDualPaneFragmentActivity> activityTestRule = 179 new ActivityTestRule<>(TestDualPaneFragmentActivity.class); 180 activityTestRule.launchActivity(null); 181 mActivity = activityTestRule.getActivity(); 182 mFragmentManager = activityTestRule.getActivity().getSupportFragmentManager(); 183 184 assertThat(getCurrentFragment().getView().hasFocus()).isTrue(); 185 } 186 187 @Test onTopLevelPreferenceTapped_focusUpdated()188 public void onTopLevelPreferenceTapped_focusUpdated() throws Throwable { 189 setUpTopLevelTestFragment(); 190 mActivityTestRule.runOnUiThread(() -> 191 mTopLevelFragment.getPreferenceScreen().getPreference(0).performClick()); 192 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 193 assertThat(getCurrentFragment().getView().hasFocus()).isTrue(); 194 } 195 196 @Test onFragmentLaunched_maintainContentFocus()197 public void onFragmentLaunched_maintainContentFocus() throws Throwable { 198 mActivityTestRule.runOnUiThread(() -> { 199 BaseTestSettingsFragment fragment = new BaseTestSettingsFragment(); 200 mActivity.launchFragment(fragment); 201 }); 202 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 203 assertThat(getCurrentFragment().getView().hasFocus()).isTrue(); 204 mActivityTestRule.runOnUiThread(() -> 205 getCurrentFragment().getPreferenceScreen().getPreference(0).performClick()); 206 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 207 assertThat(getCurrentFragment().getView().hasFocus()).isTrue(); 208 } 209 210 @Test onBack_maintainContentFocus()211 public void onBack_maintainContentFocus() throws Throwable { 212 mActivityTestRule.runOnUiThread(() -> { 213 BaseTestSettingsFragment fragment1 = new BaseTestSettingsFragment(); 214 mActivity.launchFragment(fragment1); 215 BaseTestSettingsFragment fragment2 = new BaseTestSettingsFragment(); 216 mActivity.launchFragment(fragment2); 217 }); 218 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 219 assertThat(getCurrentFragment().getView().hasFocus()).isTrue(); 220 mActivityTestRule.runOnUiThread(() -> mActivity.goBack()); 221 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 222 assertThat(getCurrentFragment().getView().hasFocus()).isTrue(); 223 } 224 225 @Test onPreferenceDisabled_maintainContentFocus()226 public void onPreferenceDisabled_maintainContentFocus() throws Throwable { 227 mActivityTestRule.runOnUiThread(() -> { 228 BaseTestSettingsFragment fragment = new BaseTestSettingsFragment(); 229 mActivity.launchFragment(fragment); 230 }); 231 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 232 assertThat(getCurrentFragment().getView().hasFocus()).isTrue(); 233 mActivityTestRule.runOnUiThread(() -> 234 getCurrentFragment().getPreferenceScreen().getPreference(0).setEnabled(false)); 235 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 236 assertThat(getCurrentFragment().getView().hasFocus()).isTrue(); 237 } 238 239 @Test onFragmentLaunched_noFocusableElements_parkingViewFocused()240 public void onFragmentLaunched_noFocusableElements_parkingViewFocused() throws Throwable { 241 mActivityTestRule.runOnUiThread(() -> { 242 EmptySettingsFragment fragment = new EmptySettingsFragment(); 243 mActivity.launchFragment(fragment); 244 }); 245 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 246 assertThat(mActivity.findViewById(R.id.settings_focus_parking_view).isFocused()).isTrue(); 247 } 248 setUpTopLevelTestFragment()249 private void setUpTopLevelTestFragment() throws Throwable { 250 String topLevelMenuTag = "top_level_menu"; 251 mActivityTestRule.runOnUiThread(() -> { 252 mFragmentManager.beginTransaction() 253 .replace(R.id.top_level_menu, new TestTopLevelMenuFragment(), topLevelMenuTag) 254 .commitNow(); 255 }); 256 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 257 mTopLevelFragment = (TopLevelMenuFragment) mFragmentManager.findFragmentByTag( 258 topLevelMenuTag); 259 } 260 261 public static class TestDualPaneHomepageActivity extends DualPaneTestActivity { 262 @Nullable 263 @Override getInitialFragment()264 protected Fragment getInitialFragment() { 265 return new BaseTestSettingsFragment(); 266 } 267 268 @Override shouldFocusContentOnLaunch()269 protected boolean shouldFocusContentOnLaunch() { 270 return false; 271 } 272 } 273 274 public static class TestDualPaneFragmentActivity extends DualPaneTestActivity { 275 @Nullable 276 @Override getInitialFragment()277 protected Fragment getInitialFragment() { 278 return new BaseTestSettingsFragment(); 279 } 280 } 281 } 282