| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.am; |
| |
| import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; |
| import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; |
| import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; |
| |
| import static com.android.server.am.ActivityStackSupervisor.ON_TOP; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.Mockito.doReturn; |
| |
| import android.platform.test.annotations.Presubmit; |
| |
| import androidx.test.filters.SmallTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| /** |
| * Tests for the {@link ActivityDisplay} class. |
| * |
| * Build/Install/Run: |
| * atest WmTests:ActivityDisplayTests |
| */ |
| @SmallTest |
| @Presubmit |
| @RunWith(AndroidJUnit4.class) |
| public class ActivityDisplayTests extends ActivityTestsBase { |
| |
| @Before |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| setupActivityTaskManagerService(); |
| } |
| |
| @Test |
| public void testLastFocusedStackIsUpdatedWhenMovingStack() { |
| // Create a stack at bottom. |
| final ActivityDisplay display = mSupervisor.getDefaultDisplay(); |
| final ActivityStack stack = display.createStack( |
| WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, !ON_TOP); |
| final ActivityStack prevFocusedStack = display.getFocusedStack(); |
| |
| stack.moveToFront("moveStackToFront"); |
| // After moving the stack to front, the previous focused should be the last focused. |
| assertTrue(stack.isFocusedStackOnDisplay()); |
| assertEquals(prevFocusedStack, display.getLastFocusedStack()); |
| |
| stack.moveToBack("moveStackToBack", null /* task */); |
| // After moving the stack to back, the stack should be the last focused. |
| assertEquals(stack, display.getLastFocusedStack()); |
| } |
| |
| /** |
| * This test simulates the picture-in-picture menu activity launches an activity to fullscreen |
| * stack. The fullscreen stack should be the top focused for resuming correctly. |
| */ |
| @Test |
| public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() { |
| // Create a pinned stack and move to front. |
| final ActivityStack pinnedStack = mSupervisor.getDefaultDisplay().createStack( |
| WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP); |
| final TaskRecord pinnedTask = new TaskBuilder(mService.mStackSupervisor) |
| .setStack(pinnedStack).build(); |
| new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE) |
| .setTask(pinnedTask).build(); |
| pinnedStack.moveToFront("movePinnedStackToFront"); |
| |
| // The focused stack should be the pinned stack. |
| assertTrue(pinnedStack.isFocusedStackOnDisplay()); |
| |
| // Create a fullscreen stack and move to front. |
| final ActivityStack fullscreenStack = createFullscreenStackWithSimpleActivityAt( |
| mSupervisor.getDefaultDisplay()); |
| fullscreenStack.moveToFront("moveFullscreenStackToFront"); |
| |
| // The focused stack should be the fullscreen stack. |
| assertTrue(fullscreenStack.isFocusedStackOnDisplay()); |
| } |
| |
| /** |
| * Test {@link ActivityDisplay#mPreferredTopFocusableStack} will be cleared when the stack is |
| * removed or moved to back, and the focused stack will be according to z-order. |
| */ |
| @Test |
| public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() { |
| // Create a display which only contains 2 stacks. |
| final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); |
| final ActivityStack stack1 = createFullscreenStackWithSimpleActivityAt(display); |
| final ActivityStack stack2 = createFullscreenStackWithSimpleActivityAt(display); |
| |
| // Put stack1 and stack2 on top. |
| stack1.moveToFront("moveStack1ToFront"); |
| stack2.moveToFront("moveStack2ToFront"); |
| assertTrue(stack2.isFocusedStackOnDisplay()); |
| |
| // Stack1 should be focused after moving stack2 to back. |
| stack2.moveToBack("moveStack2ToBack", null /* task */); |
| assertTrue(stack1.isFocusedStackOnDisplay()); |
| |
| // Stack2 should be focused after removing stack1. |
| display.removeChild(stack1); |
| assertTrue(stack2.isFocusedStackOnDisplay()); |
| } |
| |
| private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) { |
| final ActivityStack fullscreenStack = display.createStack( |
| WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); |
| final TaskRecord fullscreenTask = new TaskBuilder(mService.mStackSupervisor) |
| .setStack(fullscreenStack).build(); |
| new ActivityBuilder(mService).setTask(fullscreenTask).build(); |
| return fullscreenStack; |
| } |
| |
| /** |
| * Verifies the correct activity is returned when querying the top running activity. |
| */ |
| @Test |
| public void testTopRunningActivity() { |
| // Create stack to hold focus. |
| final ActivityDisplay display = mSupervisor.getDefaultDisplay(); |
| final ActivityStack emptyStack = display.createStack(WINDOWING_MODE_FULLSCREEN, |
| ACTIVITY_TYPE_STANDARD, true /* onTop */); |
| |
| final KeyguardController keyguard = mSupervisor.getKeyguardController(); |
| final ActivityStack stack = mSupervisor.getDefaultDisplay().createStack( |
| WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); |
| final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) |
| .setStack(stack).build(); |
| |
| // Make sure the top running activity is not affected when keyguard is not locked. |
| assertTopRunningActivity(activity, display); |
| |
| // Check to make sure activity not reported when it cannot show on lock and lock is on. |
| doReturn(true).when(keyguard).isKeyguardLocked(); |
| assertEquals(activity, display.topRunningActivity()); |
| assertNull(display.topRunningActivity(true /* considerKeyguardState */)); |
| |
| // Change focus to stack with activity. |
| stack.moveToFront("focusChangeToTestStack"); |
| assertEquals(stack, display.getFocusedStack()); |
| assertEquals(activity, display.topRunningActivity()); |
| assertNull(display.topRunningActivity(true /* considerKeyguardState */)); |
| |
| // Add activity that should be shown on the keyguard. |
| final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService) |
| .setCreateTask(true) |
| .setStack(stack) |
| .setActivityFlags(FLAG_SHOW_WHEN_LOCKED) |
| .build(); |
| |
| // Ensure the show when locked activity is returned. |
| assertTopRunningActivity(showWhenLockedActivity, display); |
| |
| // Change focus back to empty stack. |
| emptyStack.moveToFront("focusChangeToEmptyStack"); |
| assertEquals(emptyStack, display.getFocusedStack()); |
| // If there is no running activity in focused stack, the running activity in next focusable |
| // stack should be returned. |
| assertTopRunningActivity(showWhenLockedActivity, display); |
| } |
| |
| private static void assertTopRunningActivity(ActivityRecord top, ActivityDisplay display) { |
| assertEquals(top, display.topRunningActivity()); |
| assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */)); |
| } |
| } |