1 /* 2 * Copyright (C) 2018 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.internal.widget; 18 19 import static android.view.View.VISIBLE; 20 21 import static org.hamcrest.Matchers.is; 22 import static org.junit.Assert.assertThat; 23 import static org.mockito.ArgumentMatchers.any; 24 import static org.mockito.Mockito.atLeastOnce; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.verifyNoMoreInteractions; 28 29 import static java.util.Arrays.asList; 30 import static java.util.Collections.emptyList; 31 32 import android.graphics.Color; 33 import android.graphics.drawable.ColorDrawable; 34 import android.graphics.drawable.Drawable; 35 import android.view.ViewGroup; 36 import android.widget.FrameLayout; 37 38 import androidx.test.InstrumentationRegistry; 39 40 import org.junit.Before; 41 import org.junit.Test; 42 43 import java.util.List; 44 45 public class BackgroundFallbackTest { 46 47 private static final int NAVBAR_BOTTOM = 0; 48 private static final int NAVBAR_LEFT = 1; 49 private static final int NAVBAR_RIGHT = 2; 50 51 private static final int SCREEN_HEIGHT = 2000; 52 private static final int SCREEN_WIDTH = 1000; 53 private static final int STATUS_HEIGHT = 100; 54 private static final int NAV_SIZE = 200; 55 56 private static final boolean INSET_CONTENT_VIEWS = true; 57 private static final boolean DONT_INSET_CONTENT_VIEWS = false; 58 59 BackgroundFallback mFallback; 60 Drawable mDrawableMock; 61 62 ViewGroup mStatusBarView; 63 ViewGroup mNavigationBarView; 64 65 ViewGroup mDecorViewMock; 66 ViewGroup mContentRootMock; 67 ViewGroup mContentContainerMock; 68 ViewGroup mContentMock; 69 70 int mLastTop = 0; 71 72 @Before setUp()73 public void setUp() throws Exception { 74 mFallback = new BackgroundFallback(); 75 mDrawableMock = mock(Drawable.class); 76 77 mFallback.setDrawable(mDrawableMock); 78 79 } 80 81 @Test hasFallback_withDrawable_true()82 public void hasFallback_withDrawable_true() { 83 mFallback.setDrawable(mDrawableMock); 84 assertThat(mFallback.hasFallback(), is(true)); 85 } 86 87 @Test hasFallback_withoutDrawable_false()88 public void hasFallback_withoutDrawable_false() { 89 mFallback.setDrawable(null); 90 assertThat(mFallback.hasFallback(), is(false)); 91 } 92 93 @Test draw_portrait_noFallback()94 public void draw_portrait_noFallback() { 95 setUpViewHierarchy(INSET_CONTENT_VIEWS, NAVBAR_BOTTOM); 96 97 mFallback.draw(mDecorViewMock, mContentRootMock, null /* canvas */, mContentContainerMock, 98 mStatusBarView, mNavigationBarView); 99 100 verifyNoMoreInteractions(mDrawableMock); 101 } 102 103 @Test draw_portrait_translucentBars_fallback()104 public void draw_portrait_translucentBars_fallback() { 105 setUpViewHierarchy(INSET_CONTENT_VIEWS, NAVBAR_BOTTOM); 106 setTranslucent(mStatusBarView); 107 setTranslucent(mNavigationBarView); 108 109 mFallback.draw(mDecorViewMock, mContentRootMock, null /* canvas */, mContentContainerMock, 110 mStatusBarView, mNavigationBarView); 111 112 verifyFallbackTop(STATUS_HEIGHT); 113 verifyFallbackBottom(NAV_SIZE); 114 verifyNoMoreInteractions(mDrawableMock); 115 } 116 117 @Test draw_landscape_translucentBars_fallback()118 public void draw_landscape_translucentBars_fallback() { 119 setUpViewHierarchy(INSET_CONTENT_VIEWS, NAVBAR_RIGHT); 120 setTranslucent(mStatusBarView); 121 setTranslucent(mNavigationBarView); 122 123 mFallback.draw(mDecorViewMock, mContentRootMock, null /* canvas */, mContentContainerMock, 124 mStatusBarView, mNavigationBarView); 125 126 verifyFallbackTop(STATUS_HEIGHT); 127 verifyFallbackRight(NAV_SIZE); 128 verifyNoMoreInteractions(mDrawableMock); 129 } 130 131 @Test draw_seascape_translucentBars_fallback()132 public void draw_seascape_translucentBars_fallback() { 133 setUpViewHierarchy(INSET_CONTENT_VIEWS, NAVBAR_LEFT); 134 setTranslucent(mStatusBarView); 135 setTranslucent(mNavigationBarView); 136 137 mFallback.draw(mDecorViewMock, mContentRootMock, null /* canvas */, mContentContainerMock, 138 mStatusBarView, mNavigationBarView); 139 140 verifyFallbackTop(STATUS_HEIGHT); 141 verifyFallbackLeft(NAV_SIZE); 142 verifyNoMoreInteractions(mDrawableMock); 143 } 144 145 @Test draw_landscape_noFallback()146 public void draw_landscape_noFallback() { 147 setUpViewHierarchy(INSET_CONTENT_VIEWS, NAVBAR_RIGHT); 148 149 mFallback.draw(mDecorViewMock, mContentRootMock, null /* canvas */, mContentContainerMock, 150 mStatusBarView, mNavigationBarView); 151 152 verifyNoMoreInteractions(mDrawableMock); 153 } 154 155 @Test draw_seascape_noFallback()156 public void draw_seascape_noFallback() { 157 setUpViewHierarchy(INSET_CONTENT_VIEWS, NAVBAR_LEFT); 158 159 mFallback.draw(mDecorViewMock, mContentRootMock, null /* canvas */, mContentContainerMock, 160 mStatusBarView, mNavigationBarView); 161 162 verifyNoMoreInteractions(mDrawableMock); 163 } 164 165 @Test draw_seascape_translucentBars_noInsets_noFallback()166 public void draw_seascape_translucentBars_noInsets_noFallback() { 167 setUpViewHierarchy(DONT_INSET_CONTENT_VIEWS, NAVBAR_LEFT); 168 setTranslucent(mStatusBarView); 169 setTranslucent(mNavigationBarView); 170 171 mFallback.draw(mDecorViewMock, mContentRootMock, null /* canvas */, mContentContainerMock, 172 mStatusBarView, mNavigationBarView); 173 174 verifyNoMoreInteractions(mDrawableMock); 175 } 176 verifyFallbackTop(int size)177 private void verifyFallbackTop(int size) { 178 verify(mDrawableMock).setBounds(0, 0, SCREEN_WIDTH, size); 179 verify(mDrawableMock, atLeastOnce()).draw(any()); 180 mLastTop = size; 181 } 182 verifyFallbackLeft(int size)183 private void verifyFallbackLeft(int size) { 184 verify(mDrawableMock).setBounds(0, mLastTop, size, SCREEN_HEIGHT); 185 verify(mDrawableMock, atLeastOnce()).draw(any()); 186 } 187 verifyFallbackRight(int size)188 private void verifyFallbackRight(int size) { 189 verify(mDrawableMock).setBounds(SCREEN_WIDTH - size, mLastTop, SCREEN_WIDTH, SCREEN_HEIGHT); 190 verify(mDrawableMock, atLeastOnce()).draw(any()); 191 } 192 verifyFallbackBottom(int size)193 private void verifyFallbackBottom(int size) { 194 verify(mDrawableMock).setBounds(0, SCREEN_HEIGHT - size, SCREEN_WIDTH, SCREEN_HEIGHT); 195 verify(mDrawableMock, atLeastOnce()).draw(any()); 196 } 197 setUpViewHierarchy(boolean insetContentViews, int navBarPosition)198 private void setUpViewHierarchy(boolean insetContentViews, int navBarPosition) { 199 int insetLeft = 0; 200 int insetTop = 0; 201 int insetRight = 0; 202 int insetBottom = 0; 203 204 mStatusBarView = mockView(0, 0, SCREEN_WIDTH, STATUS_HEIGHT, 205 new ColorDrawable(Color.BLACK), VISIBLE, emptyList()); 206 if (insetContentViews) { 207 insetTop = STATUS_HEIGHT; 208 } 209 210 switch (navBarPosition) { 211 case NAVBAR_BOTTOM: 212 mNavigationBarView = mockView(0, SCREEN_HEIGHT - NAV_SIZE, SCREEN_WIDTH, 213 SCREEN_HEIGHT, new ColorDrawable(Color.BLACK), VISIBLE, emptyList()); 214 if (insetContentViews) { 215 insetBottom = NAV_SIZE; 216 } 217 break; 218 case NAVBAR_LEFT: 219 mNavigationBarView = mockView(0, 0, NAV_SIZE, SCREEN_HEIGHT, 220 new ColorDrawable(Color.BLACK), VISIBLE, emptyList()); 221 if (insetContentViews) { 222 insetLeft = NAV_SIZE; 223 } 224 break; 225 case NAVBAR_RIGHT: 226 mNavigationBarView = mockView(SCREEN_WIDTH - NAV_SIZE, 0, SCREEN_WIDTH, 227 SCREEN_HEIGHT, new ColorDrawable(Color.BLACK), VISIBLE, emptyList()); 228 if (insetContentViews) { 229 insetRight = NAV_SIZE; 230 } 231 break; 232 } 233 234 mContentMock = mockView(0, 0, SCREEN_WIDTH - insetLeft - insetRight, 235 SCREEN_HEIGHT - insetTop - insetBottom, null, VISIBLE, emptyList()); 236 mContentContainerMock = mockView(0, 0, SCREEN_WIDTH - insetLeft - insetRight, 237 SCREEN_HEIGHT - insetTop - insetBottom, null, VISIBLE, asList(mContentMock)); 238 mContentRootMock = mockView(insetLeft, insetTop, SCREEN_WIDTH - insetRight, 239 SCREEN_HEIGHT - insetBottom, null, VISIBLE, asList(mContentContainerMock)); 240 241 mDecorViewMock = mockView(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, null, VISIBLE, 242 asList(mContentRootMock, mStatusBarView, mNavigationBarView)); 243 } 244 setTranslucent(ViewGroup bar)245 private void setTranslucent(ViewGroup bar) { 246 bar.setBackground(new ColorDrawable(Color.TRANSPARENT)); 247 } 248 mockView(int left, int top, int right, int bottom, Drawable background, int visibility, List<ViewGroup> children)249 private ViewGroup mockView(int left, int top, int right, int bottom, Drawable background, 250 int visibility, List<ViewGroup> children) { 251 final ViewGroup v = new FrameLayout(InstrumentationRegistry.getTargetContext()); 252 253 v.layout(left, top, right, bottom); 254 v.setBackground(background); 255 v.setVisibility(visibility); 256 257 for (ViewGroup c : children) { 258 v.addView(c); 259 } 260 261 return v; 262 } 263 }