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 17package com.android.server.am; 18 19import android.app.ActivityOptions; 20import android.content.pm.ActivityInfo.WindowLayout; 21import android.platform.test.annotations.Presubmit; 22import android.support.test.filters.MediumTest; 23import android.support.test.runner.AndroidJUnit4; 24 25import com.android.server.am.LaunchParamsController.LaunchParams; 26import org.junit.runner.RunWith; 27import org.junit.Before; 28import org.junit.Test; 29 30import com.android.server.am.LaunchParamsController.LaunchParamsModifier; 31 32import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 33import static org.mockito.Mockito.any; 34import static org.mockito.Mockito.anyInt; 35import static org.mockito.Mockito.doNothing; 36import static org.mockito.Mockito.eq; 37import static org.mockito.Mockito.mock; 38import static org.mockito.Mockito.never; 39import static org.mockito.Mockito.spy; 40import static org.mockito.Mockito.times; 41import static org.mockito.Mockito.verify; 42 43import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; 44import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; 45import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; 46 47import static org.junit.Assert.assertEquals; 48import static org.junit.Assert.assertNotEquals; 49 50/** 51 * Tests for exercising {@link LaunchParamsController}. 52 * 53 * Build/Install/Run: 54 * atest FrameworksServicesTests:LaunchParamsControllerTests 55 */ 56@MediumTest 57@Presubmit 58@RunWith(AndroidJUnit4.class) 59public class LaunchParamsControllerTests extends ActivityTestsBase { 60 private ActivityManagerService mService; 61 private LaunchParamsController mController; 62 63 @Before 64 @Override 65 public void setUp() throws Exception { 66 super.setUp(); 67 mService = createActivityManagerService(); 68 mController = new LaunchParamsController(mService); 69 } 70 71 /** 72 * Makes sure positioners get values passed to controller. 73 */ 74 @Test 75 public void testArgumentPropagation() { 76 final LaunchParamsModifier 77 positioner = mock(LaunchParamsModifier.class); 78 mController.registerModifier(positioner); 79 80 final ActivityRecord record = new ActivityBuilder(mService).build(); 81 final ActivityRecord source = new ActivityBuilder(mService).build(); 82 final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0); 83 final ActivityOptions options = mock(ActivityOptions.class); 84 85 mController.calculate(record.getTask(), layout, record, source, options, 86 new LaunchParams()); 87 verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record), 88 eq(source), eq(options), any(), any()); 89 } 90 91 /** 92 * Ensures positioners further down the chain are not called when RESULT_DONE is returned. 93 */ 94 @Test 95 public void testEarlyExit() { 96 final LaunchParamsModifier 97 ignoredPositioner = mock(LaunchParamsModifier.class); 98 final LaunchParamsModifier earlyExitPositioner = 99 (task, layout, activity, source, options, currentParams, outParams) -> RESULT_DONE; 100 101 mController.registerModifier(ignoredPositioner); 102 mController.registerModifier(earlyExitPositioner); 103 104 mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, 105 null /*source*/, null /*options*/, new LaunchParams()); 106 verify(ignoredPositioner, never()).onCalculate(any(), any(), any(), any(), any(), 107 any(), any()); 108 } 109 110 /** 111 * Ensures that positioners are called in the correct order. 112 */ 113 @Test 114 public void testRegistration() { 115 LaunchParamsModifier earlyExitPositioner = 116 new InstrumentedPositioner(RESULT_DONE, new LaunchParams()); 117 118 final LaunchParamsModifier firstPositioner = spy(earlyExitPositioner); 119 120 mController.registerModifier(firstPositioner); 121 122 mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, 123 null /*source*/, null /*options*/, new LaunchParams()); 124 verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(), 125 any()); 126 127 final LaunchParamsModifier secondPositioner = spy(earlyExitPositioner); 128 129 mController.registerModifier(secondPositioner); 130 131 mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, 132 null /*source*/, null /*options*/, new LaunchParams()); 133 verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(), 134 any()); 135 verify(secondPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(), 136 any()); 137 } 138 139 /** 140 * Makes sure positioners further down the registration chain are called. 141 */ 142 @Test 143 public void testPassThrough() { 144 final LaunchParamsModifier 145 positioner1 = mock(LaunchParamsModifier.class); 146 final LaunchParams params = new LaunchParams(); 147 params.mWindowingMode = WINDOWING_MODE_FREEFORM; 148 params.mBounds.set(0, 0, 30, 20); 149 params.mPreferredDisplayId = 3; 150 151 final InstrumentedPositioner positioner2 = new InstrumentedPositioner(RESULT_CONTINUE, 152 params); 153 154 mController.registerModifier(positioner1); 155 mController.registerModifier(positioner2); 156 157 mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/, 158 null /*options*/, new LaunchParams()); 159 160 verify(positioner1, times(1)).onCalculate(any(), any(), any(), any(), any(), 161 eq(positioner2.getLaunchParams()), any()); 162 } 163 164 /** 165 * Ensures skipped results are not propagated. 166 */ 167 @Test 168 public void testSkip() { 169 final LaunchParams params1 = new LaunchParams(); 170 params1.mBounds.set(0, 0, 10, 10); 171 final InstrumentedPositioner positioner1 = new InstrumentedPositioner(RESULT_SKIP, params1); 172 173 final LaunchParams params2 = new LaunchParams(); 174 params2.mBounds.set(0, 0, 20, 30); 175 final InstrumentedPositioner positioner2 = 176 new InstrumentedPositioner(RESULT_CONTINUE, params2); 177 178 mController.registerModifier(positioner1); 179 mController.registerModifier(positioner2); 180 181 final LaunchParams 182 result = new LaunchParams(); 183 184 mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/, 185 null /*options*/, result); 186 187 assertEquals(result, positioner2.getLaunchParams()); 188 } 189 190 /** 191 * Ensures that {@link LaunchParamsModifier} requests specifying display id during 192 * layout are honored. 193 */ 194 @Test 195 public void testLayoutTaskPreferredDisplayChange() { 196 final LaunchParams params = new LaunchParams(); 197 params.mPreferredDisplayId = 2; 198 final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params); 199 final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build(); 200 201 mController.registerModifier(positioner); 202 203 doNothing().when(mService).moveStackToDisplay(anyInt(), anyInt()); 204 mController.layoutTask(task, null /* windowLayout */); 205 verify(mService, times(1)).moveStackToDisplay(eq(task.getStackId()), 206 eq(params.mPreferredDisplayId)); 207 } 208 209 /** 210 * Ensures that {@link LaunchParamsModifier} requests specifying windowingMode during 211 * layout are honored. 212 */ 213 @Test 214 public void testLayoutTaskWindowingModeChange() { 215 final LaunchParams params = new LaunchParams(); 216 final int windowingMode = WINDOWING_MODE_FREEFORM; 217 params.mWindowingMode = windowingMode; 218 final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params); 219 final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build(); 220 221 mController.registerModifier(positioner); 222 223 final int beforeWindowMode = task.getStack().getWindowingMode(); 224 assertNotEquals(beforeWindowMode, windowingMode); 225 226 mController.layoutTask(task, null /* windowLayout */); 227 228 final int afterWindowMode = task.getStack().getWindowingMode(); 229 assertEquals(afterWindowMode, windowingMode); 230 } 231 232 public static class InstrumentedPositioner implements 233 LaunchParamsModifier { 234 235 final private int mReturnVal; 236 final private LaunchParams mParams; 237 238 InstrumentedPositioner(int returnVal, LaunchParams params) { 239 mReturnVal = returnVal; 240 mParams = params; 241 } 242 243 @Override 244 public int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity, 245 ActivityRecord source, ActivityOptions options, 246 LaunchParams currentParams, LaunchParams outParams) { 247 outParams.set(mParams); 248 return mReturnVal; 249 } 250 251 LaunchParams getLaunchParams() { 252 return mParams; 253 } 254 } 255} 256