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 static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
     20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
     21 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
     22 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
     23 import static android.view.Display.DEFAULT_DISPLAY;
     24 
     25 import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
     26 import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
     27 import static com.android.server.am.ActivityStack.ActivityState.FINISHING;
     28 import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
     29 import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
     30 import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
     31 import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
     32 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
     33 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
     34 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
     35 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
     36 
     37 import static junit.framework.TestCase.assertNotNull;
     38 
     39 import static org.junit.Assert.assertEquals;
     40 import static org.junit.Assert.assertFalse;
     41 import static org.junit.Assert.assertNull;
     42 import static org.junit.Assert.assertTrue;
     43 import static org.mockito.Mockito.any;
     44 import static org.mockito.Mockito.anyInt;
     45 import static org.mockito.Mockito.doAnswer;
     46 import static org.mockito.Mockito.eq;
     47 import static org.mockito.Mockito.times;
     48 import static org.mockito.Mockito.verify;
     49 import static org.mockito.Mockito.when;
     50 
     51 import android.app.ActivityOptions;
     52 import android.app.servertransaction.ClientTransaction;
     53 import android.app.servertransaction.PauseActivityItem;
     54 import android.graphics.Rect;
     55 import android.platform.test.annotations.Presubmit;
     56 import android.support.test.filters.MediumTest;
     57 import android.support.test.runner.AndroidJUnit4;
     58 import android.util.MutableBoolean;
     59 
     60 import org.junit.runner.RunWith;
     61 import org.junit.Before;
     62 import org.junit.Ignore;
     63 import org.junit.Test;
     64 import org.mockito.invocation.InvocationOnMock;
     65 
     66 /**
     67  * Tests for the {@link ActivityRecord} class.
     68  *
     69  * Build/Install/Run:
     70  *  atest FrameworksServicesTests:com.android.server.am.ActivityRecordTests
     71  */
     72 @MediumTest
     73 @Presubmit
     74 @RunWith(AndroidJUnit4.class)
     75 public class ActivityRecordTests extends ActivityTestsBase {
     76     private ActivityManagerService mService;
     77     private TestActivityStack mStack;
     78     private TaskRecord mTask;
     79     private ActivityRecord mActivity;
     80 
     81     @Before
     82     @Override
     83     public void setUp() throws Exception {
     84         super.setUp();
     85 
     86         mService = createActivityManagerService();
     87         mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
     88                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     89         mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
     90         mActivity = new ActivityBuilder(mService).setTask(mTask).build();
     91     }
     92 
     93     @Test
     94     public void testStackCleanupOnClearingTask() throws Exception {
     95         mActivity.setTask(null);
     96         assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
     97     }
     98 
     99     @Test
    100     public void testStackCleanupOnActivityRemoval() throws Exception {
    101         mTask.removeActivity(mActivity);
    102         assertEquals(mStack.onActivityRemovedFromStackInvocationCount(),  1);
    103     }
    104 
    105     @Test
    106     public void testStackCleanupOnTaskRemoval() throws Exception {
    107         mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING);
    108         // Stack should be gone on task removal.
    109         assertNull(mService.mStackSupervisor.getStack(mStack.mStackId));
    110     }
    111 
    112     @Test
    113     public void testNoCleanupMovingActivityInSameStack() throws Exception {
    114         final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
    115                 .build();
    116         mActivity.reparent(newTask, 0, null /*reason*/);
    117         assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0);
    118     }
    119 
    120     @Test
    121     public void testPausingWhenVisibleFromStopped() throws Exception {
    122         final MutableBoolean pauseFound = new MutableBoolean(false);
    123         doAnswer((InvocationOnMock invocationOnMock) -> {
    124             final ClientTransaction transaction = invocationOnMock.getArgument(0);
    125             if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
    126                 pauseFound.value = true;
    127             }
    128             return null;
    129         }).when(mActivity.app.thread).scheduleTransaction(any());
    130 
    131         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
    132 
    133         // The activity is in the focused stack so it should not move to paused.
    134         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
    135         assertTrue(mActivity.isState(STOPPED));
    136         assertFalse(pauseFound.value);
    137 
    138         // Clear focused stack
    139         mActivity.mStackSupervisor.mFocusedStack = null;
    140 
    141         // In the unfocused stack, the activity should move to paused.
    142         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
    143         assertTrue(mActivity.isState(PAUSING));
    144         assertTrue(pauseFound.value);
    145 
    146         // Make sure that the state does not change for current non-stopping states.
    147         mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
    148 
    149         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
    150 
    151         assertTrue(mActivity.isState(INITIALIZING));
    152 
    153         // Make sure the state does not change if we are not the current top activity.
    154         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
    155 
    156         // Make sure that the state does not change when we have an activity becoming translucent
    157         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
    158         mStack.mTranslucentActivityWaiting = topActivity;
    159         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
    160 
    161         assertTrue(mActivity.isState(STOPPED));
    162     }
    163 
    164     @Test
    165     public void testPositionLimitedAspectRatioNavBarBottom() throws Exception {
    166         verifyPositionWithLimitedAspectRatio(NAV_BAR_BOTTOM, new Rect(0, 0, 1000, 2000), 1.5f,
    167                 new Rect(0, 0, 1000, 1500));
    168     }
    169 
    170     @Test
    171     public void testPositionLimitedAspectRatioNavBarLeft() throws Exception {
    172         verifyPositionWithLimitedAspectRatio(NAV_BAR_LEFT, new Rect(0, 0, 2000, 1000), 1.5f,
    173                 new Rect(500, 0, 2000, 1000));
    174     }
    175 
    176     @Test
    177     public void testPositionLimitedAspectRatioNavBarRight() throws Exception {
    178         verifyPositionWithLimitedAspectRatio(NAV_BAR_RIGHT, new Rect(0, 0, 2000, 1000), 1.5f,
    179                 new Rect(0, 0, 1500, 1000));
    180     }
    181 
    182     private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds,
    183             float aspectRatio, Rect expectedActivityBounds) {
    184         // Verify with nav bar on the right.
    185         when(mService.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition);
    186         mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
    187         mActivity.info.maxAspectRatio = aspectRatio;
    188         mActivity.ensureActivityConfiguration(
    189                 0 /* globalChanges */, false /* preserveWindow */);
    190         assertEquals(expectedActivityBounds, mActivity.getBounds());
    191     }
    192 
    193     @Test
    194     public void testCanBeLaunchedOnDisplay() throws Exception {
    195         testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
    196                 true /*activityResizeable*/, true /*expected*/);
    197 
    198         testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
    199                 false /*activityResizeable*/, false /*expected*/);
    200 
    201         testSupportsLaunchingResizeable(true /*taskPresent*/, false /*taskResizeable*/,
    202                 true /*activityResizeable*/, false /*expected*/);
    203 
    204         testSupportsLaunchingResizeable(true /*taskPresent*/, true /*taskResizeable*/,
    205                 false /*activityResizeable*/, true /*expected*/);
    206     }
    207 
    208     @Test
    209     public void testsApplyOptionsLocked() {
    210         ActivityOptions activityOptions = ActivityOptions.makeBasic();
    211 
    212         // Set and apply options for ActivityRecord. Pending options should be cleared
    213         mActivity.updateOptionsLocked(activityOptions);
    214         mActivity.applyOptionsLocked();
    215         assertNull(mActivity.pendingOptions);
    216 
    217         // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
    218         // Pending options should be cleared for both ActivityRecords
    219         ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
    220         activity2.updateOptionsLocked(activityOptions);
    221         mActivity.updateOptionsLocked(activityOptions);
    222         mActivity.applyOptionsLocked();
    223         assertNull(mActivity.pendingOptions);
    224         assertNull(activity2.pendingOptions);
    225 
    226         // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
    227         // Pending options should be cleared for only ActivityRecord that was applied
    228         TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
    229         activity2 = new ActivityBuilder(mService).setTask(task2).build();
    230         activity2.updateOptionsLocked(activityOptions);
    231         mActivity.updateOptionsLocked(activityOptions);
    232         mActivity.applyOptionsLocked();
    233         assertNull(mActivity.pendingOptions);
    234         assertNotNull(activity2.pendingOptions);
    235     }
    236 
    237     private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable,
    238             boolean activityResizeable, boolean expected) {
    239         mService.mSupportsMultiWindow = true;
    240 
    241         final TaskRecord task = taskPresent
    242                 ? new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build() : null;
    243 
    244         if (task != null) {
    245             task.setResizeMode(taskResizeable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE);
    246         }
    247 
    248         final ActivityRecord record = new ActivityBuilder(mService).setTask(task).build();
    249         record.info.resizeMode = activityResizeable
    250                 ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
    251 
    252         record.canBeLaunchedOnDisplay(DEFAULT_DISPLAY);
    253 
    254 
    255         verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected),
    256                 anyInt(), anyInt(), eq(record.info));
    257     }
    258 }
    259