1 /* 2 * Copyright (C) 2020 Google Inc. 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.carlauncher.homescreen; 18 19 import static androidx.test.espresso.Espresso.onView; 20 import static androidx.test.espresso.assertion.ViewAssertions.matches; 21 import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; 22 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; 23 import static androidx.test.espresso.matcher.ViewMatchers.withId; 24 import static androidx.test.espresso.matcher.ViewMatchers.withText; 25 26 import static org.hamcrest.CoreMatchers.allOf; 27 import static org.hamcrest.CoreMatchers.not; 28 import static org.junit.Assert.assertNotNull; 29 import static org.mockito.Mockito.mock; 30 import static org.mockito.Mockito.verify; 31 import static org.mockito.Mockito.when; 32 33 import android.graphics.drawable.Drawable; 34 import android.widget.ImageButton; 35 36 import androidx.test.ext.junit.runners.AndroidJUnit4; 37 import androidx.test.filters.Suppress; 38 import androidx.test.platform.app.InstrumentationRegistry; 39 import androidx.test.rule.ActivityTestRule; 40 41 import com.android.car.carlauncher.CarLauncher; 42 import com.android.car.carlauncher.R; 43 import com.android.car.carlauncher.homescreen.ui.CardHeader; 44 import com.android.car.carlauncher.homescreen.ui.DescriptiveTextView; 45 import com.android.car.carlauncher.homescreen.ui.DescriptiveTextWithControlsView; 46 import com.android.car.carlauncher.homescreen.ui.TextBlockView; 47 48 import org.junit.Rule; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 52 @Suppress // To be ignored until b/224978827 is fixed 53 @RunWith(AndroidJUnit4.class) 54 public class HomeCardFragmentTest { 55 56 private static final String DESCRIPTIVE_TEXT_TITLE = "Test title text"; 57 private static final String DESCRIPTIVE_TEXT_SUBTITLE = "Test subtitle text"; 58 private static final String DESCRIPTIVE_TEXT_FOOTER = "Descriptive footer"; 59 private static final String TEXT_BLOCK_CONTENT = "Test text for text block"; 60 private static final String TEXT_BLOCK_FOOTER = "Text block footer"; 61 private static final CardHeader CARD_HEADER = new CardHeader("Test App Name", /* appIcon= */ 62 null); 63 private static final DescriptiveTextView DESCRIPTIVE_TEXT_VIEW = 64 new DescriptiveTextView(/* image = */ null, DESCRIPTIVE_TEXT_TITLE, 65 DESCRIPTIVE_TEXT_SUBTITLE, DESCRIPTIVE_TEXT_FOOTER); 66 private static final DescriptiveTextView DESCRIPTIVE_TEXT_VIEW_NO_FOOTER = 67 new DescriptiveTextView(/* image = */ null, DESCRIPTIVE_TEXT_TITLE, 68 DESCRIPTIVE_TEXT_SUBTITLE); 69 private static final TextBlockView TEXT_BLOCK_VIEW = new TextBlockView(TEXT_BLOCK_CONTENT, 70 TEXT_BLOCK_FOOTER); 71 private static final TextBlockView TEXT_BLOCK_VIEW_NO_FOOTER = new TextBlockView( 72 TEXT_BLOCK_CONTENT); 73 74 @Rule 75 public ActivityTestRule<CarLauncher> mActivityTestRule = new ActivityTestRule<CarLauncher>( 76 CarLauncher.class); 77 78 @Test updateContentView_descriptiveTextWithFooter_displaysTapForMoreView()79 public void updateContentView_descriptiveTextWithFooter_displaysTapForMoreView() { 80 HomeCardFragment fragment = (HomeCardFragment) mActivityTestRule.getActivity() 81 .getSupportFragmentManager().findFragmentById(R.id.top_card); 82 fragment.updateHeaderView(CARD_HEADER); 83 fragment.updateContentView(DESCRIPTIVE_TEXT_VIEW); 84 85 onView(allOf(withId(R.id.descriptive_text_layout), 86 isDescendantOfA(withId(R.id.top_card)))).check( 87 matches(isDisplayed())); 88 onView(allOf(withId(R.id.primary_text), withText(DESCRIPTIVE_TEXT_TITLE), 89 isDescendantOfA(withId(R.id.descriptive_text_layout)), 90 isDescendantOfA(withId(R.id.top_card)))).check(matches(isDisplayed())); 91 onView(allOf(withId(R.id.secondary_text), withText(DESCRIPTIVE_TEXT_SUBTITLE), 92 isDescendantOfA(withId(R.id.descriptive_text_layout)), 93 isDescendantOfA(withId(R.id.top_card)))).check(matches(isDisplayed())); 94 onView(allOf(withId(R.id.tap_for_more_text), withText(DESCRIPTIVE_TEXT_FOOTER), 95 isDescendantOfA(withId(R.id.descriptive_text_layout)), 96 isDescendantOfA(withId(R.id.top_card)))).check(matches(isDisplayed())); 97 } 98 99 @Test updateContentView_descriptiveTextWithNoFooter_hidesTapForMoreView()100 public void updateContentView_descriptiveTextWithNoFooter_hidesTapForMoreView() { 101 HomeCardFragment fragment = (HomeCardFragment) mActivityTestRule.getActivity() 102 .getSupportFragmentManager().findFragmentById(R.id.top_card); 103 fragment.updateHeaderView(CARD_HEADER); 104 fragment.updateContentView(DESCRIPTIVE_TEXT_VIEW_NO_FOOTER); 105 106 onView(allOf(withId(R.id.descriptive_text_layout), 107 isDescendantOfA(withId(R.id.top_card)))).check( 108 matches(isDisplayed())); 109 onView(allOf(withId(R.id.primary_text), withText(DESCRIPTIVE_TEXT_TITLE), 110 isDescendantOfA(withId(R.id.descriptive_text_layout)), 111 isDescendantOfA(withId(R.id.top_card)))).check(matches(isDisplayed())); 112 onView(allOf(withId(R.id.secondary_text), withText(DESCRIPTIVE_TEXT_SUBTITLE), 113 isDescendantOfA(withId(R.id.descriptive_text_layout)), 114 isDescendantOfA(withId(R.id.top_card)))).check(matches(isDisplayed())); 115 onView(allOf(withId(R.id.tap_for_more_text), 116 isDescendantOfA(withId(R.id.descriptive_text_layout)), 117 isDescendantOfA(withId(R.id.top_card)))).check(matches(not(isDisplayed()))); 118 } 119 120 @Test updateContentView_textBlockWithFooter_displaysTapForMoreView()121 public void updateContentView_textBlockWithFooter_displaysTapForMoreView() { 122 HomeCardFragment fragment = (HomeCardFragment) mActivityTestRule.getActivity() 123 .getSupportFragmentManager().findFragmentById(R.id.top_card); 124 fragment.updateHeaderView(CARD_HEADER); 125 fragment.updateContentView(TEXT_BLOCK_VIEW); 126 127 onView(allOf(withId(R.id.text_block_layout), isDescendantOfA(withId(R.id.top_card)))).check( 128 matches(isDisplayed())); 129 onView(allOf(withId(R.id.text_block), withText(TEXT_BLOCK_CONTENT), 130 isDescendantOfA(withId(R.id.text_block_layout)), 131 isDescendantOfA(withId(R.id.top_card)))).check(matches(isDisplayed())); 132 onView(allOf(withId(R.id.tap_for_more_text), withText(TEXT_BLOCK_FOOTER), 133 isDescendantOfA(withId(R.id.text_block_layout)), 134 isDescendantOfA(withId(R.id.top_card)))).check(matches(isDisplayed())); 135 } 136 137 @Test updateContentView_textBlockNoFooter_hidesTapForMoreView()138 public void updateContentView_textBlockNoFooter_hidesTapForMoreView() { 139 HomeCardFragment fragment = (HomeCardFragment) mActivityTestRule.getActivity() 140 .getSupportFragmentManager().findFragmentById(R.id.top_card); 141 fragment.updateHeaderView(CARD_HEADER); 142 fragment.updateContentView(TEXT_BLOCK_VIEW_NO_FOOTER); 143 144 onView(allOf(withId(R.id.text_block_layout), isDescendantOfA(withId(R.id.top_card)))).check( 145 matches(isDisplayed())); 146 onView(allOf(withId(R.id.text_block), withText(TEXT_BLOCK_CONTENT), 147 isDescendantOfA(withId(R.id.text_block_layout)), 148 isDescendantOfA(withId(R.id.top_card)))).check(matches(isDisplayed())); 149 onView(allOf(withId(R.id.tap_for_more_text), 150 isDescendantOfA(withId(R.id.text_block_layout)), 151 isDescendantOfA(withId(R.id.top_card)))).check(matches(not(isDisplayed()))); 152 } 153 154 @Test updateControlBarButton_updatesButtonSelectedState()155 public void updateControlBarButton_updatesButtonSelectedState() { 156 HomeCardFragment fragment = (HomeCardFragment) mActivityTestRule.getActivity() 157 .getSupportFragmentManager().findFragmentById(R.id.top_card); 158 assertNotNull(fragment); 159 160 ImageButton leftImageButton = mock(ImageButton.class); 161 fragment.setControlBarLeftButton(leftImageButton); 162 163 Drawable mockIcon = mock(Drawable.class); 164 DescriptiveTextWithControlsView.Control buttonControl = mock( 165 DescriptiveTextWithControlsView.Control.class); 166 DescriptiveTextWithControlsView.Control leftButtonControl = mock( 167 DescriptiveTextWithControlsView.Control.class); 168 169 // unselects the button in case the icon doesn't have a selected state 170 when(mockIcon.getState()).thenReturn(new int[0]); 171 when(leftButtonControl.getIcon()).thenReturn(mockIcon); 172 DescriptiveTextWithControlsView controlView = new DescriptiveTextWithControlsView(null, 173 "test", "test", leftButtonControl, buttonControl, buttonControl); 174 fragment.updateHeaderView(CARD_HEADER); 175 fragment.updateContentView(controlView); 176 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 177 verify(leftImageButton).setSelected(false); 178 179 // selects the button in case the icon have a selected state 180 when(mockIcon.getState()).thenReturn(new int[]{android.R.attr.state_selected}); 181 when(leftButtonControl.getIcon()).thenReturn(mockIcon); 182 controlView = new DescriptiveTextWithControlsView(null, 183 "test", "test", leftButtonControl, buttonControl, buttonControl); 184 fragment.updateContentView(controlView); 185 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 186 verify(leftImageButton).setSelected(true); 187 } 188 } 189