Home | History | Annotate | Download | only in am
      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 
     17 package com.android.server.am;
     18 
     19 import android.content.pm.ActivityInfo.WindowLayout;
     20 import android.graphics.Rect;
     21 import android.platform.test.annotations.Presubmit;
     22 import android.support.test.filters.MediumTest;
     23 import android.support.test.runner.AndroidJUnit4;
     24 
     25 import android.view.Gravity;
     26 
     27 import org.junit.runner.RunWith;
     28 import org.junit.Before;
     29 import org.junit.Test;
     30 
     31 import org.mockito.invocation.InvocationOnMock;
     32 
     33 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
     34 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
     35 
     36 import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
     37 
     38 import static org.mockito.Mockito.any;
     39 import static org.mockito.Mockito.mock;
     40 import static org.mockito.Mockito.when;
     41 import static org.mockito.Mockito.doAnswer;
     42 import static org.junit.Assert.assertEquals;
     43 
     44 
     45 /**
     46  * Tests for exercising resizing task bounds.
     47  *
     48  * Build/Install/Run:
     49  *  atest FrameworksServicesTests:TaskLaunchParamsModifierTests
     50  */
     51 @MediumTest
     52 @Presubmit
     53 @RunWith(AndroidJUnit4.class)
     54 public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
     55     private final static int STACK_WIDTH = 100;
     56     private final static int STACK_HEIGHT = 200;
     57 
     58     private final static Rect STACK_BOUNDS = new Rect(0, 0, STACK_WIDTH, STACK_HEIGHT);
     59 
     60     private ActivityManagerService mService;
     61     private ActivityStack mStack;
     62     private TaskRecord mTask;
     63 
     64     private TaskLaunchParamsModifier mPositioner;
     65 
     66     private LaunchParamsController.LaunchParams mCurrent;
     67     private LaunchParamsController.LaunchParams mResult;
     68 
     69     @Before
     70     @Override
     71     public void setUp() throws Exception {
     72         super.setUp();
     73 
     74         mService = createActivityManagerService();
     75         mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
     76                 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     77         mStack.requestResize(STACK_BOUNDS);
     78 
     79         // We must create the task after resizing to make sure it does not inherit the stack
     80         // dimensions on resize.
     81         mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
     82 
     83         mPositioner = new TaskLaunchParamsModifier();
     84 
     85         mResult = new LaunchParamsController.LaunchParams();
     86         mCurrent = new LaunchParamsController.LaunchParams();
     87     }
     88 
     89     /**
     90      * Ensures that the setup bounds are set as expected with the stack bounds set and the task
     91      * bounds still {@code null}.
     92      * @throws Exception
     93      */
     94     @Test
     95     public void testInitialBounds() throws Exception {
     96         assertEquals(mStack.getOverrideBounds(), STACK_BOUNDS);
     97         assertEquals(mTask.getOverrideBounds(), new Rect());
     98     }
     99 
    100     /**
    101      * Ensures that a task positioned with no {@link WindowLayout} receives the default launch
    102      * position.
    103      * @throws Exception
    104      */
    105     @Test
    106     public void testLaunchNoWindowLayout() throws Exception {
    107         assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask, null /*layout*/,
    108                 null /*record*/, null /*source*/, null /*options*/, mCurrent, mResult));
    109         assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult.mBounds);
    110     }
    111 
    112     /**
    113      * Ensures that a task positioned with an empty {@link WindowLayout} receives the default launch
    114      * position.
    115      * @throws Exception
    116      */
    117     @Test
    118     public void testlaunchEmptyWindowLayout() throws Exception {
    119         assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
    120                 new WindowLayout(0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0), null /*activity*/,
    121                 null /*source*/, null /*options*/, mCurrent, mResult));
    122         assertEquals(mResult.mBounds, getDefaultBounds(Gravity.NO_GRAVITY));
    123     }
    124 
    125     /**
    126      * Ensures that a task positioned with a {@link WindowLayout} gravity specified is positioned
    127      * according to specification.
    128      * @throws Exception
    129      */
    130     @Test
    131     public void testlaunchWindowLayoutGravity() throws Exception {
    132         // Unspecified gravity should be ignored
    133         testGravity(Gravity.NO_GRAVITY);
    134 
    135         // Unsupported gravity should be ignored
    136         testGravity(Gravity.LEFT);
    137         testGravity(Gravity.RIGHT);
    138 
    139         // Test defaults for vertical gravities
    140         testGravity(Gravity.TOP);
    141         testGravity(Gravity.BOTTOM);
    142 
    143         // Test corners
    144         testGravity(Gravity.TOP | Gravity.LEFT);
    145         testGravity(Gravity.TOP | Gravity.RIGHT);
    146         testGravity(Gravity.BOTTOM | Gravity.LEFT);
    147         testGravity(Gravity.BOTTOM | Gravity.RIGHT);
    148     }
    149 
    150     private void testGravity(int gravity) {
    151         try {
    152             assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
    153                     new WindowLayout(0, 0, 0, 0, gravity, 0, 0), null /*activity*/,
    154                     null /*source*/, null /*options*/, mCurrent, mResult));
    155             assertEquals(mResult.mBounds, getDefaultBounds(gravity));
    156         } finally {
    157             mCurrent.reset();
    158             mResult.reset();
    159         }
    160     }
    161 
    162     /**
    163      * Ensures that a task which causes a conflict with another task when positioned is adjusted as
    164      * expected.
    165      * @throws Exception
    166      */
    167     @Test
    168     public void testLaunchWindowCenterConflict() throws Exception {
    169         testConflict(Gravity.NO_GRAVITY);
    170         testConflict(Gravity.TOP);
    171         testConflict(Gravity.BOTTOM);
    172         testConflict(Gravity.TOP | Gravity.LEFT);
    173         testConflict(Gravity.TOP | Gravity.RIGHT);
    174         testConflict(Gravity.BOTTOM | Gravity.LEFT);
    175         testConflict(Gravity.BOTTOM | Gravity.RIGHT);
    176     }
    177 
    178     private void testConflict(int gravity) {
    179         final WindowLayout layout = new WindowLayout(0, 0, 0, 0, gravity, 0, 0);
    180 
    181         // layout first task
    182         mService.mStackSupervisor.getLaunchParamsController().layoutTask(mTask, layout);
    183 
    184         // Second task will be laid out on top of the first so starting bounds is the same.
    185         final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
    186 
    187         ActivityRecord activity = null;
    188         TaskRecord secondTask = null;
    189 
    190         // wrap with try/finally to ensure cleanup of activity/stack.
    191         try {
    192             // empty tasks are ignored in conflicts
    193             activity = new ActivityBuilder(mService).setTask(mTask).build();
    194 
    195             // Create secondary task
    196             secondTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
    197 
    198             // layout second task
    199             assertEquals(RESULT_CONTINUE,
    200                     mPositioner.onCalculate(secondTask, layout, null /*activity*/,
    201                             null /*source*/, null /*options*/, mCurrent, mResult));
    202 
    203             if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
    204                     || (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
    205                     == (Gravity.BOTTOM | Gravity.RIGHT)) {
    206                 expectedBounds.offset(-TaskLaunchParamsModifier.getHorizontalStep(
    207                         mStack.getOverrideBounds()), 0);
    208             } else if ((gravity & Gravity.TOP) == Gravity.TOP
    209                     || (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
    210                 expectedBounds.offset(
    211                         TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()), 0);
    212             } else {
    213                 expectedBounds.offset(
    214                         TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()),
    215                         TaskLaunchParamsModifier.getVerticalStep(mStack.getOverrideBounds()));
    216             }
    217 
    218             assertEquals(mResult.mBounds, expectedBounds);
    219         } finally {
    220             // Remove task and activity to prevent influencing future tests
    221             if (activity != null) {
    222                 mTask.removeActivity(activity);
    223             }
    224 
    225             if (secondTask != null) {
    226                 mStack.removeTask(secondTask, "cleanup", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
    227             }
    228         }
    229     }
    230 
    231     private Rect getDefaultBounds(int gravity) {
    232         final Rect bounds = new Rect();
    233         bounds.set(mStack.getOverrideBounds());
    234 
    235         final int verticalInset =
    236                 TaskLaunchParamsModifier.getFreeformStartTop(mStack.getOverrideBounds());
    237         final int horizontalInset =
    238                 TaskLaunchParamsModifier.getFreeformStartLeft(mStack.getOverrideBounds());
    239 
    240         bounds.inset(horizontalInset, verticalInset);
    241 
    242         if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)) {
    243             bounds.offsetTo(horizontalInset * 2, 0);
    244         } else if ((gravity & Gravity.TOP) == Gravity.TOP) {
    245             bounds.offsetTo(0, 0);
    246         } else if ((gravity & (Gravity.BOTTOM | Gravity.RIGHT))
    247                 == (Gravity.BOTTOM | Gravity.RIGHT)) {
    248             bounds.offsetTo(horizontalInset * 2, verticalInset * 2);
    249         } else if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
    250             bounds.offsetTo(0, verticalInset * 2);
    251         }
    252 
    253         return bounds;
    254     }
    255 }
    256