Home | History | Annotate | Download | only in am
      1 /*
      2  * Copyright (C) 2016 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.server.am;
     18 
     19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
     20 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
     21 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
     22 import static android.server.am.ActivityLauncher.KEY_LAUNCH_ACTIVITY;
     23 import static android.server.am.ActivityLauncher.KEY_NEW_TASK;
     24 import static android.server.am.ActivityLauncher.KEY_TARGET_COMPONENT;
     25 import static android.server.am.ActivityManagerDisplayTestBase.ReportedDisplayMetrics.getDisplayMetrics;
     26 import static android.server.am.ActivityManagerState.STATE_RESUMED;
     27 import static android.server.am.ActivityManagerState.STATE_STOPPED;
     28 import static android.server.am.ComponentNameUtils.getActivityName;
     29 import static android.server.am.ComponentNameUtils.getWindowName;
     30 import static android.server.am.Components.ALT_LAUNCHING_ACTIVITY;
     31 import static android.server.am.Components.BROADCAST_RECEIVER_ACTIVITY;
     32 import static android.server.am.Components.BroadcastReceiverActivity.ACTION_TRIGGER_BROADCAST;
     33 import static android.server.am.Components.BroadcastReceiverActivity.EXTRA_FINISH_BROADCAST;
     34 import static android.server.am.Components.LAUNCHING_ACTIVITY;
     35 import static android.server.am.Components.LAUNCH_BROADCAST_ACTION;
     36 import static android.server.am.Components.LAUNCH_BROADCAST_RECEIVER;
     37 import static android.server.am.Components.NON_RESIZEABLE_ACTIVITY;
     38 import static android.server.am.Components.RESIZEABLE_ACTIVITY;
     39 import static android.server.am.Components.SHOW_WHEN_LOCKED_ATTR_ACTIVITY;
     40 import static android.server.am.Components.TEST_ACTIVITY;
     41 import static android.server.am.Components.VIRTUAL_DISPLAY_ACTIVITY;
     42 import static android.server.am.StateLogger.logAlways;
     43 import static android.server.am.StateLogger.logE;
     44 import static android.server.am.UiDeviceUtils.pressSleepButton;
     45 import static android.server.am.UiDeviceUtils.pressWakeupButton;
     46 import static android.server.am.second.Components.SECOND_ACTIVITY;
     47 import static android.server.am.second.Components.SECOND_LAUNCH_BROADCAST_ACTION;
     48 import static android.server.am.second.Components.SECOND_LAUNCH_BROADCAST_RECEIVER;
     49 import static android.server.am.second.Components.SECOND_NO_EMBEDDING_ACTIVITY;
     50 import static android.server.am.third.Components.THIRD_ACTIVITY;
     51 import static android.view.Display.DEFAULT_DISPLAY;
     52 
     53 import static org.junit.Assert.assertEquals;
     54 import static org.junit.Assert.assertFalse;
     55 import static org.junit.Assert.assertNotNull;
     56 import static org.junit.Assert.assertNull;
     57 import static org.junit.Assert.assertTrue;
     58 import static org.junit.Assert.fail;
     59 import static org.junit.Assume.assumeTrue;
     60 
     61 import android.content.ComponentName;
     62 import android.os.SystemClock;
     63 import android.platform.test.annotations.Presubmit;
     64 import android.server.am.ActivityManagerState.ActivityDisplay;
     65 import android.support.test.filters.FlakyTest;
     66 
     67 import androidx.annotation.Nullable;
     68 
     69 import org.junit.Before;
     70 import org.junit.Test;
     71 
     72 import java.util.concurrent.TimeUnit;
     73 import java.util.List;
     74 import java.util.regex.Matcher;
     75 import java.util.regex.Pattern;
     76 
     77 /**
     78  * Build/Install/Run:
     79  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerMultiDisplayTests
     80  */
     81 @Presubmit
     82 @FlakyTest(bugId = 77652261)
     83 public class ActivityManagerMultiDisplayTests extends ActivityManagerDisplayTestBase {
     84 
     85     // TODO(b/70247058): Use {@link Context#sendBroadcast(Intent).
     86     // Shell command to finish {@link #BROADCAST_RECEIVER_ACTIVITY}.
     87     private static final String FINISH_ACTIVITY_BROADCAST = "am broadcast -a "
     88             + ACTION_TRIGGER_BROADCAST + " --ez " + EXTRA_FINISH_BROADCAST + " true";
     89     // Shell command to launch activity via {@link #BROADCAST_RECEIVER_ACTIVITY}.
     90     private static final String LAUNCH_ACTIVITY_BROADCAST = "am broadcast -a "
     91             + ACTION_TRIGGER_BROADCAST + " --ez " + KEY_LAUNCH_ACTIVITY + " true --ez "
     92             + KEY_NEW_TASK + " true --es " + KEY_TARGET_COMPONENT + " ";
     93 
     94     @Before
     95     @Override
     96     public void setUp() throws Exception {
     97         super.setUp();
     98 
     99         assumeTrue(supportsMultiDisplay());
    100     }
    101 
    102     /**
    103      * Tests launching an activity on virtual display.
    104      */
    105     @Test
    106     public void testLaunchActivityOnSecondaryDisplay() throws Exception {
    107         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    108             // Create new virtual display.
    109             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    110 
    111             // Launch activity on new secondary display.
    112             final LogSeparator logSeparator = separateLogs();
    113             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
    114             mAmWmState.computeState(TEST_ACTIVITY);
    115 
    116             mAmWmState.assertFocusedActivity(
    117                     "Activity launched on secondary display must be focused",
    118                     TEST_ACTIVITY);
    119 
    120             // Check that activity is on the right display.
    121             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    122             final ActivityManagerState.ActivityStack frontStack =
    123                     mAmWmState.getAmState().getStackById(frontStackId);
    124             assertEquals("Launched activity must be on the secondary display and resumed",
    125                     getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
    126             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
    127 
    128             // Check that activity config corresponds to display config.
    129             final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY,
    130                     logSeparator);
    131             assertEquals("Activity launched on secondary display must have proper configuration",
    132                     CUSTOM_DENSITY_DPI, reportedSizes.densityDpi);
    133         }
    134     }
    135 
    136     /**
    137      * Tests launching an activity on primary display explicitly.
    138      */
    139     @Test
    140     public void testLaunchActivityOnPrimaryDisplay() throws Exception {
    141         // Launch activity on primary display explicitly.
    142         launchActivityOnDisplay(LAUNCHING_ACTIVITY, 0);
    143         mAmWmState.computeState(LAUNCHING_ACTIVITY);
    144 
    145         mAmWmState.assertFocusedActivity("Activity launched on primary display must be focused",
    146                 LAUNCHING_ACTIVITY);
    147 
    148         // Check that activity is on the right display.
    149         int frontStackId = mAmWmState.getAmState().getFrontStackId(0 /* displayId */);
    150         ActivityManagerState.ActivityStack frontStack
    151                 = mAmWmState.getAmState().getStackById(frontStackId);
    152         assertEquals("Launched activity must be on the primary display and resumed",
    153                 getActivityName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity);
    154         mAmWmState.assertFocusedStack("Focus must be on primary display", frontStackId);
    155 
    156         // Launch another activity on primary display using the first one
    157         getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).setNewTask(true)
    158                 .setMultipleTask(true).setDisplayId(0).execute();
    159         mAmWmState.computeState(TEST_ACTIVITY);
    160 
    161         mAmWmState.assertFocusedActivity("Activity launched on primary display must be focused",
    162                 TEST_ACTIVITY);
    163 
    164         // Check that activity is on the right display.
    165         frontStackId = mAmWmState.getAmState().getFrontStackId(0 /* displayId */);
    166         frontStack = mAmWmState.getAmState().getStackById(frontStackId);
    167         assertEquals("Launched activity must be on the primary display and resumed",
    168                 getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
    169         mAmWmState.assertFocusedStack("Focus must be on primary display", frontStackId);
    170     }
    171 
    172     /**
    173      * Tests launching a non-resizeable activity on virtual display. It should land on the
    174      * default display.
    175      */
    176     @Test
    177     public void testLaunchNonResizeableActivityOnSecondaryDisplay() throws Exception {
    178         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    179             // Create new virtual display.
    180             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    181 
    182             // Launch activity on new secondary display.
    183             launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY, newDisplay.mId);
    184             mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
    185 
    186             mAmWmState.assertFocusedActivity(
    187                     "Activity launched on secondary display must be focused",
    188                     NON_RESIZEABLE_ACTIVITY);
    189 
    190             // Check that activity is on the right display.
    191             final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY);
    192             final ActivityManagerState.ActivityStack frontStack =
    193                     mAmWmState.getAmState().getStackById(frontStackId);
    194             assertEquals("Launched activity must be on the primary display and resumed",
    195                     getActivityName(NON_RESIZEABLE_ACTIVITY),
    196                     frontStack.mResumedActivity);
    197             mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId);
    198         }
    199     }
    200 
    201     /**
    202      * Tests launching a non-resizeable activity on virtual display while split-screen is active
    203      * on the primary display. It should land on the primary display and dismiss docked stack.
    204      */
    205     @Test
    206     public void testLaunchNonResizeableActivityWithSplitScreen() throws Exception {
    207         assumeTrue(supportsSplitScreenMultiWindow());
    208 
    209         // Start launching activity.
    210         launchActivitiesInSplitScreen(
    211                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
    212                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
    213 
    214         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    215             // Create new virtual display.
    216             final ActivityDisplay newDisplay = virtualDisplaySession.setLaunchInSplitScreen(true)
    217                     .createDisplay();
    218 
    219             // Launch activity on new secondary display.
    220             launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY, newDisplay.mId);
    221             mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
    222 
    223             mAmWmState.assertFocusedActivity(
    224                     "Activity launched on secondary display must be focused",
    225                     NON_RESIZEABLE_ACTIVITY);
    226 
    227             // Check that activity is on the right display.
    228             final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY);
    229             final ActivityManagerState.ActivityStack frontStack =
    230                     mAmWmState.getAmState().getStackById(frontStackId);
    231             assertEquals("Launched activity must be on the primary display and resumed",
    232                     getActivityName(NON_RESIZEABLE_ACTIVITY),
    233                     frontStack.mResumedActivity);
    234             mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId);
    235             mAmWmState.assertDoesNotContainStack("Must not contain docked stack.",
    236                     WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
    237         }
    238     }
    239 
    240     /**
    241      * Tests moving a non-resizeable activity to a virtual display. It should stay on the default
    242      * display with no action performed.
    243      */
    244     @Test
    245     public void testMoveNonResizeableActivityToSecondaryDisplay() throws Exception {
    246         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    247             // Create new virtual display.
    248             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    249             // Launch a non-resizeable activity on a primary display.
    250             launchActivityInNewTask(NON_RESIZEABLE_ACTIVITY);
    251             // Launch a resizeable activity on new secondary display to create a new stack there.
    252             launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
    253             final int externalFrontStackId = mAmWmState.getAmState()
    254                     .getFrontStackId(newDisplay.mId);
    255 
    256             // Try to move the non-resizeable activity to new secondary display.
    257             moveActivityToStack(NON_RESIZEABLE_ACTIVITY, externalFrontStackId);
    258             mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
    259 
    260             mAmWmState.assertFocusedActivity(
    261                     "Activity launched on secondary display must be focused",
    262                     RESIZEABLE_ACTIVITY);
    263 
    264             // Check that activity is in the same stack
    265             final int defaultFrontStackId = mAmWmState.getAmState().getFrontStackId(
    266                     DEFAULT_DISPLAY);
    267             final ActivityManagerState.ActivityStack defaultFrontStack =
    268                     mAmWmState.getAmState().getStackById(defaultFrontStackId);
    269             assertEquals("Launched activity must be on the primary display and resumed",
    270                     getActivityName(NON_RESIZEABLE_ACTIVITY),
    271                     defaultFrontStack.getTopTask().mRealActivity);
    272             mAmWmState.assertFocusedStack("Focus must remain on the secondary display",
    273                     externalFrontStackId);
    274         }
    275     }
    276 
    277     /**
    278      * Tests launching a non-resizeable activity on virtual display from activity there. It should
    279      * land on the secondary display based on the resizeability of the root activity of the task.
    280      */
    281     @Test
    282     public void testLaunchNonResizeableActivityFromSecondaryDisplaySameTask() throws Exception {
    283         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    284             // Create new simulated display.
    285             final ActivityDisplay newDisplay = virtualDisplaySession.setSimulateDisplay(true)
    286                     .createDisplay();
    287 
    288             // Launch activity on new secondary display.
    289             launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId);
    290             mAmWmState.assertFocusedActivity(
    291                     "Activity launched on secondary display must be focused",
    292                     BROADCAST_RECEIVER_ACTIVITY);
    293 
    294             // Check that launching activity is on the secondary display.
    295             int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    296             ActivityManagerState.ActivityStack frontStack =
    297                     mAmWmState.getAmState().getStackById(frontStackId);
    298             assertEquals("Launched activity must be on the secondary display and resumed",
    299                     getActivityName(BROADCAST_RECEIVER_ACTIVITY),
    300                     frontStack.mResumedActivity);
    301             mAmWmState.assertFocusedStack("Focus must be on the secondary display", frontStackId);
    302 
    303             // Launch non-resizeable activity from secondary display.
    304             executeShellCommand(
    305                     LAUNCH_ACTIVITY_BROADCAST + getActivityName(NON_RESIZEABLE_ACTIVITY));
    306             mAmWmState.computeState(NON_RESIZEABLE_ACTIVITY);
    307 
    308             // Check that non-resizeable activity is on the secondary display, because of the
    309             // resizeable root of the task.
    310             frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    311             frontStack = mAmWmState.getAmState().getStackById(frontStackId);
    312             assertEquals("Launched activity must be on the primary display and resumed",
    313                     getActivityName(NON_RESIZEABLE_ACTIVITY),
    314                     frontStack.mResumedActivity);
    315             mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId);
    316         }
    317     }
    318 
    319     /**
    320      * Tests launching a non-resizeable activity on virtual display from activity there. It should
    321      * land on some different suitable display (usually - on the default one).
    322      */
    323     @Test
    324     public void testLaunchNonResizeableActivityFromSecondaryDisplayNewTask() throws Exception {
    325         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    326             // Create new virtual display.
    327             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    328 
    329             // Launch activity on new secondary display.
    330             launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
    331             mAmWmState.assertFocusedActivity(
    332                     "Activity launched on secondary display must be focused",
    333                     LAUNCHING_ACTIVITY);
    334 
    335             // Check that launching activity is on the secondary display.
    336             int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    337             ActivityManagerState.ActivityStack frontStack =
    338                     mAmWmState.getAmState().getStackById(frontStackId);
    339             assertEquals("Launched activity must be on the secondary display and resumed",
    340                     getActivityName(LAUNCHING_ACTIVITY),
    341                     frontStack.mResumedActivity);
    342             mAmWmState.assertFocusedStack("Focus must be on the secondary display", frontStackId);
    343 
    344             // Launch non-resizeable activity from secondary display.
    345             getLaunchActivityBuilder().setTargetActivity(NON_RESIZEABLE_ACTIVITY)
    346                     .setNewTask(true).setMultipleTask(true).execute();
    347 
    348             // Check that non-resizeable activity is on the primary display.
    349             frontStackId = mAmWmState.getAmState().getFocusedStackId();
    350             frontStack = mAmWmState.getAmState().getStackById(frontStackId);
    351             assertFalse("Launched activity must be on a different display",
    352                     newDisplay.mId == frontStack.mDisplayId);
    353             assertEquals("Launched activity must be resumed",
    354                     getActivityName(NON_RESIZEABLE_ACTIVITY),
    355                     frontStack.mResumedActivity);
    356             mAmWmState.assertFocusedStack("Focus must be on a just launched activity",
    357                     frontStackId);
    358         }
    359     }
    360 
    361     /**
    362      * Tests launching an activity on a virtual display without special permission must not be
    363      * allowed.
    364      */
    365     @Test
    366     public void testLaunchWithoutPermissionOnVirtualDisplay() throws Exception {
    367         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    368             // Create new virtual display.
    369             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    370 
    371             final LogSeparator logSeparator = separateLogs();
    372 
    373             // Try to launch an activity and check it security exception was triggered.
    374             getLaunchActivityBuilder()
    375                     .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER,
    376                             SECOND_LAUNCH_BROADCAST_ACTION)
    377                     .setDisplayId(newDisplay.mId)
    378                     .setTargetActivity(TEST_ACTIVITY)
    379                     .execute();
    380 
    381             assertSecurityException("ActivityLauncher", logSeparator);
    382 
    383             mAmWmState.computeState(TEST_ACTIVITY);
    384             assertFalse("Restricted activity must not be launched",
    385                     mAmWmState.getAmState().containsActivity(TEST_ACTIVITY));
    386         }
    387     }
    388 
    389     /**
    390      * Tests launching an activity on a virtual display without special permission must be allowed
    391      * for activities with same UID.
    392      */
    393     @Test
    394     public void testLaunchWithoutPermissionOnVirtualDisplayByOwner() throws Exception {
    395         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    396             // Create new virtual display.
    397             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    398 
    399             // Try to launch an activity and check it security exception was triggered.
    400             getLaunchActivityBuilder()
    401                     .setUseBroadcastReceiver(LAUNCH_BROADCAST_RECEIVER, LAUNCH_BROADCAST_ACTION)
    402                     .setDisplayId(newDisplay.mId)
    403                     .setTargetActivity(TEST_ACTIVITY)
    404                     .execute();
    405 
    406             mAmWmState.waitForValidState(TEST_ACTIVITY);
    407 
    408             final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
    409             final ActivityManagerState.ActivityStack focusedStack =
    410                     mAmWmState.getAmState().getStackById(externalFocusedStackId);
    411             assertEquals("Focused stack must be on secondary display", newDisplay.mId,
    412                     focusedStack.mDisplayId);
    413 
    414             mAmWmState.assertFocusedActivity("Focus must be on newly launched app",
    415                     TEST_ACTIVITY);
    416             assertEquals("Activity launched by owner must be on external display",
    417                     externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
    418         }
    419     }
    420 
    421     /**
    422      * Tests launching an activity on virtual display and then launching another activity via shell
    423      * command and without specifying the display id - the second activity must appear on the
    424      * primary display.
    425      */
    426     @Test
    427     public void testConsequentLaunchActivity() throws Exception {
    428         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    429             // Create new virtual display.
    430             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    431 
    432             // Launch activity on new secondary display.
    433             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
    434             mAmWmState.computeState(TEST_ACTIVITY);
    435 
    436             mAmWmState.assertFocusedActivity(
    437                     "Activity launched on secondary display must be focused",
    438                     TEST_ACTIVITY);
    439 
    440             // Launch second activity without specifying display.
    441             launchActivity(LAUNCHING_ACTIVITY);
    442             mAmWmState.computeState(LAUNCHING_ACTIVITY);
    443 
    444             // Check that activity is launched in focused stack on primary display.
    445             mAmWmState.assertFocusedActivity("Launched activity must be focused",
    446                     LAUNCHING_ACTIVITY);
    447             final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY);
    448             final ActivityManagerState.ActivityStack frontStack =
    449                     mAmWmState.getAmState().getStackById(frontStackId);
    450             assertEquals("Launched activity must be resumed in front stack",
    451                     getActivityName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity);
    452             assertEquals("Front stack must be on primary display",
    453                     DEFAULT_DISPLAY, frontStack.mDisplayId);
    454         }
    455     }
    456 
    457     /**
    458      * Tests launching an activity on simulated display and then launching another activity from the
    459      * first one - it must appear on the secondary display, because it was launched from there.
    460      */
    461     @Test
    462     public void testConsequentLaunchActivityFromSecondaryDisplay() throws Exception {
    463         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    464             // Create new simulated display.
    465             final ActivityDisplay newDisplay = virtualDisplaySession.setSimulateDisplay(true)
    466                     .createDisplay();
    467 
    468             // Launch activity on new secondary display.
    469             launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
    470             mAmWmState.computeState(new WaitForValidActivityState(LAUNCHING_ACTIVITY));
    471 
    472             mAmWmState.assertFocusedActivity(
    473                     "Activity launched on secondary display must be resumed",
    474                     LAUNCHING_ACTIVITY);
    475 
    476             // Launch second activity from app on secondary display without specifying display id.
    477             getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute();
    478             mAmWmState.computeState(TEST_ACTIVITY);
    479 
    480             // Check that activity is launched in focused stack on external display.
    481             mAmWmState.assertFocusedActivity("Launched activity must be focused",
    482                     TEST_ACTIVITY);
    483             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    484             final ActivityManagerState.ActivityStack frontStack =
    485                     mAmWmState.getAmState().getStackById(frontStackId);
    486             assertEquals("Launched activity must be resumed in front stack",
    487                     getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
    488         }
    489     }
    490 
    491     /**
    492      * Tests launching an activity on virtual display and then launching another activity from the
    493      * first one - it must appear on the secondary display, because it was launched from there.
    494      */
    495     @Test
    496     public void testConsequentLaunchActivityFromVirtualDisplay() throws Exception {
    497         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    498             // Create new virtual display.
    499             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    500 
    501             // Launch activity on new secondary display.
    502             launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
    503             mAmWmState.computeState(LAUNCHING_ACTIVITY);
    504 
    505             mAmWmState.assertFocusedActivity(
    506                     "Activity launched on secondary display must be resumed",
    507                     LAUNCHING_ACTIVITY);
    508 
    509             // Launch second activity from app on secondary display without specifying display id.
    510             getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute();
    511             mAmWmState.computeState(TEST_ACTIVITY);
    512 
    513             // Check that activity is launched in focused stack on external display.
    514             mAmWmState.assertFocusedActivity("Launched activity must be focused",
    515                     TEST_ACTIVITY);
    516             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    517             final ActivityManagerState.ActivityStack frontStack = mAmWmState.getAmState()
    518                     .getStackById(frontStackId);
    519             assertEquals("Launched activity must be resumed in front stack",
    520                     getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
    521         }
    522     }
    523 
    524     /**
    525      * Tests launching an activity on virtual display and then launching another activity from the
    526      * first one with specifying the target display - it must appear on the secondary display.
    527      */
    528     @Test
    529     public void testConsequentLaunchActivityFromVirtualDisplayToTargetDisplay() throws Exception {
    530         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    531             // Create new virtual display.
    532             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    533 
    534             // Launch activity on new secondary display.
    535             launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
    536             mAmWmState.computeState(LAUNCHING_ACTIVITY);
    537 
    538             mAmWmState.assertFocusedActivity(
    539                     "Activity launched on secondary display must be resumed",
    540                     LAUNCHING_ACTIVITY);
    541 
    542             // Launch second activity from app on secondary display specifying same display id.
    543             getLaunchActivityBuilder()
    544                     .setTargetActivity(SECOND_ACTIVITY)
    545                     .setDisplayId(newDisplay.mId)
    546                     .execute();
    547             mAmWmState.computeState(TEST_ACTIVITY);
    548 
    549             // Check that activity is launched in focused stack on external display.
    550             mAmWmState.assertFocusedActivity("Launched activity must be focused", SECOND_ACTIVITY);
    551             int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    552             ActivityManagerState.ActivityStack frontStack =
    553                     mAmWmState.getAmState().getStackById(frontStackId);
    554             assertEquals("Launched activity must be resumed in front stack",
    555                     getActivityName(SECOND_ACTIVITY), frontStack.mResumedActivity);
    556 
    557             // Launch other activity with different uid and check if it has launched successfully.
    558             getLaunchActivityBuilder()
    559                     .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER,
    560                             SECOND_LAUNCH_BROADCAST_ACTION)
    561                     .setDisplayId(newDisplay.mId)
    562                     .setTargetActivity(THIRD_ACTIVITY)
    563                     .execute();
    564             mAmWmState.waitForValidState(THIRD_ACTIVITY);
    565 
    566             // Check that activity is launched in focused stack on external display.
    567             mAmWmState.assertFocusedActivity("Launched activity must be focused", THIRD_ACTIVITY);
    568             frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    569             frontStack = mAmWmState.getAmState().getStackById(frontStackId);
    570             assertEquals("Launched activity must be resumed in front stack",
    571                     getActivityName(THIRD_ACTIVITY), frontStack.mResumedActivity);
    572         }
    573     }
    574 
    575     /**
    576      * Tests launching an activity on virtual display and then launching another activity that
    577      * doesn't allow embedding - it should fail with security exception.
    578      */
    579     @Test
    580     public void testConsequentLaunchActivityFromVirtualDisplayNoEmbedding() throws Exception {
    581         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    582             // Create new virtual display.
    583             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    584 
    585             // Launch activity on new secondary display.
    586             launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
    587             mAmWmState.computeState(LAUNCHING_ACTIVITY);
    588 
    589             mAmWmState.assertFocusedActivity(
    590                     "Activity launched on secondary display must be resumed",
    591                     LAUNCHING_ACTIVITY);
    592 
    593             final LogSeparator logSeparator = separateLogs();
    594 
    595             // Launch second activity from app on secondary display specifying same display id.
    596             getLaunchActivityBuilder()
    597                     .setTargetActivity(SECOND_NO_EMBEDDING_ACTIVITY)
    598                     .setDisplayId(newDisplay.mId)
    599                     .execute();
    600 
    601             assertSecurityException("ActivityLauncher", logSeparator);
    602         }
    603     }
    604 
    605     /**
    606      * Tests launching an activity to secondary display from activity on primary display.
    607      */
    608     @Test
    609     public void testLaunchActivityFromAppToSecondaryDisplay() throws Exception {
    610         // Start launching activity.
    611         launchActivity(LAUNCHING_ACTIVITY);
    612 
    613         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    614             // Create new simulated display.
    615             final ActivityDisplay newDisplay = virtualDisplaySession.setSimulateDisplay(true)
    616                     .createDisplay();
    617 
    618             // Launch activity on secondary display from the app on primary display.
    619             getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)
    620                     .setDisplayId(newDisplay.mId).execute();
    621 
    622             // Check that activity is launched on external display.
    623             mAmWmState.computeState(TEST_ACTIVITY);
    624             mAmWmState.assertFocusedActivity(
    625                     "Activity launched on secondary display must be focused",
    626                     TEST_ACTIVITY);
    627             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    628             final ActivityManagerState.ActivityStack frontStack =
    629                     mAmWmState.getAmState().getStackById(frontStackId);
    630             assertEquals("Launched activity must be resumed in front stack",
    631                     getActivityName(TEST_ACTIVITY), frontStack.mResumedActivity);
    632         }
    633     }
    634 
    635     /**
    636      * Tests launching activities on secondary and then on primary display to see if the stack
    637      * visibility is not affected.
    638      */
    639     @Test
    640     public void testLaunchActivitiesAffectsVisibility() throws Exception {
    641         // Start launching activity.
    642         launchActivity(LAUNCHING_ACTIVITY);
    643 
    644         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    645             // Create new virtual display.
    646             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    647             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
    648 
    649             // Launch activity on new secondary display.
    650             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
    651             mAmWmState.assertVisibility(TEST_ACTIVITY, true /* visible */);
    652             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
    653 
    654             // Launch activity on primary display and check if it doesn't affect activity on
    655             // secondary display.
    656             getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY).execute();
    657             mAmWmState.waitForValidState(RESIZEABLE_ACTIVITY);
    658             mAmWmState.assertVisibility(TEST_ACTIVITY, true /* visible */);
    659             mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
    660         }
    661     }
    662 
    663     /**
    664      * Test that move-task works when moving between displays.
    665      */
    666     @Test
    667     public void testMoveTaskBetweenDisplays() throws Exception {
    668         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    669             // Create new virtual display.
    670             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    671             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
    672             mAmWmState.assertFocusedActivity("Virtual display activity must be focused",
    673                     VIRTUAL_DISPLAY_ACTIVITY);
    674             final int defaultDisplayStackId = mAmWmState.getAmState().getFocusedStackId();
    675             ActivityManagerState.ActivityStack focusedStack = mAmWmState.getAmState().getStackById(
    676                     defaultDisplayStackId);
    677             assertEquals("Focus must remain on primary display",
    678                     DEFAULT_DISPLAY, focusedStack.mDisplayId);
    679 
    680             // Launch activity on new secondary display.
    681             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
    682             mAmWmState.assertFocusedActivity("Focus must be on secondary display",
    683                     TEST_ACTIVITY);
    684             int focusedStackId = mAmWmState.getAmState().getFocusedStackId();
    685             focusedStack = mAmWmState.getAmState().getStackById(focusedStackId);
    686             assertEquals("Focused stack must be on secondary display",
    687                     newDisplay.mId, focusedStack.mDisplayId);
    688 
    689             // Move activity from secondary display to primary.
    690             moveActivityToStack(TEST_ACTIVITY, defaultDisplayStackId);
    691             mAmWmState.waitForFocusedStack(defaultDisplayStackId);
    692             mAmWmState.assertFocusedActivity("Focus must be on moved activity", TEST_ACTIVITY);
    693             focusedStackId = mAmWmState.getAmState().getFocusedStackId();
    694             focusedStack = mAmWmState.getAmState().getStackById(focusedStackId);
    695             assertEquals("Focus must return to primary display",
    696                     DEFAULT_DISPLAY, focusedStack.mDisplayId);
    697         }
    698     }
    699 
    700     /**
    701      * Tests launching activities on secondary display and then removing it to see if stack focus
    702      * is moved correctly.
    703      * This version launches virtual display creator to fullscreen stack in split-screen.
    704      */
    705     @Test
    706     public void testStackFocusSwitchOnDisplayRemoved() throws Exception {
    707         assumeTrue(supportsSplitScreenMultiWindow());
    708 
    709         // Start launching activity into docked stack.
    710         launchActivitiesInSplitScreen(
    711                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
    712                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
    713         mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
    714 
    715         tryCreatingAndRemovingDisplayWithActivity(true /* splitScreen */,
    716                 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
    717     }
    718 
    719     /**
    720      * Tests launching activities on secondary display and then removing it to see if stack focus
    721      * is moved correctly.
    722      * This version launches virtual display creator to docked stack in split-screen.
    723      */
    724     @Test
    725     public void testStackFocusSwitchOnDisplayRemoved2() throws Exception {
    726         assumeTrue(supportsSplitScreenMultiWindow());
    727 
    728         // Setup split-screen.
    729         launchActivitiesInSplitScreen(
    730                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY),
    731                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY));
    732         mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
    733 
    734         tryCreatingAndRemovingDisplayWithActivity(true /* splitScreen */,
    735                 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
    736     }
    737 
    738     /**
    739      * Tests launching activities on secondary display and then removing it to see if stack focus
    740      * is moved correctly.
    741      * This version works without split-screen.
    742      */
    743     @Test
    744     public void testStackFocusSwitchOnDisplayRemoved3() throws Exception {
    745         // Start an activity on default display to determine default stack.
    746         launchActivity(BROADCAST_RECEIVER_ACTIVITY);
    747         final int focusedStackWindowingMode = mAmWmState.getAmState().getFrontStackWindowingMode(
    748                 DEFAULT_DISPLAY);
    749         // Finish probing activity.
    750         executeShellCommand(FINISH_ACTIVITY_BROADCAST);
    751 
    752         tryCreatingAndRemovingDisplayWithActivity(false /* splitScreen */,
    753                 focusedStackWindowingMode);
    754     }
    755 
    756     /**
    757      * Create a virtual display, launch a test activity there, destroy the display and check if test
    758      * activity is moved to a stack on the default display.
    759      */
    760     private void tryCreatingAndRemovingDisplayWithActivity(boolean splitScreen, int windowingMode)
    761             throws Exception {
    762         LogSeparator logSeparator;
    763         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    764             // Create new virtual display.
    765             final ActivityDisplay newDisplay = virtualDisplaySession
    766                     .setPublicDisplay(true)
    767                     .setLaunchInSplitScreen(splitScreen)
    768                     .createDisplay();
    769             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
    770             if (splitScreen) {
    771                 mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
    772             }
    773 
    774             // Launch activity on new secondary display.
    775             launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
    776             mAmWmState.assertFocusedActivity("Focus must be on secondary display",
    777                     RESIZEABLE_ACTIVITY);
    778             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    779             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
    780 
    781             // Destroy virtual display.
    782             logSeparator = separateLogs();
    783         }
    784 
    785         mAmWmState.computeState(true);
    786         assertActivityLifecycle(RESIZEABLE_ACTIVITY, false /* relaunched */, logSeparator);
    787         mAmWmState.waitForValidState(new WaitForValidActivityState.Builder(RESIZEABLE_ACTIVITY)
    788                 .setWindowingMode(windowingMode)
    789                 .setActivityType(ACTIVITY_TYPE_STANDARD)
    790                 .build());
    791         mAmWmState.assertSanity();
    792         mAmWmState.assertValidBounds(true /* compareTaskAndStackBounds */);
    793 
    794         // Check if the focus is switched back to primary display.
    795         mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
    796         mAmWmState.assertFocusedStack(
    797                 "Default stack on primary display must be focused after display removed",
    798                 windowingMode, ACTIVITY_TYPE_STANDARD);
    799         mAmWmState.assertFocusedActivity(
    800                 "Focus must be switched back to activity on primary display",
    801                 RESIZEABLE_ACTIVITY);
    802     }
    803 
    804     /**
    805      * Tests launching activities on secondary display and then removing it to see if stack focus
    806      * is moved correctly.
    807      */
    808     @Test
    809     public void testStackFocusSwitchOnStackEmptied() throws Exception {
    810         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession();
    811              final LockScreenSession lockScreenSession = new LockScreenSession()) {
    812             // Create new virtual display.
    813             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    814             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
    815             final int focusedStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY);
    816 
    817             // Launch activity on new secondary display.
    818             launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId);
    819             mAmWmState.assertFocusedActivity("Focus must be on secondary display",
    820                     BROADCAST_RECEIVER_ACTIVITY);
    821 
    822             // Lock the device, so that activity containers will be detached.
    823             lockScreenSession.sleepDevice();
    824 
    825             // Finish activity on secondary display.
    826             executeShellCommand(FINISH_ACTIVITY_BROADCAST);
    827 
    828             // Unlock and check if the focus is switched back to primary display.
    829             lockScreenSession.wakeUpDevice()
    830                     .unlockDevice();
    831             mAmWmState.waitForFocusedStack(focusedStackId);
    832             mAmWmState.waitForValidState(VIRTUAL_DISPLAY_ACTIVITY);
    833             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
    834             mAmWmState.assertFocusedActivity("Focus must be switched back to primary display",
    835                     VIRTUAL_DISPLAY_ACTIVITY);
    836         }
    837     }
    838 
    839     /**
    840      * Tests that input events on the primary display take focus from the virtual display.
    841      */
    842     @Test
    843     public void testStackFocusSwitchOnTouchEvent() throws Exception {
    844         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    845             // Create new virtual display.
    846             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    847 
    848             mAmWmState.computeState(VIRTUAL_DISPLAY_ACTIVITY);
    849             mAmWmState.assertFocusedActivity("Focus must be switched back to primary display",
    850                     VIRTUAL_DISPLAY_ACTIVITY);
    851 
    852             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
    853 
    854             mAmWmState.computeState(TEST_ACTIVITY);
    855             mAmWmState.assertFocusedActivity(
    856                     "Activity launched on secondary display must be focused",
    857                     TEST_ACTIVITY);
    858 
    859             final ReportedDisplayMetrics displayMetrics = getDisplayMetrics();
    860             final int width = displayMetrics.getSize().getWidth();
    861             final int height = displayMetrics.getSize().getHeight();
    862             executeShellCommand("input tap " + (width / 2) + " " + (height / 2));
    863 
    864             mAmWmState.computeState(VIRTUAL_DISPLAY_ACTIVITY);
    865             mAmWmState.assertFocusedActivity("Focus must be switched back to primary display",
    866                     VIRTUAL_DISPLAY_ACTIVITY);
    867         }
    868     }
    869 
    870     /** Test that shell is allowed to launch on secondary displays. */
    871     @Test
    872     public void testPermissionLaunchFromShell() throws Exception {
    873         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    874             // Create new virtual display.
    875             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    876             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
    877             mAmWmState.assertFocusedActivity("Virtual display activity must be focused",
    878                     VIRTUAL_DISPLAY_ACTIVITY);
    879             final int defaultDisplayFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
    880             ActivityManagerState.ActivityStack focusedStack = mAmWmState.getAmState().getStackById(
    881                     defaultDisplayFocusedStackId);
    882             assertEquals("Focus must remain on primary display",
    883                     DEFAULT_DISPLAY, focusedStack.mDisplayId);
    884 
    885             // Launch activity on new secondary display.
    886             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
    887             mAmWmState.assertFocusedActivity("Focus must be on secondary display",
    888                     TEST_ACTIVITY);
    889             final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
    890             focusedStack = mAmWmState.getAmState().getStackById(externalFocusedStackId);
    891             assertEquals("Focused stack must be on secondary display", newDisplay.mId,
    892                     focusedStack.mDisplayId);
    893 
    894             // Launch other activity with different uid and check it is launched on dynamic stack on
    895             // secondary display.
    896             final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY)
    897                             + " --display " + newDisplay.mId;
    898             executeShellCommand(startCmd);
    899 
    900             mAmWmState.waitForValidState(SECOND_ACTIVITY);
    901             mAmWmState.assertFocusedActivity(
    902                     "Focus must be on newly launched app", SECOND_ACTIVITY);
    903             assertEquals("Activity launched by system must be on external display",
    904                     externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
    905         }
    906     }
    907 
    908     /** Test that launching from app that is on external display is allowed. */
    909     @Test
    910     public void testPermissionLaunchFromAppOnSecondary() throws Exception {
    911         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    912             // Create new simulated display.
    913             final ActivityDisplay newDisplay = virtualDisplaySession.setSimulateDisplay(true)
    914                     .createDisplay();
    915 
    916             // Launch activity with different uid on secondary display.
    917             final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY)
    918                     + " --display " + newDisplay.mId;
    919             executeShellCommand(startCmd);
    920 
    921             mAmWmState.waitForValidState(SECOND_ACTIVITY);
    922             mAmWmState.assertFocusedActivity(
    923                     "Focus must be on newly launched app", SECOND_ACTIVITY);
    924             final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
    925             ActivityManagerState.ActivityStack focusedStack =
    926                     mAmWmState.getAmState().getStackById(externalFocusedStackId);
    927             assertEquals("Focused stack must be on secondary display", newDisplay.mId,
    928                     focusedStack.mDisplayId);
    929 
    930             // Launch another activity with third different uid from app on secondary display and
    931             // check it is launched on secondary display.
    932             getLaunchActivityBuilder()
    933                     .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER,
    934                             SECOND_LAUNCH_BROADCAST_ACTION)
    935                     .setDisplayId(newDisplay.mId)
    936                     .setTargetActivity(THIRD_ACTIVITY)
    937                     .execute();
    938 
    939             mAmWmState.waitForValidState(THIRD_ACTIVITY);
    940             mAmWmState.assertFocusedActivity("Focus must be on newly launched app", THIRD_ACTIVITY);
    941             assertEquals("Activity launched by app on secondary display must be on that display",
    942                     externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
    943         }
    944     }
    945 
    946     /** Tests that an activity can launch an activity from a different UID into its own task. */
    947     @Test
    948     public void testPermissionLaunchMultiUidTask() throws Exception {
    949         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    950             final ActivityDisplay newDisplay = virtualDisplaySession.setSimulateDisplay(true)
    951                     .createDisplay();
    952 
    953             launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
    954             mAmWmState.computeState(LAUNCHING_ACTIVITY);
    955 
    956             // Check that the first activity is launched onto the secondary display
    957             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
    958             ActivityManagerState.ActivityStack frontStack = mAmWmState.getAmState().getStackById(
    959                     frontStackId);
    960             assertEquals("Activity launched on secondary display must be resumed",
    961                     getActivityName(LAUNCHING_ACTIVITY),
    962                     frontStack.mResumedActivity);
    963             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
    964 
    965             // Launch an activity from a different UID into the first activity's task
    966             getLaunchActivityBuilder().setTargetActivity(SECOND_ACTIVITY).execute();
    967 
    968             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
    969             frontStack = mAmWmState.getAmState().getStackById(frontStackId);
    970             mAmWmState.assertFocusedActivity(
    971                     "Focus must be on newly launched app", SECOND_ACTIVITY);
    972             assertEquals("Secondary display must contain 1 task", 1, frontStack.getTasks().size());
    973         }
    974     }
    975 
    976     /**
    977      * Test that launching from display owner is allowed even when the the display owner
    978      * doesn't have anything on the display.
    979      */
    980     @Test
    981     public void testPermissionLaunchFromOwner() throws Exception {
    982         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
    983             // Create new virtual display.
    984             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
    985             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
    986             mAmWmState.assertFocusedActivity("Virtual display activity must be focused",
    987                     VIRTUAL_DISPLAY_ACTIVITY);
    988             final int defaultDisplayFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
    989             ActivityManagerState.ActivityStack focusedStack =
    990                     mAmWmState.getAmState().getStackById(defaultDisplayFocusedStackId);
    991             assertEquals("Focus must remain on primary display",
    992                     DEFAULT_DISPLAY, focusedStack.mDisplayId);
    993 
    994             // Launch other activity with different uid on secondary display.
    995             final String startCmd = "am start -n " + getActivityName(SECOND_ACTIVITY)
    996                     + " --display " + newDisplay.mId;
    997             executeShellCommand(startCmd);
    998 
    999             mAmWmState.waitForValidState(SECOND_ACTIVITY);
   1000             mAmWmState.assertFocusedActivity(
   1001                     "Focus must be on newly launched app", SECOND_ACTIVITY);
   1002             final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
   1003             focusedStack = mAmWmState.getAmState().getStackById(externalFocusedStackId);
   1004             assertEquals("Focused stack must be on secondary display", newDisplay.mId,
   1005                     focusedStack.mDisplayId);
   1006 
   1007             // Check that owner uid can launch its own activity on secondary display.
   1008             getLaunchActivityBuilder()
   1009                     .setUseBroadcastReceiver(LAUNCH_BROADCAST_RECEIVER, LAUNCH_BROADCAST_ACTION)
   1010                     .setNewTask(true)
   1011                     .setMultipleTask(true)
   1012                     .setDisplayId(newDisplay.mId)
   1013                     .execute();
   1014 
   1015             mAmWmState.waitForValidState(TEST_ACTIVITY);
   1016             mAmWmState.assertFocusedActivity("Focus must be on newly launched app",
   1017                     TEST_ACTIVITY);
   1018             assertEquals("Activity launched by owner must be on external display",
   1019                     externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
   1020         }
   1021     }
   1022 
   1023     /**
   1024      * Test that launching from app that is not present on external display and doesn't own it to
   1025      * that external display is not allowed.
   1026      */
   1027     @Test
   1028     public void testPermissionLaunchFromDifferentApp() throws Exception {
   1029         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1030             // Create new virtual display.
   1031             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
   1032             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
   1033             mAmWmState.assertFocusedActivity("Virtual display activity must be focused",
   1034                     VIRTUAL_DISPLAY_ACTIVITY);
   1035             final int defaultDisplayFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
   1036             ActivityManagerState.ActivityStack focusedStack = mAmWmState.getAmState().getStackById(
   1037                     defaultDisplayFocusedStackId);
   1038             assertEquals("Focus must remain on primary display",
   1039                     DEFAULT_DISPLAY, focusedStack.mDisplayId);
   1040 
   1041             // Launch activity on new secondary display.
   1042             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
   1043             mAmWmState.assertFocusedActivity("Focus must be on secondary display",
   1044                     TEST_ACTIVITY);
   1045             final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId();
   1046             focusedStack = mAmWmState.getAmState().getStackById(externalFocusedStackId);
   1047             assertEquals("Focused stack must be on secondary display", newDisplay.mId,
   1048                     focusedStack.mDisplayId);
   1049 
   1050             final LogSeparator logSeparator = separateLogs();
   1051 
   1052             // Launch other activity with different uid and check security exception is triggered.
   1053             getLaunchActivityBuilder()
   1054                     .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER,
   1055                             SECOND_LAUNCH_BROADCAST_ACTION)
   1056                     .setDisplayId(newDisplay.mId)
   1057                     .setTargetActivity(THIRD_ACTIVITY)
   1058                     .execute();
   1059 
   1060             assertSecurityException("ActivityLauncher", logSeparator);
   1061 
   1062             mAmWmState.waitForValidState(TEST_ACTIVITY);
   1063             mAmWmState.assertFocusedActivity("Focus must be on first activity", TEST_ACTIVITY);
   1064             assertEquals("Focused stack must be on secondary display's stack",
   1065                     externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId());
   1066         }
   1067     }
   1068 
   1069     private void assertSecurityException(String component, LogSeparator logSeparator)
   1070             throws Exception {
   1071         final Pattern pattern = Pattern.compile(".*SecurityException launching activity.*");
   1072         for (int retry = 1; retry <= 5; retry++) {
   1073             String[] logs = getDeviceLogsForComponents(logSeparator, component);
   1074             for (String line : logs) {
   1075                 Matcher m = pattern.matcher(line);
   1076                 if (m.matches()) {
   1077                     return;
   1078                 }
   1079             }
   1080             logAlways("***Waiting for SecurityException for " + component + " ... retry=" + retry);
   1081             try {
   1082                 Thread.sleep(500);
   1083             } catch (InterruptedException e) {
   1084             }
   1085         }
   1086         fail("Expected exception for " + component + " not found");
   1087     }
   1088 
   1089     /**
   1090      * Test that only private virtual display can show content with insecure keyguard.
   1091      */
   1092     @Test
   1093     public void testFlagShowWithInsecureKeyguardOnPublicVirtualDisplay() throws Exception {
   1094         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1095             // Try to create new show-with-insecure-keyguard public virtual display.
   1096             final ActivityDisplay newDisplay = virtualDisplaySession
   1097                     .setPublicDisplay(true)
   1098                     .setCanShowWithInsecureKeyguard(true)
   1099                     .setMustBeCreated(false)
   1100                     .createDisplay();
   1101 
   1102             // Check that the display is not created.
   1103             assertNull(newDisplay);
   1104         }
   1105     }
   1106 
   1107     /**
   1108      * Test that all activities that were on the private display are destroyed on display removal.
   1109      */
   1110     @Test
   1111     public void testContentDestroyOnDisplayRemoved() throws Exception {
   1112         LogSeparator logSeparator;
   1113         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1114             // Create new private virtual display.
   1115             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
   1116             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
   1117 
   1118             // Launch activities on new secondary display.
   1119             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
   1120             mAmWmState.assertVisibility(TEST_ACTIVITY, true /* visible */);
   1121             mAmWmState.assertFocusedActivity("Launched activity must be focused",
   1122                     TEST_ACTIVITY);
   1123             launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
   1124             mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
   1125             mAmWmState.assertFocusedActivity("Launched activity must be focused",
   1126                     RESIZEABLE_ACTIVITY);
   1127 
   1128             // Destroy the display and check if activities are removed from system.
   1129             logSeparator = separateLogs();
   1130         }
   1131 
   1132         mAmWmState.waitForWithAmState(
   1133                 (state) -> !state.containsActivity(TEST_ACTIVITY)
   1134                         && !state.containsActivity(RESIZEABLE_ACTIVITY),
   1135                 "Waiting for activity to be removed");
   1136         mAmWmState.waitForWithWmState(
   1137                 (state) -> !state.containsWindow(getWindowName(TEST_ACTIVITY))
   1138                         && !state.containsWindow(getWindowName(RESIZEABLE_ACTIVITY)),
   1139                 "Waiting for activity window to be gone");
   1140 
   1141         // Check AM state.
   1142         assertFalse("Activity from removed display must be destroyed",
   1143                 mAmWmState.getAmState().containsActivity(TEST_ACTIVITY));
   1144         assertFalse("Activity from removed display must be destroyed",
   1145                 mAmWmState.getAmState().containsActivity(RESIZEABLE_ACTIVITY));
   1146         // Check WM state.
   1147         assertFalse("Activity windows from removed display must be destroyed",
   1148                 mAmWmState.getWmState().containsWindow(getWindowName(TEST_ACTIVITY)));
   1149         assertFalse("Activity windows from removed display must be destroyed",
   1150                 mAmWmState.getWmState().containsWindow(getWindowName(RESIZEABLE_ACTIVITY)));
   1151         // Check activity logs.
   1152         assertActivityDestroyed(TEST_ACTIVITY, logSeparator);
   1153         assertActivityDestroyed(RESIZEABLE_ACTIVITY, logSeparator);
   1154     }
   1155 
   1156     /**
   1157      * Test that the update of display metrics updates all its content.
   1158      */
   1159     @Test
   1160     public void testDisplayResize() throws Exception {
   1161         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1162             // Create new virtual display.
   1163             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
   1164             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
   1165 
   1166             // Launch a resizeable activity on new secondary display.
   1167             final LogSeparator initialLogSeparator = separateLogs();
   1168             launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
   1169             mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
   1170             mAmWmState.assertFocusedActivity("Launched activity must be focused",
   1171                     RESIZEABLE_ACTIVITY);
   1172 
   1173             // Grab reported sizes and compute new with slight size change.
   1174             final ReportedSizes initialSize = getLastReportedSizesForActivity(
   1175                     RESIZEABLE_ACTIVITY, initialLogSeparator);
   1176 
   1177             // Resize the display
   1178             final LogSeparator logSeparator = separateLogs();
   1179             virtualDisplaySession.resizeDisplay();
   1180 
   1181             mAmWmState.waitForWithAmState(amState -> {
   1182                 try {
   1183                     return readConfigChangeNumber(RESIZEABLE_ACTIVITY, logSeparator) == 1
   1184                             && amState.hasActivityState(RESIZEABLE_ACTIVITY, STATE_RESUMED);
   1185                 } catch (Exception e) {
   1186                     logE("Error waiting for valid state: " + e.getMessage());
   1187                     return false;
   1188                 }
   1189             }, "Wait for the configuration change to happen and for activity to be resumed.");
   1190 
   1191             mAmWmState.computeState(false /* compareTaskAndStackBounds */,
   1192                     new WaitForValidActivityState(RESIZEABLE_ACTIVITY),
   1193                     new WaitForValidActivityState(VIRTUAL_DISPLAY_ACTIVITY));
   1194             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true);
   1195             mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true);
   1196 
   1197             // Check if activity in virtual display was resized properly.
   1198             assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY, 0 /* numRelaunch */,
   1199                     1 /* numConfigChange */, logSeparator);
   1200 
   1201             final ReportedSizes updatedSize = getLastReportedSizesForActivity(
   1202                     RESIZEABLE_ACTIVITY, logSeparator);
   1203             assertTrue(updatedSize.widthDp <= initialSize.widthDp);
   1204             assertTrue(updatedSize.heightDp <= initialSize.heightDp);
   1205             assertTrue(updatedSize.displayWidth == initialSize.displayWidth / 2);
   1206             assertTrue(updatedSize.displayHeight == initialSize.displayHeight / 2);
   1207         }
   1208     }
   1209 
   1210     /** Read the number of configuration changes sent to activity from logs. */
   1211     private int readConfigChangeNumber(ComponentName activityName, LogSeparator logSeparator)
   1212             throws Exception {
   1213         return (new ActivityLifecycleCounts(activityName, logSeparator)).mConfigurationChangedCount;
   1214     }
   1215 
   1216     /**
   1217      * Tests that when an activity is launched with displayId specified and there is an existing
   1218      * matching task on some other display - that task will moved to the target display.
   1219      */
   1220     @Test
   1221     public void testMoveToDisplayOnLaunch() throws Exception {
   1222         // Launch activity with unique affinity, so it will the only one in its task.
   1223         launchActivity(LAUNCHING_ACTIVITY);
   1224 
   1225         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1226             // Create new virtual display.
   1227             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
   1228             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
   1229             // Launch something to that display so that a new stack is created. We need this to be
   1230             // able to compare task numbers in stacks later.
   1231             launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
   1232             mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
   1233 
   1234             final int stackNum = mAmWmState.getAmState().getDisplay(DEFAULT_DISPLAY)
   1235                     .mStacks.size();
   1236             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
   1237             final int taskNumOnSecondary = mAmWmState.getAmState().getStackById(frontStackId)
   1238                     .getTasks().size();
   1239 
   1240             // Launch activity on new secondary display.
   1241             // Using custom command here, because normally we add flags
   1242             // {@link Intent#FLAG_ACTIVITY_NEW_TASK} and {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
   1243             // when launching on some specific display. We don't do it here as we want an existing
   1244             // task to be used.
   1245             final String launchCommand = "am start -n " + getActivityName(LAUNCHING_ACTIVITY)
   1246                     + " --display " + newDisplay.mId;
   1247             executeShellCommand(launchCommand);
   1248             mAmWmState.waitForActivityState(LAUNCHING_ACTIVITY, STATE_RESUMED);
   1249 
   1250             // Check that activity is brought to front.
   1251             mAmWmState.assertFocusedActivity("Existing task must be brought to front",
   1252                     LAUNCHING_ACTIVITY);
   1253             mAmWmState.assertResumedActivity("Existing task must be resumed",
   1254                     LAUNCHING_ACTIVITY);
   1255 
   1256             // Check that activity is on the right display.
   1257             final ActivityManagerState.ActivityStack firstFrontStack =
   1258                     mAmWmState.getAmState().getStackById(frontStackId);
   1259             assertEquals("Activity must be moved to the secondary display",
   1260                     getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
   1261             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
   1262 
   1263             // Check that task has moved from primary display to secondary.
   1264             final int stackNumFinal = mAmWmState.getAmState().getDisplay(DEFAULT_DISPLAY)
   1265                     .mStacks.size();
   1266             assertEquals("Stack number in default stack must be decremented.", stackNum - 1,
   1267                     stackNumFinal);
   1268             final int taskNumFinalOnSecondary = mAmWmState.getAmState().getStackById(frontStackId)
   1269                     .getTasks().size();
   1270             assertEquals("Task number in stack on external display must be incremented.",
   1271                     taskNumOnSecondary + 1, taskNumFinalOnSecondary);
   1272         }
   1273     }
   1274 
   1275     /**
   1276      * Tests that when an activity is launched with displayId specified and there is an existing
   1277      * matching task on some other display - that task will moved to the target display.
   1278      */
   1279     @Test
   1280     public void testMoveToEmptyDisplayOnLaunch() throws Exception {
   1281         // Launch activity with unique affinity, so it will the only one in its task.
   1282         launchActivity(LAUNCHING_ACTIVITY);
   1283 
   1284         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1285             // Create new virtual display.
   1286             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
   1287             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
   1288 
   1289             final int stackNum = mAmWmState.getAmState().getDisplay(DEFAULT_DISPLAY).mStacks.size();
   1290 
   1291             // Launch activity on new secondary display.
   1292             // Using custom command here, because normally we add flags
   1293             // {@link Intent#FLAG_ACTIVITY_NEW_TASK} and {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
   1294             // when launching on some specific display. We don't do it here as we want an existing
   1295             // task to be used.
   1296             final String launchCommand = "am start -n " + getActivityName(LAUNCHING_ACTIVITY)
   1297                     + " --display " + newDisplay.mId;
   1298             executeShellCommand(launchCommand);
   1299             mAmWmState.waitForActivityState(LAUNCHING_ACTIVITY, STATE_RESUMED);
   1300 
   1301             // Check that activity is brought to front.
   1302             mAmWmState.assertFocusedActivity("Existing task must be brought to front",
   1303                     LAUNCHING_ACTIVITY);
   1304             mAmWmState.assertResumedActivity("Existing task must be resumed",
   1305                     LAUNCHING_ACTIVITY);
   1306 
   1307             // Check that activity is on the right display.
   1308             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
   1309             final ActivityManagerState.ActivityStack firstFrontStack =
   1310                     mAmWmState.getAmState().getStackById(frontStackId);
   1311             assertEquals("Activity must be moved to the secondary display",
   1312                     getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
   1313             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
   1314 
   1315             // Check that task has moved from primary display to secondary.
   1316             final int stackNumFinal = mAmWmState.getAmState().getDisplay(DEFAULT_DISPLAY)
   1317                     .mStacks.size();
   1318             assertEquals("Stack number in default stack must be decremented.", stackNum - 1,
   1319                     stackNumFinal);
   1320         }
   1321     }
   1322 
   1323     /**
   1324      * Tests that when primary display is rotated secondary displays are not affected.
   1325      */
   1326     @Test
   1327     public void testRotationNotAffectingSecondaryScreen() throws Exception {
   1328         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1329             // Create new virtual display.
   1330             final ActivityDisplay newDisplay = virtualDisplaySession.setResizeDisplay(false)
   1331                     .createDisplay();
   1332             mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
   1333 
   1334             // Launch activity on new secondary display.
   1335             LogSeparator logSeparator = separateLogs();
   1336             launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId);
   1337             mAmWmState.assertFocusedActivity("Focus must be on secondary display",
   1338                     RESIZEABLE_ACTIVITY);
   1339             final ReportedSizes initialSizes = getLastReportedSizesForActivity(
   1340                     RESIZEABLE_ACTIVITY, logSeparator);
   1341             assertNotNull("Test activity must have reported initial sizes on launch", initialSizes);
   1342 
   1343             try (final RotationSession rotationSession = new RotationSession()) {
   1344                 // Rotate primary display and check that activity on secondary display is not
   1345                 // affected.
   1346 
   1347                 rotateAndCheckSameSizes(rotationSession, RESIZEABLE_ACTIVITY);
   1348 
   1349                 // Launch activity to secondary display when primary one is rotated.
   1350                 final int initialRotation = mAmWmState.getWmState().getRotation();
   1351                 rotationSession.set((initialRotation + 1) % 4);
   1352 
   1353                 logSeparator = separateLogs();
   1354                 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
   1355                 mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
   1356                 mAmWmState.assertFocusedActivity("Focus must be on secondary display",
   1357                         TEST_ACTIVITY);
   1358                 final ReportedSizes testActivitySizes = getLastReportedSizesForActivity(
   1359                         TEST_ACTIVITY, logSeparator);
   1360                 assertEquals(
   1361                         "Sizes of secondary display must not change after rotation of primary "
   1362                                 + "display",
   1363                         initialSizes, testActivitySizes);
   1364             }
   1365         }
   1366     }
   1367 
   1368     private void rotateAndCheckSameSizes(
   1369             RotationSession rotationSession, ComponentName activityName) throws Exception {
   1370         for (int rotation = 3; rotation >= 0; --rotation) {
   1371             final LogSeparator logSeparator = separateLogs();
   1372             rotationSession.set(rotation);
   1373             final ReportedSizes rotatedSizes = getLastReportedSizesForActivity(activityName,
   1374                     logSeparator);
   1375             assertNull("Sizes must not change after rotation", rotatedSizes);
   1376         }
   1377     }
   1378 
   1379     /**
   1380      * Tests that task affinity does affect what display an activity is launched on but that
   1381      * matching the task component root does.
   1382      */
   1383     @Test
   1384     public void testTaskMatchAcrossDisplays() throws Exception {
   1385         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1386             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
   1387 
   1388             launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
   1389             mAmWmState.computeState(LAUNCHING_ACTIVITY);
   1390 
   1391             // Check that activity is on the secondary display.
   1392             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
   1393             final ActivityManagerState.ActivityStack firstFrontStack =
   1394                     mAmWmState.getAmState().getStackById(frontStackId);
   1395             assertEquals("Activity launched on secondary display must be resumed",
   1396                     getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
   1397             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
   1398 
   1399             executeShellCommand("am start -n " + getActivityName(ALT_LAUNCHING_ACTIVITY));
   1400             mAmWmState.waitForValidState(ALT_LAUNCHING_ACTIVITY);
   1401 
   1402             // Check that second activity gets launched on the default display despite
   1403             // the affinity match on the secondary display.
   1404             final int defaultDisplayFrontStackId = mAmWmState.getAmState().getFrontStackId(
   1405                     DEFAULT_DISPLAY);
   1406             final ActivityManagerState.ActivityStack defaultDisplayFrontStack =
   1407                     mAmWmState.getAmState().getStackById(defaultDisplayFrontStackId);
   1408             assertEquals("Activity launched on default display must be resumed",
   1409                     getActivityName(ALT_LAUNCHING_ACTIVITY),
   1410                     defaultDisplayFrontStack.mResumedActivity);
   1411             mAmWmState.assertFocusedStack("Focus must be on primary display",
   1412                     defaultDisplayFrontStackId);
   1413 
   1414             executeShellCommand("am start -n " + getActivityName(LAUNCHING_ACTIVITY));
   1415             mAmWmState.waitForFocusedStack(frontStackId);
   1416 
   1417             // Check that the third intent is redirected to the first task due to the root
   1418             // component match on the secondary display.
   1419             final ActivityManagerState.ActivityStack secondFrontStack =
   1420                     mAmWmState.getAmState().getStackById(frontStackId);
   1421             assertEquals("Activity launched on secondary display must be resumed",
   1422                     getActivityName(LAUNCHING_ACTIVITY), secondFrontStack.mResumedActivity);
   1423             mAmWmState.assertFocusedStack("Focus must be on primary display", frontStackId);
   1424             assertEquals("Focused stack must only contain 1 task",
   1425                     1, secondFrontStack.getTasks().size());
   1426             assertEquals("Focused task must only contain 1 activity",
   1427                     1, secondFrontStack.getTasks().get(0).mActivities.size());
   1428         }
   1429     }
   1430 
   1431     /**
   1432      * Tests that the task affinity search respects the launch display id.
   1433      */
   1434     @Test
   1435     public void testLaunchDisplayAffinityMatch() throws Exception {
   1436         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1437             final ActivityDisplay newDisplay = virtualDisplaySession.createDisplay();
   1438 
   1439             launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId);
   1440 
   1441             // Check that activity is on the secondary display.
   1442             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
   1443             final ActivityManagerState.ActivityStack firstFrontStack =
   1444                     mAmWmState.getAmState().getStackById(frontStackId);
   1445             assertEquals("Activity launched on secondary display must be resumed",
   1446                     getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity);
   1447             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
   1448 
   1449             // We don't want FLAG_ACTIVITY_MULTIPLE_TASK, so we can't use launchActivityOnDisplay
   1450             executeShellCommand("am start -n " + getActivityName(ALT_LAUNCHING_ACTIVITY)
   1451                     + " -f 0x10000000" // FLAG_ACTIVITY_NEW_TASK
   1452                     + " --display " + newDisplay.mId);
   1453             mAmWmState.computeState(ALT_LAUNCHING_ACTIVITY);
   1454 
   1455             // Check that second activity gets launched into the affinity matching
   1456             // task on the secondary display
   1457             final int secondFrontStackId =
   1458                     mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
   1459             final ActivityManagerState.ActivityStack secondFrontStack =
   1460                     mAmWmState.getAmState().getStackById(secondFrontStackId);
   1461             assertEquals("Activity launched on secondary display must be resumed",
   1462                     getActivityName(ALT_LAUNCHING_ACTIVITY),
   1463                     secondFrontStack.mResumedActivity);
   1464             mAmWmState.assertFocusedStack("Focus must be on secondary display",
   1465                     secondFrontStackId);
   1466             assertEquals("Focused stack must only contain 1 task",
   1467                     1, secondFrontStack.getTasks().size());
   1468             assertEquals("Focused task must contain 2 activities",
   1469                     2, secondFrontStack.getTasks().get(0).mActivities.size());
   1470         }
   1471     }
   1472 
   1473     /**
   1474      * Tests than a new task launched by an activity will end up on that activity's display
   1475      * even if the focused stack is not on that activity's display.
   1476      */
   1477     @Test
   1478     public void testNewTaskSameDisplay() throws Exception {
   1479         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1480             final ActivityDisplay newDisplay = virtualDisplaySession.setSimulateDisplay(true)
   1481                     .createDisplay();
   1482 
   1483             launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId);
   1484             mAmWmState.computeState(BROADCAST_RECEIVER_ACTIVITY);
   1485 
   1486             // Check that the first activity is launched onto the secondary display
   1487             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
   1488             final ActivityManagerState.ActivityStack firstFrontStack =
   1489                     mAmWmState.getAmState().getStackById(frontStackId);
   1490             assertEquals("Activity launched on secondary display must be resumed",
   1491                     getActivityName(BROADCAST_RECEIVER_ACTIVITY),
   1492                     firstFrontStack.mResumedActivity);
   1493             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
   1494 
   1495             executeShellCommand("am start -n " + getActivityName(TEST_ACTIVITY));
   1496             mAmWmState.waitForValidState(TEST_ACTIVITY);
   1497 
   1498             // Check that the second activity is launched on the default display
   1499             final int focusedStackId = mAmWmState.getAmState().getFocusedStackId();
   1500             final ActivityManagerState.ActivityStack focusedStack =
   1501                     mAmWmState.getAmState().getStackById(focusedStackId);
   1502             assertEquals("Activity launched on default display must be resumed",
   1503                     getActivityName(TEST_ACTIVITY), focusedStack.mResumedActivity);
   1504             assertEquals("Focus must be on primary display",
   1505                     DEFAULT_DISPLAY, focusedStack.mDisplayId);
   1506 
   1507             executeShellCommand(LAUNCH_ACTIVITY_BROADCAST + getActivityName(LAUNCHING_ACTIVITY));
   1508 
   1509             // Check that the third activity ends up in a new task in the same stack as the
   1510             // first activity
   1511             mAmWmState.waitForValidState(LAUNCHING_ACTIVITY);
   1512             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
   1513             final ActivityManagerState.ActivityStack secondFrontStack =
   1514                     mAmWmState.getAmState().getStackById(frontStackId);
   1515             assertEquals("Activity must be launched on secondary display",
   1516                     getActivityName(LAUNCHING_ACTIVITY), secondFrontStack.mResumedActivity);
   1517             assertEquals("Secondary display must contain 2 tasks",
   1518                     2, secondFrontStack.getTasks().size());
   1519         }
   1520     }
   1521 
   1522     /**
   1523      * Tests than an immediate launch after new display creation is handled correctly.
   1524      */
   1525     @Test
   1526     public void testImmediateLaunchOnNewDisplay() throws Exception {
   1527         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
   1528             // Create new virtual display and immediately launch an activity on it.
   1529             final ActivityDisplay newDisplay = virtualDisplaySession
   1530                     .setLaunchActivity(TEST_ACTIVITY)
   1531                     .createDisplay();
   1532 
   1533             // Check that activity is launched and placed correctly.
   1534             mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_RESUMED);
   1535             mAmWmState.assertResumedActivity("Test activity must be launched on a new display",
   1536                     TEST_ACTIVITY);
   1537             final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mId);
   1538             final ActivityManagerState.ActivityStack firstFrontStack =
   1539                     mAmWmState.getAmState().getStackById(frontStackId);
   1540             assertEquals("Activity launched on secondary display must be resumed",
   1541                     getActivityName(TEST_ACTIVITY), firstFrontStack.mResumedActivity);
   1542             mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
   1543         }
   1544     }
   1545 
   1546     /**
   1547      * Tests that turning the primary display off does not affect the activity running
   1548      * on an external secondary display.
   1549      */
   1550     @Test
   1551     public void testExternalDisplayActivityTurnPrimaryOff() throws Exception {
   1552         // Launch something on the primary display so we know there is a resumed activity there
   1553         launchActivity(RESIZEABLE_ACTIVITY);
   1554         waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY,
   1555                 "Activity launched on primary display must be resumed");
   1556 
   1557         try (final ExternalDisplaySession externalDisplaySession = new ExternalDisplaySession();
   1558              final PrimaryDisplayStateSession displayStateSession =
   1559                      new PrimaryDisplayStateSession()) {
   1560             final ActivityDisplay newDisplay =
   1561                     externalDisplaySession.createVirtualDisplay(true /* showContentWhenLocked */);
   1562 
   1563             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
   1564 
   1565             // Check that the activity is launched onto the external display
   1566             waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
   1567                     "Activity launched on external display must be resumed");
   1568 
   1569             final LogSeparator logSeparator = separateLogs();
   1570 
   1571             displayStateSession.turnScreenOff();
   1572 
   1573             // Wait for the fullscreen stack to start sleeping, and then make sure the
   1574             // test activity is still resumed.
   1575             int retry = 0;
   1576             ActivityLifecycleCounts lifecycleCounts;
   1577             do {
   1578                 lifecycleCounts = new ActivityLifecycleCounts(RESIZEABLE_ACTIVITY, logSeparator);
   1579                 if (lifecycleCounts.mStopCount == 1) {
   1580                     break;
   1581                 }
   1582                 logAlways("***testExternalDisplayActivityTurnPrimaryOff... retry=" + retry);
   1583                 SystemClock.sleep(TimeUnit.SECONDS.toMillis(1));
   1584             } while (retry++ < 5);
   1585 
   1586             if (lifecycleCounts.mStopCount != 1) {
   1587                 fail(RESIZEABLE_ACTIVITY + " has received " + lifecycleCounts.mStopCount
   1588                         + " onStop() calls, expecting 1");
   1589             }
   1590             waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
   1591                     "Activity launched on external display must be resumed");
   1592         }
   1593     }
   1594 
   1595     /**
   1596      * Tests that an activity can be launched on a secondary display while the primary
   1597      * display is off.
   1598      */
   1599     @Test
   1600     public void testLaunchExternalDisplayActivityWhilePrimaryOff() throws Exception {
   1601         // Launch something on the primary display so we know there is a resumed activity there
   1602         launchActivity(RESIZEABLE_ACTIVITY);
   1603         waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY,
   1604                 "Activity launched on primary display must be resumed");
   1605 
   1606         try (final PrimaryDisplayStateSession displayStateSession =
   1607                      new PrimaryDisplayStateSession();
   1608              final ExternalDisplaySession externalDisplaySession = new ExternalDisplaySession()) {
   1609             displayStateSession.turnScreenOff();
   1610 
   1611             // Make sure there is no resumed activity when the primary display is off
   1612             waitAndAssertActivityStopped(RESIZEABLE_ACTIVITY,
   1613                     "Activity launched on primary display must be stopped after turning off");
   1614             assertEquals("Unexpected resumed activity",
   1615                     0, mAmWmState.getAmState().getResumedActivitiesCount());
   1616 
   1617             final ActivityDisplay newDisplay =
   1618                     externalDisplaySession.createVirtualDisplay(true /* showContentWhenLocked */);
   1619 
   1620             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
   1621 
   1622             // Check that the test activity is resumed on the external display
   1623             waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
   1624                     "Activity launched on external display must be resumed");
   1625         }
   1626     }
   1627 
   1628     /**
   1629      * Tests that turning the secondary display off stops activities running on that display.
   1630      */
   1631     @Test
   1632     public void testExternalDisplayToggleState() throws Exception {
   1633         try (final ExternalDisplaySession externalDisplaySession = new ExternalDisplaySession()) {
   1634             final ActivityDisplay newDisplay =
   1635                     externalDisplaySession.createVirtualDisplay(false /* showContentWhenLocked */);
   1636 
   1637             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
   1638 
   1639             // Check that the test activity is resumed on the external display
   1640             waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
   1641                     "Activity launched on external display must be resumed");
   1642 
   1643             externalDisplaySession.turnDisplayOff();
   1644 
   1645             // Check that turning off the external display stops the activity
   1646             waitAndAssertActivityStopped(TEST_ACTIVITY,
   1647                     "Activity launched on external display must be stopped after turning off");
   1648 
   1649             externalDisplaySession.turnDisplayOn();
   1650 
   1651             // Check that turning on the external display resumes the activity
   1652             waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
   1653                     "Activity launched on external display must be resumed");
   1654         }
   1655     }
   1656 
   1657     /**
   1658      * Tests that tapping on the primary display after showing the keyguard resumes the
   1659      * activity on the primary display.
   1660      */
   1661     @Test
   1662     public void testStackFocusSwitchOnTouchEventAfterKeyguard() throws Exception {
   1663         // Launch something on the primary display so we know there is a resumed activity there
   1664         launchActivity(RESIZEABLE_ACTIVITY);
   1665         waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY,
   1666                 "Activity launched on primary display must be resumed");
   1667 
   1668         try (final LockScreenSession lockScreenSession = new LockScreenSession();
   1669              final ExternalDisplaySession externalDisplaySession = new ExternalDisplaySession()) {
   1670             lockScreenSession.sleepDevice();
   1671 
   1672             // Make sure there is no resumed activity when the primary display is off
   1673             waitAndAssertActivityStopped(RESIZEABLE_ACTIVITY,
   1674                     "Activity launched on primary display must be stopped after turning off");
   1675             assertEquals("Unexpected resumed activity",
   1676                     0, mAmWmState.getAmState().getResumedActivitiesCount());
   1677 
   1678             final ActivityDisplay newDisplay =
   1679                     externalDisplaySession.createVirtualDisplay(true /* showContentWhenLocked */);
   1680 
   1681             launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
   1682 
   1683             // Check that the test activity is resumed on the external display
   1684             waitAndAssertActivityResumed(TEST_ACTIVITY, newDisplay.mId,
   1685                     "Activity launched on external display must be resumed");
   1686 
   1687             // Unlock the device and tap on the middle of the primary display
   1688             lockScreenSession.wakeUpDevice();
   1689             executeShellCommand("wm dismiss-keyguard");
   1690             mAmWmState.waitForKeyguardGone();
   1691             mAmWmState.waitForValidState(TEST_ACTIVITY);
   1692             final ReportedDisplayMetrics displayMetrics = getDisplayMetrics();
   1693             final int width = displayMetrics.getSize().getWidth();
   1694             final int height = displayMetrics.getSize().getHeight();
   1695             executeShellCommand("input tap " + (width / 2) + " " + (height / 2));
   1696 
   1697             // Check that the activity on the primary display is resumed
   1698             waitAndAssertActivityResumed(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY,
   1699                     "Activity launched on primary display must be resumed");
   1700             assertEquals("Unexpected resumed activity",
   1701                     1, mAmWmState.getAmState().getResumedActivitiesCount());
   1702         }
   1703     }
   1704 
   1705     private void waitAndAssertActivityResumed(
   1706             ComponentName activityName, int displayId, String message) throws Exception {
   1707         mAmWmState.waitForActivityState(activityName, STATE_RESUMED);
   1708 
   1709         assertEquals(message,
   1710                 getActivityName(activityName), mAmWmState.getAmState().getResumedActivity());
   1711         final int frontStackId = mAmWmState.getAmState().getFrontStackId(displayId);
   1712         ActivityManagerState.ActivityStack firstFrontStack =
   1713                 mAmWmState.getAmState().getStackById(frontStackId);
   1714         assertEquals(message,
   1715                 getActivityName(activityName), firstFrontStack.mResumedActivity);
   1716         assertTrue(message,
   1717                 mAmWmState.getAmState().hasActivityState(activityName, STATE_RESUMED));
   1718         mAmWmState.assertFocusedStack("Focus must be on external display", frontStackId);
   1719         mAmWmState.assertVisibility(activityName, true /* visible */);
   1720     }
   1721 
   1722     private void waitAndAssertActivityStopped(ComponentName activityName, String message)
   1723             throws Exception {
   1724         mAmWmState.waitForActivityState(activityName, STATE_STOPPED);
   1725 
   1726         assertTrue(message, mAmWmState.getAmState().hasActivityState(activityName,
   1727                 STATE_STOPPED));
   1728     }
   1729 
   1730     /**
   1731      * Tests that showWhenLocked works on a secondary display.
   1732      */
   1733     @Test
   1734     public void testSecondaryDisplayShowWhenLocked() throws Exception {
   1735         try (final ExternalDisplaySession externalDisplaySession = new ExternalDisplaySession();
   1736              final LockScreenSession lockScreenSession = new LockScreenSession()) {
   1737             lockScreenSession.setLockCredential();
   1738 
   1739             launchActivity(TEST_ACTIVITY);
   1740 
   1741             final ActivityDisplay newDisplay =
   1742                     externalDisplaySession.createVirtualDisplay(false /* showContentWhenLocked */);
   1743             launchActivityOnDisplay(SHOW_WHEN_LOCKED_ATTR_ACTIVITY, newDisplay.mId);
   1744 
   1745             lockScreenSession.gotoKeyguard();
   1746 
   1747             mAmWmState.waitForActivityState(TEST_ACTIVITY, STATE_STOPPED);
   1748             mAmWmState.waitForActivityState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY, STATE_RESUMED);
   1749 
   1750             mAmWmState.computeState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY);
   1751             assertTrue("Expected resumed activity on secondary display", mAmWmState.getAmState()
   1752                     .hasActivityState(SHOW_WHEN_LOCKED_ATTR_ACTIVITY, STATE_RESUMED));
   1753         }
   1754     }
   1755 
   1756     /** Assert that component received onMovedToDisplay and onConfigurationChanged callbacks. */
   1757     private void assertMovedToDisplay(ComponentName componentName, LogSeparator logSeparator)
   1758             throws Exception {
   1759         final ActivityLifecycleCounts lifecycleCounts =
   1760                 new ActivityLifecycleCounts(componentName, logSeparator);
   1761         if (lifecycleCounts.mDestroyCount != 0) {
   1762             fail(componentName + " has been destroyed " + lifecycleCounts.mDestroyCount
   1763                     + " time(s), wasn't expecting any");
   1764         } else if (lifecycleCounts.mCreateCount != 0) {
   1765             fail(componentName + " has been (re)created " + lifecycleCounts.mCreateCount
   1766                     + " time(s), wasn't expecting any");
   1767         } else if (lifecycleCounts.mConfigurationChangedCount != 1) {
   1768             fail(componentName + " has received "
   1769                     + lifecycleCounts.mConfigurationChangedCount
   1770                     + " onConfigurationChanged() calls, expecting " + 1);
   1771         } else if (lifecycleCounts.mMovedToDisplayCount != 1) {
   1772             fail(componentName + " has received "
   1773                     + lifecycleCounts.mMovedToDisplayCount
   1774                     + " onMovedToDisplay() calls, expecting " + 1);
   1775         }
   1776     }
   1777 
   1778     private class ExternalDisplaySession implements AutoCloseable {
   1779 
   1780         @Nullable
   1781         private VirtualDisplayHelper mExternalDisplayHelper;
   1782 
   1783         /**
   1784          * Creates a private virtual display with the external and show with insecure
   1785          * keyguard flags set.
   1786          */
   1787         ActivityDisplay createVirtualDisplay(boolean showContentWhenLocked)
   1788                 throws Exception {
   1789             final List<ActivityDisplay> originalDS = getDisplaysStates();
   1790             final int originalDisplayCount = originalDS.size();
   1791 
   1792             mExternalDisplayHelper = new VirtualDisplayHelper();
   1793             mExternalDisplayHelper.createAndWaitForDisplay(showContentWhenLocked);
   1794 
   1795             // Wait for the virtual display to be created and get configurations.
   1796             final List<ActivityDisplay> ds = getDisplayStateAfterChange(originalDisplayCount + 1);
   1797             assertEquals("New virtual display must be created", originalDisplayCount + 1,
   1798                     ds.size());
   1799 
   1800             // Find the newly added display.
   1801             final List<ActivityDisplay> newDisplays = findNewDisplayStates(originalDS, ds);
   1802             return newDisplays.get(0);
   1803         }
   1804 
   1805         void turnDisplayOff() {
   1806             if (mExternalDisplayHelper == null) {
   1807                 throw new RuntimeException("No external display created");
   1808             }
   1809             mExternalDisplayHelper.turnDisplayOff();
   1810         }
   1811 
   1812         void turnDisplayOn() {
   1813             if (mExternalDisplayHelper == null) {
   1814                 throw new RuntimeException("No external display created");
   1815             }
   1816             mExternalDisplayHelper.turnDisplayOn();
   1817         }
   1818 
   1819         @Override
   1820         public void close() throws Exception {
   1821             if (mExternalDisplayHelper != null) {
   1822                 mExternalDisplayHelper.releaseDisplay();
   1823                 mExternalDisplayHelper = null;
   1824             }
   1825         }
   1826     }
   1827 
   1828     private static class PrimaryDisplayStateSession implements AutoCloseable {
   1829 
   1830         void turnScreenOff() {
   1831             setPrimaryDisplayState(false);
   1832         }
   1833 
   1834         @Override
   1835         public void close() throws Exception {
   1836             setPrimaryDisplayState(true);
   1837         }
   1838 
   1839         /** Turns the primary display on/off by pressing the power key */
   1840         private void setPrimaryDisplayState(boolean wantOn) {
   1841             if (wantOn) {
   1842                 pressWakeupButton();
   1843             } else {
   1844                 pressSleepButton();
   1845             }
   1846             VirtualDisplayHelper.waitForDefaultDisplayState(wantOn);
   1847         }
   1848     }
   1849 }
   1850