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.ActivityManager.StackId.INVALID_STACK_ID;
     20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
     21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
     22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
     23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
     24 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
     25 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
     26 import static android.server.am.ComponentNameUtils.getActivityName;
     27 import static android.server.am.ComponentNameUtils.getWindowName;
     28 import static android.server.am.StateLogger.log;
     29 import static android.server.am.StateLogger.logAlways;
     30 import static android.server.am.StateLogger.logE;
     31 
     32 import static org.hamcrest.Matchers.greaterThan;
     33 import static org.hamcrest.Matchers.lessThan;
     34 import static org.junit.Assert.assertEquals;
     35 import static org.junit.Assert.assertNotNull;
     36 import static org.junit.Assert.assertNull;
     37 import static org.junit.Assert.assertThat;
     38 
     39 import android.content.ComponentName;
     40 import android.graphics.Rect;
     41 import android.os.SystemClock;
     42 import android.server.am.ActivityManagerState.ActivityStack;
     43 import android.server.am.ActivityManagerState.ActivityTask;
     44 import android.server.am.WindowManagerState.WindowStack;
     45 import android.server.am.WindowManagerState.WindowState;
     46 import android.server.am.WindowManagerState.WindowTask;
     47 
     48 import java.util.ArrayList;
     49 import java.util.Arrays;
     50 import java.util.List;
     51 import java.util.Objects;
     52 import java.util.function.BiPredicate;
     53 import java.util.function.BooleanSupplier;
     54 import java.util.function.Predicate;
     55 
     56 /**
     57  * Combined state of the activity manager and window manager.
     58  */
     59 public class ActivityAndWindowManagersState {
     60 
     61     // Clone of android DisplayMetrics.DENSITY_DEFAULT (DENSITY_MEDIUM)
     62     // (Needed in host-side tests to convert dp to px.)
     63     private static final int DISPLAY_DENSITY_DEFAULT = 160;
     64 
     65     // Default minimal size of resizable task, used if none is set explicitly.
     66     // Must be kept in sync with 'default_minimal_size_resizable_task' dimen from frameworks/base.
     67     private static final int DEFAULT_RESIZABLE_TASK_SIZE_DP = 220;
     68 
     69     // Default minimal size of a resizable PiP task, used if none is set explicitly.
     70     // Must be kept in sync with 'default_minimal_size_pip_resizable_task' dimen from
     71     // frameworks/base.
     72     private static final int DEFAULT_PIP_RESIZABLE_TASK_SIZE_DP = 108;
     73 
     74     private ActivityManagerState mAmState = new ActivityManagerState();
     75     private WindowManagerState mWmState = new WindowManagerState();
     76 
     77     /**
     78      * Compute AM and WM state of device, check sanity and bounds.
     79      * WM state will include only visible windows, stack and task bounds will be compared.
     80      *
     81      * @param waitForActivitiesVisible array of activity names to wait for.
     82      */
     83     public void computeState(WaitForValidActivityState... waitForActivitiesVisible) {
     84         waitForValidState(true /* compareTaskAndStackBounds */, waitForActivitiesVisible);
     85     }
     86 
     87     /**
     88      * Compute AM and WM state of device, check sanity and bounds.
     89      *
     90      * @param compareTaskAndStackBounds pass 'true' if stack and task bounds should be compared,
     91      *                                  'false' otherwise.
     92      * @param waitForActivitiesVisible  array of activity states to wait for.
     93      */
     94     void computeState(boolean compareTaskAndStackBounds,
     95             WaitForValidActivityState... waitForActivitiesVisible) {
     96         waitForValidState(compareTaskAndStackBounds, waitForActivitiesVisible);
     97     }
     98 
     99     /** Wait for the activity to appear and for valid state in AM and WM. */
    100     void waitForValidState(WaitForValidActivityState... waitForActivityVisible) {
    101         waitForValidState(false /* compareTaskAndStackBounds */, waitForActivityVisible);
    102     }
    103 
    104     /**
    105      * Wait for the activities to appear in proper stacks and for valid state in AM and WM.
    106      *
    107      * @param compareTaskAndStackBounds flag indicating if we should compare task and stack bounds
    108      *                                  for equality.
    109      * @param waitForActivitiesVisible  array of activity states to wait for.
    110      */
    111     private void waitForValidState(boolean compareTaskAndStackBounds,
    112             WaitForValidActivityState... waitForActivitiesVisible) {
    113         for (int retry = 1; retry <= 5; retry++) {
    114             // TODO: Get state of AM and WM at the same time to avoid mismatches caused by
    115             // requesting dump in some intermediate state.
    116             mAmState.computeState();
    117             mWmState.computeState();
    118             if (shouldWaitForSanityCheck(compareTaskAndStackBounds)
    119                     || shouldWaitForValidStacks(compareTaskAndStackBounds)
    120                     || shouldWaitForActivities(waitForActivitiesVisible)
    121                     || shouldWaitForWindows()) {
    122                 logAlways("***Waiting for valid stacks and activities states... retry=" + retry);
    123                 SystemClock.sleep(1000);
    124             } else {
    125                 return;
    126             }
    127         }
    128         logE("***Waiting for states failed: " + Arrays.toString(waitForActivitiesVisible));
    129     }
    130 
    131     boolean waitForHomeActivityVisible() {
    132         ComponentName homeActivity = mAmState.getHomeActivityName();
    133         // Sometimes this function is called before we know what Home Activity is
    134         if (homeActivity == null) {
    135             log("Computing state to determine Home Activity");
    136             computeState(true);
    137             homeActivity = mAmState.getHomeActivityName();
    138         }
    139         assertNotNull("homeActivity should not be null", homeActivity);
    140         waitForValidState(new WaitForValidActivityState(homeActivity));
    141         return mAmState.isHomeActivityVisible();
    142     }
    143 
    144     public void waitForKeyguardShowingAndNotOccluded() {
    145         waitForWithAmState(state -> state.getKeyguardControllerState().keyguardShowing
    146                         && !state.getKeyguardControllerState().keyguardOccluded,
    147                 "***Waiting for Keyguard showing...");
    148     }
    149 
    150     @Deprecated
    151     void waitForFocusedStack(int stackId) {
    152         waitForWithAmState(state -> state.getFocusedStackId() == stackId,
    153                 "***Waiting for focused stack...");
    154     }
    155 
    156     void waitForWithAmState(Predicate<ActivityManagerState> waitCondition, String message) {
    157         waitFor((amState, wmState) -> waitCondition.test(amState), message);
    158     }
    159 
    160     void waitFor(
    161             BiPredicate<ActivityManagerState, WindowManagerState> waitCondition, String message) {
    162         waitFor(message, () -> {
    163             mAmState.computeState();
    164             mWmState.computeState();
    165             return waitCondition.test(mAmState, mWmState);
    166         });
    167     }
    168 
    169     void waitFor(String message, BooleanSupplier waitCondition) {
    170         for (int retry = 1; retry <= 5; retry++) {
    171             if (waitCondition.getAsBoolean()) {
    172                 return;
    173             }
    174             logAlways(message + " retry=" + retry);
    175             SystemClock.sleep(1000);
    176         }
    177         logE(message + " failed");
    178     }
    179 
    180     /**
    181      * @return true if should wait for valid stacks state.
    182      */
    183     private boolean shouldWaitForValidStacks(boolean compareTaskAndStackBounds) {
    184         if (!taskListsInAmAndWmAreEqual()) {
    185             // We want to wait for equal task lists in AM and WM in case we caught them in the
    186             // middle of some state change operations.
    187             logAlways("***taskListsInAmAndWmAreEqual=false");
    188             return true;
    189         }
    190         if (!stackBoundsInAMAndWMAreEqual()) {
    191             // We want to wait a little for the stacks in AM and WM to have equal bounds as there
    192             // might be a transition animation ongoing when we got the states from WM AM separately.
    193             logAlways("***stackBoundsInAMAndWMAreEqual=false");
    194             return true;
    195         }
    196         try {
    197             // Temporary fix to avoid catching intermediate state with different task bounds in AM
    198             // and WM.
    199             assertValidBounds(compareTaskAndStackBounds);
    200         } catch (AssertionError e) {
    201             logAlways("***taskBoundsInAMAndWMAreEqual=false : " + e.getMessage());
    202             return true;
    203         }
    204         final int stackCount = mAmState.getStackCount();
    205         if (stackCount == 0) {
    206             logAlways("***stackCount=" + stackCount);
    207             return true;
    208         }
    209         final int resumedActivitiesCount = mAmState.getResumedActivitiesCount();
    210         if (!mAmState.getKeyguardControllerState().keyguardShowing && resumedActivitiesCount != 1) {
    211             logAlways("***resumedActivitiesCount=" + resumedActivitiesCount);
    212             return true;
    213         }
    214         if (mAmState.getFocusedActivity() == null) {
    215             logAlways("***focusedActivity=null");
    216             return true;
    217         }
    218         return false;
    219     }
    220 
    221     /**
    222      * @return true if should wait for some activities to become visible.
    223      */
    224     private boolean shouldWaitForActivities(WaitForValidActivityState... waitForActivitiesVisible) {
    225         if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) {
    226             return false;
    227         }
    228         // If the caller is interested in us waiting for some particular activity windows to be
    229         // visible before compute the state. Check for the visibility of those activity windows
    230         // and for placing them in correct stacks (if requested).
    231         boolean allActivityWindowsVisible = true;
    232         boolean tasksInCorrectStacks = true;
    233         List<WindowState> matchingWindowStates = new ArrayList<>();
    234         for (final WaitForValidActivityState state : waitForActivitiesVisible) {
    235             final ComponentName activityName = state.activityName;
    236             final String windowName = state.windowName;
    237             final int stackId = state.stackId;
    238             final int windowingMode = state.windowingMode;
    239             final int activityType = state.activityType;
    240 
    241             mWmState.getMatchingVisibleWindowState(windowName, matchingWindowStates);
    242             boolean activityWindowVisible = !matchingWindowStates.isEmpty();
    243             if (!activityWindowVisible) {
    244                 logAlways("Activity window not visible: " + windowName);
    245                 allActivityWindowsVisible = false;
    246             } else if (activityName != null
    247                     && !mAmState.isActivityVisible(activityName)) {
    248                 logAlways("Activity not visible: " + getActivityName(activityName));
    249                 allActivityWindowsVisible = false;
    250             } else {
    251                 // Check if window is already the correct state requested by test.
    252                 boolean windowInCorrectState = false;
    253                 for (WindowState ws : matchingWindowStates) {
    254                     if (stackId != INVALID_STACK_ID && ws.getStackId() != stackId) {
    255                         continue;
    256                     }
    257                     if (windowingMode != WINDOWING_MODE_UNDEFINED
    258                             && ws.getWindowingMode() != windowingMode) {
    259                         continue;
    260                     }
    261                     if (activityType != ACTIVITY_TYPE_UNDEFINED
    262                             && ws.getActivityType() != activityType) {
    263                         continue;
    264                     }
    265                     windowInCorrectState = true;
    266                     break;
    267                 }
    268 
    269                 if (!windowInCorrectState) {
    270                     logAlways("Window in incorrect stack: " + state);
    271                     tasksInCorrectStacks = false;
    272                 }
    273             }
    274         }
    275         return !allActivityWindowsVisible || !tasksInCorrectStacks;
    276     }
    277 
    278     /**
    279      * @return true if should wait valid windows state.
    280      */
    281     private boolean shouldWaitForWindows() {
    282         if (mWmState.getFrontWindow() == null) {
    283             logAlways("***frontWindow=null");
    284             return true;
    285         }
    286         if (mWmState.getFocusedWindow() == null) {
    287             logAlways("***focusedWindow=null");
    288             return true;
    289         }
    290         if (mWmState.getFocusedApp() == null) {
    291             logAlways("***focusedApp=null");
    292             return true;
    293         }
    294 
    295         return false;
    296     }
    297 
    298     private boolean shouldWaitForSanityCheck(boolean compareTaskAndStackBounds) {
    299         try {
    300             assertSanity();
    301             assertValidBounds(compareTaskAndStackBounds);
    302         } catch (Throwable t) {
    303             logAlways("Waiting for sanity check: " + t.toString());
    304             return true;
    305         }
    306         return false;
    307     }
    308 
    309     public WindowManagerState getWmState() {
    310         return mWmState;
    311     }
    312 
    313     void assertSanity() {
    314         assertThat("Must have stacks", mAmState.getStackCount(), greaterThan(0));
    315         if (!mAmState.getKeyguardControllerState().keyguardShowing) {
    316             assertEquals("There should be one and only one resumed activity in the system.",
    317                     1, mAmState.getResumedActivitiesCount());
    318         }
    319         assertNotNull("Must have focus activity.", mAmState.getFocusedActivity());
    320 
    321         for (ActivityStack aStack : mAmState.getStacks()) {
    322             final int stackId = aStack.mStackId;
    323             for (ActivityTask aTask : aStack.getTasks()) {
    324                 assertEquals("Stack can only contain its own tasks", stackId, aTask.mStackId);
    325             }
    326         }
    327 
    328         assertNotNull("Must have front window.", mWmState.getFrontWindow());
    329         assertNotNull("Must have focused window.", mWmState.getFocusedWindow());
    330         assertNotNull("Must have app.", mWmState.getFocusedApp());
    331     }
    332 
    333     @Deprecated
    334     void assertFocusedStack(String msg, int stackId) {
    335         assertEquals(msg, stackId, mAmState.getFocusedStackId());
    336     }
    337 
    338     public void assertVisibility(final ComponentName activityName, final boolean visible) {
    339         final String windowName = getWindowName(activityName);
    340         final boolean activityVisible = mAmState.isActivityVisible(activityName);
    341         final boolean windowVisible = mWmState.isWindowVisible(windowName);
    342 
    343         assertEquals("Activity=" + getActivityName(activityName) + " must" + (visible ? "" : " NOT")
    344                 + " be visible.", visible, activityVisible);
    345         assertEquals("Window=" + windowName + " must" + (visible ? "" : " NOT") + " be visible.",
    346                 visible, windowVisible);
    347     }
    348 
    349     boolean taskListsInAmAndWmAreEqual() {
    350         for (ActivityStack aStack : mAmState.getStacks()) {
    351             final int stackId = aStack.mStackId;
    352             final WindowStack wStack = mWmState.getStack(stackId);
    353             if (wStack == null) {
    354                 log("Waiting for stack setup in WM, stackId=" + stackId);
    355                 return false;
    356             }
    357 
    358             for (ActivityTask aTask : aStack.getTasks()) {
    359                 if (wStack.getTask(aTask.mTaskId) == null) {
    360                     log("Task is in AM but not in WM, waiting for it to settle, taskId="
    361                             + aTask.mTaskId);
    362                     return false;
    363                 }
    364             }
    365 
    366             for (WindowTask wTask : wStack.mTasks) {
    367                 if (aStack.getTask(wTask.mTaskId) == null) {
    368                     log("Task is in WM but not in AM, waiting for it to settle, taskId="
    369                             + wTask.mTaskId);
    370                     return false;
    371                 }
    372             }
    373         }
    374         return true;
    375     }
    376 
    377     boolean stackBoundsInAMAndWMAreEqual() {
    378         for (ActivityStack aStack : mAmState.getStacks()) {
    379             final int stackId = aStack.mStackId;
    380             final WindowStack wStack = mWmState.getStack(stackId);
    381             if (aStack.isFullscreen() != wStack.isFullscreen()) {
    382                 log("Waiting for correct fullscreen state, stackId=" + stackId);
    383                 return false;
    384             }
    385 
    386             final Rect aStackBounds = aStack.getBounds();
    387             final Rect wStackBounds = wStack.getBounds();
    388 
    389             if (aStack.isFullscreen()) {
    390                 if (aStackBounds != null) {
    391                     log("Waiting for correct stack state in AM, stackId=" + stackId);
    392                     return false;
    393                 }
    394             } else if (!Objects.equals(aStackBounds, wStackBounds)) {
    395                 // If stack is not fullscreen - comparing bounds. Not doing it always because
    396                 // for fullscreen stack bounds in WM can be either null or equal to display size.
    397                 log("Waiting for stack bound equality in AM and WM, stackId=" + stackId);
    398                 return false;
    399             }
    400         }
    401 
    402         return true;
    403     }
    404 
    405     void assertValidBounds(boolean compareTaskAndStackBounds) {
    406         // Cycle through the stacks and tasks to figure out if the home stack is resizable
    407         final ActivityTask homeTask = mAmState.getHomeTask();
    408         final boolean homeStackIsResizable = homeTask != null
    409                 && homeTask.getResizeMode() == RESIZE_MODE_RESIZEABLE;
    410 
    411         for (ActivityStack aStack : mAmState.getStacks()) {
    412             final int stackId = aStack.mStackId;
    413             final WindowStack wStack = mWmState.getStack(stackId);
    414             assertNotNull("stackId=" + stackId + " in AM but not in WM?", wStack);
    415 
    416             assertEquals("Stack fullscreen state in AM and WM must be equal stackId=" + stackId,
    417                     aStack.isFullscreen(), wStack.isFullscreen());
    418 
    419             final Rect aStackBounds = aStack.getBounds();
    420             final Rect wStackBounds = wStack.getBounds();
    421 
    422             if (aStack.isFullscreen()) {
    423                 assertNull("Stack bounds in AM must be null stackId=" + stackId, aStackBounds);
    424             } else {
    425                 assertEquals("Stack bounds in AM and WM must be equal stackId=" + stackId,
    426                         aStackBounds, wStackBounds);
    427             }
    428 
    429             for (ActivityTask aTask : aStack.getTasks()) {
    430                 final int taskId = aTask.mTaskId;
    431                 final WindowTask wTask = wStack.getTask(taskId);
    432                 assertNotNull(
    433                         "taskId=" + taskId + " in AM but not in WM? stackId=" + stackId, wTask);
    434 
    435                 final boolean aTaskIsFullscreen = aTask.isFullscreen();
    436                 final boolean wTaskIsFullscreen = wTask.isFullscreen();
    437                 assertEquals("Task fullscreen state in AM and WM must be equal taskId=" + taskId
    438                         + ", stackId=" + stackId, aTaskIsFullscreen, wTaskIsFullscreen);
    439 
    440                 final Rect aTaskBounds = aTask.getBounds();
    441                 final Rect wTaskBounds = wTask.getBounds();
    442 
    443                 if (aTaskIsFullscreen) {
    444                     assertNull("Task bounds in AM must be null for fullscreen taskId=" + taskId,
    445                             aTaskBounds);
    446                 } else if (!homeStackIsResizable && mWmState.isDockedStackMinimized()
    447                         && !isScreenPortrait(aStack.mDisplayId)) {
    448                     // When minimized using non-resizable launcher in landscape mode, it will move
    449                     // the task offscreen in the negative x direction unlike portrait that crops.
    450                     // The x value in the task bounds will not match the stack bounds since the
    451                     // only the task was moved.
    452                     assertEquals("Task bounds in AM and WM must match width taskId=" + taskId
    453                                     + ", stackId" + stackId, aTaskBounds.width(),
    454                             wTaskBounds.width());
    455                     assertEquals("Task bounds in AM and WM must match height taskId=" + taskId
    456                                     + ", stackId" + stackId, aTaskBounds.height(),
    457                             wTaskBounds.height());
    458                     assertEquals("Task bounds must match stack bounds y taskId=" + taskId
    459                                     + ", stackId" + stackId, aTaskBounds.top,
    460                             wTaskBounds.top);
    461                     assertEquals("Task and stack bounds must match width taskId=" + taskId
    462                                     + ", stackId" + stackId, aStackBounds.width(),
    463                             wTaskBounds.width());
    464                     assertEquals("Task and stack bounds must match height taskId=" + taskId
    465                                     + ", stackId" + stackId, aStackBounds.height(),
    466                             wTaskBounds.height());
    467                     assertEquals("Task and stack bounds must match y taskId=" + taskId
    468                                     + ", stackId" + stackId, aStackBounds.top,
    469                             wTaskBounds.top);
    470                 } else {
    471                     assertEquals("Task bounds in AM and WM must be equal taskId=" + taskId
    472                             + ", stackId=" + stackId, aTaskBounds, wTaskBounds);
    473 
    474                     if (compareTaskAndStackBounds
    475                             && aStack.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
    476                         int aTaskMinWidth = aTask.getMinWidth();
    477                         int aTaskMinHeight = aTask.getMinHeight();
    478 
    479                         if (aTaskMinWidth == -1 || aTaskMinHeight == -1) {
    480                             // Minimal dimension(s) not set for task - it should be using defaults.
    481                             int defaultMinimalSize =
    482                                     aStack.getWindowingMode() == WINDOWING_MODE_PINNED
    483                                     ? defaultMinimalPinnedTaskSize(aStack.mDisplayId)
    484                                     : defaultMinimalTaskSize(aStack.mDisplayId);
    485 
    486                             if (aTaskMinWidth == -1) {
    487                                 aTaskMinWidth = defaultMinimalSize;
    488                             }
    489                             if (aTaskMinHeight == -1) {
    490                                 aTaskMinHeight = defaultMinimalSize;
    491                             }
    492                         }
    493 
    494                         if (aStackBounds.width() >= aTaskMinWidth
    495                                 && aStackBounds.height() >= aTaskMinHeight
    496                                 || aStack.getWindowingMode() == WINDOWING_MODE_PINNED) {
    497                             // Bounds are not smaller then minimal possible, so stack and task
    498                             // bounds must be equal.
    499                             assertEquals("Task bounds must be equal to stack bounds taskId="
    500                                     + taskId + ", stackId=" + stackId, aStackBounds, wTaskBounds);
    501                         } else if (aStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
    502                                 && homeStackIsResizable && mWmState.isDockedStackMinimized()) {
    503                             // Portrait if the display height is larger than the width
    504                             if (isScreenPortrait(aStack.mDisplayId)) {
    505                                 assertEquals("Task width must be equal to stack width taskId="
    506                                                 + taskId + ", stackId=" + stackId,
    507                                         aStackBounds.width(), wTaskBounds.width());
    508                                 assertThat("Task height must be greater than stack height "
    509                                                 + "taskId=" + taskId + ", stackId=" + stackId,
    510                                         aStackBounds.height(), lessThan(wTaskBounds.height()));
    511                                 assertEquals("Task and stack x position must be equal taskId="
    512                                                 + taskId + ", stackId=" + stackId,
    513                                         wTaskBounds.left, wStackBounds.left);
    514                             } else {
    515                                 assertThat("Task width must be greater than stack width taskId="
    516                                                 + taskId + ", stackId=" + stackId,
    517                                         aStackBounds.width(), lessThan(wTaskBounds.width()));
    518                                 assertEquals("Task height must be equal to stack height taskId="
    519                                                 + taskId + ", stackId=" + stackId,
    520                                         aStackBounds.height(), wTaskBounds.height());
    521                                 assertEquals("Task and stack y position must be equal taskId="
    522                                                 + taskId + ", stackId=" + stackId, wTaskBounds.top,
    523                                         wStackBounds.top);
    524                             }
    525                         } else {
    526                             // Minimal dimensions affect task size, so bounds of task and stack must
    527                             // be different - will compare dimensions instead.
    528                             int targetWidth = (int) Math.max(aTaskMinWidth,
    529                                     aStackBounds.width());
    530                             assertEquals("Task width must be set according to minimal width"
    531                                             + " taskId=" + taskId + ", stackId=" + stackId,
    532                                     targetWidth, (int) wTaskBounds.width());
    533                             int targetHeight = (int) Math.max(aTaskMinHeight,
    534                                     aStackBounds.height());
    535                             assertEquals("Task height must be set according to minimal height"
    536                                             + " taskId=" + taskId + ", stackId=" + stackId,
    537                                     targetHeight, (int) wTaskBounds.height());
    538                         }
    539                     }
    540                 }
    541             }
    542         }
    543     }
    544 
    545     boolean isScreenPortrait(int displayId) {
    546         final Rect displayRect = mWmState.getDisplay(displayId).getDisplayRect();
    547         return displayRect.height() > displayRect.width();
    548     }
    549 
    550     static int dpToPx(float dp, int densityDpi) {
    551         return (int) (dp * densityDpi / DISPLAY_DENSITY_DEFAULT + 0.5f);
    552     }
    553 
    554     private int defaultMinimalTaskSize(int displayId) {
    555         return dpToPx(DEFAULT_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi());
    556     }
    557 
    558     private int defaultMinimalPinnedTaskSize(int displayId) {
    559         return dpToPx(DEFAULT_PIP_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi());
    560     }
    561 }
    562