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 android.view; 18 19 import static org.hamcrest.Matchers.equalTo; 20 import static org.junit.Assert.assertThat; 21 22 import android.content.Context; 23 import android.graphics.Rect; 24 import android.platform.test.annotations.Presubmit; 25 import android.support.test.InstrumentationRegistry; 26 import android.support.test.filters.SmallTest; 27 import android.support.test.runner.AndroidJUnit4; 28 29 import org.junit.Before; 30 import org.junit.Test; 31 import org.junit.runner.RunWith; 32 33 import java.lang.reflect.Field; 34 import java.lang.reflect.Method; 35 36 @Presubmit 37 @SmallTest 38 @RunWith(AndroidJUnit4.class) 39 public class ViewRootImplTest { 40 41 private Context mContext; 42 private ViewRootImplAccessor mViewRootImpl; 43 44 @Before setUp()45 public void setUp() throws Exception { 46 mContext = InstrumentationRegistry.getContext(); 47 48 InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { 49 mViewRootImpl = new ViewRootImplAccessor( 50 new ViewRootImpl(mContext, mContext.getDisplay())); 51 }); 52 } 53 54 @Test negativeInsets_areSetToZero()55 public void negativeInsets_areSetToZero() throws Exception { 56 mViewRootImpl.getAttachInfo().getContentInsets().set(-10, -20, -30 , -40); 57 mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40); 58 final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */); 59 60 assertThat(insets.getSystemWindowInsets(), equalTo(new Rect())); 61 assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(), 62 insets.getStableInsetRight(), insets.getStableInsetBottom()), equalTo(new Rect())); 63 } 64 65 @Test negativeInsets_areSetToZero_positiveAreLeftAsIs()66 public void negativeInsets_areSetToZero_positiveAreLeftAsIs() throws Exception { 67 mViewRootImpl.getAttachInfo().getContentInsets().set(-10, 20, -30 , 40); 68 mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40); 69 final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */); 70 71 assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(0, 20, 0, 40))); 72 assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(), 73 insets.getStableInsetRight(), insets.getStableInsetBottom()), 74 equalTo(new Rect(10, 0, 30, 0))); 75 } 76 77 @Test positiveInsets_areLeftAsIs()78 public void positiveInsets_areLeftAsIs() throws Exception { 79 mViewRootImpl.getAttachInfo().getContentInsets().set(10, 20, 30 , 40); 80 mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40); 81 final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */); 82 83 assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(10, 20, 30, 40))); 84 assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(), 85 insets.getStableInsetRight(), insets.getStableInsetBottom()), 86 equalTo(new Rect(10, 20, 30, 40))); 87 } 88 89 private static class ViewRootImplAccessor { 90 91 private final ViewRootImpl mViewRootImpl; 92 ViewRootImplAccessor(ViewRootImpl viewRootImpl)93 ViewRootImplAccessor(ViewRootImpl viewRootImpl) { 94 mViewRootImpl = viewRootImpl; 95 } 96 get()97 public ViewRootImpl get() { 98 return mViewRootImpl; 99 } 100 getAttachInfo()101 AttachInfoAccessor getAttachInfo() throws Exception { 102 return new AttachInfoAccessor( 103 getField(mViewRootImpl, ViewRootImpl.class.getDeclaredField("mAttachInfo"))); 104 } 105 getWindowInsets(boolean forceConstruct)106 WindowInsets getWindowInsets(boolean forceConstruct) throws Exception { 107 return (WindowInsets) invokeMethod(mViewRootImpl, 108 ViewRootImpl.class.getDeclaredMethod("getWindowInsets", boolean.class), 109 forceConstruct); 110 } 111 112 class AttachInfoAccessor { 113 114 private final Class<?> mClass; 115 private final Object mAttachInfo; 116 AttachInfoAccessor(Object attachInfo)117 AttachInfoAccessor(Object attachInfo) throws Exception { 118 mAttachInfo = attachInfo; 119 mClass = ViewRootImpl.class.getClassLoader().loadClass( 120 "android.view.View$AttachInfo"); 121 } 122 getContentInsets()123 Rect getContentInsets() throws Exception { 124 return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mContentInsets")); 125 } 126 getStableInsets()127 Rect getStableInsets() throws Exception { 128 return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mStableInsets")); 129 } 130 } 131 getField(Object o, Field field)132 private static Object getField(Object o, Field field) throws Exception { 133 field.setAccessible(true); 134 return field.get(o); 135 } 136 invokeMethod(Object o, Method method, Object... args)137 private static Object invokeMethod(Object o, Method method, Object... args) 138 throws Exception { 139 method.setAccessible(true); 140 return method.invoke(o, args); 141 } 142 } 143 } 144