Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c671ce1 authored by Charles Chen's avatar Charles Chen Committed by Android (Google) Code Review
Browse files

Merge "Choose TDA by DisplayAreaPolicy for WindowContext"

parents 66cd7d57 082dec98
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -3691,6 +3691,18 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "1874559932": {
      "message": "The TaskDisplayArea with %s does not exist.",
      "level": "WARN",
      "group": "WM_DEBUG_WINDOW_ORGANIZER",
      "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java"
    },
    "1884961873": {
      "message": "Sleep still need to stop %d activities",
      "level": "VERBOSE",
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/Task.java"
    },
    "1891501279": {
      "message": "cancelAnimation(): reason=%s",
      "level": "DEBUG",
+4 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION
import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
import static com.android.server.wm.DisplayAreaPolicyBuilder.HierarchyBuilder;

import android.annotation.Nullable;
import android.content.res.Resources;
import android.os.Bundle;
import android.text.TextUtils;
@@ -86,6 +87,9 @@ public abstract class DisplayAreaPolicy {
     */
    public abstract TaskDisplayArea getDefaultTaskDisplayArea();

    /** Returns the {@link TaskDisplayArea} specified by launch options. */
    public abstract TaskDisplayArea getTaskDisplayArea(@Nullable Bundle options);

    /** Provider for platform-default display area policy. */
    static final class DefaultProvider implements DisplayAreaPolicy.Provider {
        @Override
+82 −5
Original line number Diff line number Diff line
@@ -27,12 +27,19 @@ import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
import static android.window.DisplayAreaOrganizer.KEY_ROOT_DISPLAY_AREA_ID;

import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.os.Bundle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.window.DisplayAreaOrganizer;
import android.window.WindowContainerToken;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;

import java.util.ArrayList;
@@ -43,6 +50,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * A builder for instantiating a complex {@link DisplayAreaPolicy}
@@ -149,6 +157,8 @@ class DisplayAreaPolicyBuilder {
     **/
    @Nullable private BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;

    @Nullable private Function<Bundle, TaskDisplayArea> mSelectTaskDisplayAreaFunc;

    /** Defines the root hierarchy for the whole logical display. */
    DisplayAreaPolicyBuilder setRootHierarchy(HierarchyBuilder rootHierarchyBuilder) {
        mRootHierarchyBuilder = rootHierarchyBuilder;
@@ -175,6 +185,16 @@ class DisplayAreaPolicyBuilder {
        return this;
    }

    /**
     * The policy will use this function to find the {@link TaskDisplayArea}.
     * @see DefaultSelectTaskDisplayAreaFunction as an example.
     */
    DisplayAreaPolicyBuilder setSelectTaskDisplayAreaFunc(
            Function<Bundle, TaskDisplayArea> selectTaskDisplayAreaFunc) {
        mSelectTaskDisplayAreaFunc = selectTaskDisplayAreaFunc;
        return this;
    }

    /**
     * Makes sure the setting meets the requirement:
     * 1. {@link #mRootHierarchyBuilder} must be set.
@@ -182,8 +202,9 @@ class DisplayAreaPolicyBuilder {
     * 3. {@link Feature} below the same {@link RootDisplayArea} must have unique ids.
     * 4. There must be exactly one {@link HierarchyBuilder} that contains the IME container.
     * 5. There must be exactly one {@link HierarchyBuilder} that contains the default
     *    {@link TaskDisplayArea} with id {@link FEATURE_DEFAULT_TASK_CONTAINER}.
     * 6. None of the ids is greater than {@link FEATURE_VENDOR_LAST}.
     *    {@link TaskDisplayArea} with id
     *    {@link DisplayAreaOrganizer#FEATURE_DEFAULT_TASK_CONTAINER}.
     * 6. None of the ids is greater than {@link DisplayAreaOrganizer#FEATURE_VENDOR_LAST}.
     */
    private void validate() {
        if (mRootHierarchyBuilder == null) {
@@ -250,7 +271,7 @@ class DisplayAreaPolicyBuilder {
     * {@link Feature} below the same {@link RootDisplayArea} must have unique ids, but
     * {@link Feature} below different {@link RootDisplayArea} can have the same id so that we can
     * organize them together.
     * None of the ids is greater than {@link FEATURE_VENDOR_LAST}
     * None of the ids is greater than {@link DisplayAreaOrganizer#FEATURE_VENDOR_LAST}
     *
     * @param uniqueIdSet ids of {@link RootDisplayArea} and {@link TaskDisplayArea} that must be
     *                    unique,
@@ -323,7 +344,7 @@ class DisplayAreaPolicyBuilder {
                    mRootHierarchyBuilder.mRoot, displayAreaGroupRoots);
        }
        return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
                mSelectRootForWindowFunc);
                mSelectRootForWindowFunc, mSelectTaskDisplayAreaFunc);
    }

    /**
@@ -367,6 +388,51 @@ class DisplayAreaPolicyBuilder {
        }
    }

    /**
     * The default function to find {@link TaskDisplayArea} if there's no other function set
     * through {@link #setSelectTaskDisplayAreaFunc(Function)}.
     * <p>
     * This function returns {@link TaskDisplayArea} specified by
     * {@link ActivityOptions#getLaunchTaskDisplayArea()} if it is not {@code null}. Otherwise,
     * returns {@link DisplayContent#getDefaultTaskDisplayArea()}.
     * </p>
     */
    private static class DefaultSelectTaskDisplayAreaFunction implements
            Function<Bundle, TaskDisplayArea> {
        private final TaskDisplayArea mDefaultTaskDisplayArea;
        private final int mDisplayId;

        DefaultSelectTaskDisplayAreaFunction(TaskDisplayArea defaultTaskDisplayArea) {
            mDefaultTaskDisplayArea = defaultTaskDisplayArea;
            mDisplayId = defaultTaskDisplayArea.getDisplayId();
        }

        @Override
        public TaskDisplayArea apply(@Nullable Bundle options) {
            if (options == null) {
                return mDefaultTaskDisplayArea;
            }
            final ActivityOptions activityOptions = new ActivityOptions(options);
            final WindowContainerToken tdaToken = activityOptions.getLaunchTaskDisplayArea();
            if (tdaToken == null) {
                return mDefaultTaskDisplayArea;
            }
            final TaskDisplayArea tda = WindowContainer.fromBinder(tdaToken.asBinder())
                    .asTaskDisplayArea();
            if (tda == null) {
                ProtoLog.w(WM_DEBUG_WINDOW_ORGANIZER, "The TaskDisplayArea with %s does not "
                        + "exist.", tdaToken);
                return mDefaultTaskDisplayArea;
            }
            if (tda.getDisplayId() != mDisplayId) {
                throw new IllegalArgumentException("The specified TaskDisplayArea must attach "
                        + "to Display#" + mDisplayId + ", but it is in Display#"
                        + tda.getDisplayId());
            }
            return tda;
        }
    }

    /**
     *  Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a
     * {@link RootDisplayArea}
@@ -722,11 +788,13 @@ class DisplayAreaPolicyBuilder {
    static class Result extends DisplayAreaPolicy {
        final List<RootDisplayArea> mDisplayAreaGroupRoots;
        final BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
        private final Function<Bundle, TaskDisplayArea> mSelectTaskDisplayAreaFunc;
        private final TaskDisplayArea mDefaultTaskDisplayArea;

        Result(WindowManagerService wmService, RootDisplayArea root,
                List<RootDisplayArea> displayAreaGroupRoots,
                BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
                BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc,
                Function<Bundle, TaskDisplayArea> selectTaskDisplayAreaFunc) {
            super(wmService, root);
            mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
            mSelectRootForWindowFunc = selectRootForWindowFunc;
@@ -740,6 +808,9 @@ class DisplayAreaPolicyBuilder {
                throw new IllegalStateException(
                        "No display area with FEATURE_DEFAULT_TASK_CONTAINER");
            }
            mSelectTaskDisplayAreaFunc = selectTaskDisplayAreaFunc != null
                    ? selectTaskDisplayAreaFunc
                    : new DefaultSelectTaskDisplayAreaFunction(mDefaultTaskDisplayArea);
        }

        @Override
@@ -796,6 +867,12 @@ class DisplayAreaPolicyBuilder {
        public TaskDisplayArea getDefaultTaskDisplayArea() {
            return mDefaultTaskDisplayArea;
        }

        @NonNull
        @Override
        public TaskDisplayArea getTaskDisplayArea(@Nullable Bundle options) {
            return mSelectTaskDisplayAreaFunc.apply(options);
        }
    }

    static class PendingArea {
+1 −2
Original line number Diff line number Diff line
@@ -6464,9 +6464,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp

    DisplayArea findAreaForWindowType(int windowType, Bundle options,
            boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
        // TODO(b/159767464): figure out how to find an appropriate TDA.
        if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
            return getDefaultTaskDisplayArea();
            return mDisplayAreaPolicy.getTaskDisplayArea(options);
        }
        // Return IME container here because it could be in one of sub RootDisplayAreas depending on
        // the focused edit text. Also, the RootDisplayArea choosing strategy is implemented by
+208 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -48,12 +49,14 @@ import static org.testng.Assert.assertThrows;

import static java.util.stream.Collectors.toList;

import android.app.ActivityOptions;
import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.window.WindowContainerToken;

import com.google.android.collect.Lists;

@@ -80,6 +83,8 @@ import java.util.stream.Collectors;
 */
@Presubmit
public class DisplayAreaPolicyBuilderTest {
    private static final String KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID =
            "android.test.launchTaskDisplayAreaFeatureId";

    @Rule
    public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule();
@@ -103,6 +108,7 @@ public class DisplayAreaPolicyBuilderTest {
        mImeContainer = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "ImeContainer");
        mDisplayContent = mock(DisplayContent.class);
        doReturn(true).when(mDisplayContent).isTrusted();
        doReturn(DEFAULT_DISPLAY).when(mDisplayContent).getDisplayId();
        mDisplayContent.isDefaultDisplay = true;
        mDefaultTaskDisplayArea = new TaskDisplayArea(mDisplayContent, mWms, "Tasks",
                FEATURE_DEFAULT_TASK_CONTAINER);
@@ -711,6 +717,208 @@ public class DisplayAreaPolicyBuilderTest {
                .build();
    }

    @Test
    public void testGetTaskDisplayArea_DefaultFunction_NullOptions_ReturnsDefaultTda() {
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                        .setTaskDisplayAreas(mTaskDisplayAreaList);
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1)
                        .setImeContainer(mImeContainer)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda1));
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda2));
        final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
                .setRootHierarchy(hierarchy0)
                .addDisplayAreaGroupHierarchy(hierarchy1)
                .addDisplayAreaGroupHierarchy(hierarchy2)
                .build(mWms);

        final TaskDisplayArea tda = policy.getTaskDisplayArea(null /* options */);

        assertThat(tda).isEqualTo(mDefaultTaskDisplayArea);
        assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea());
    }

    @Test
    public void testGetTaskDisplayArea_DefaultFunction_NotContainsLunchedTda_ReturnsDefaultTda() {
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                        .setTaskDisplayAreas(mTaskDisplayAreaList);
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1)
                        .setImeContainer(mImeContainer)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda1));
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda2));
        final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
                .setRootHierarchy(hierarchy0)
                .addDisplayAreaGroupHierarchy(hierarchy1)
                .addDisplayAreaGroupHierarchy(hierarchy2)
                .build(mWms);

        final TaskDisplayArea tda = policy.getTaskDisplayArea(new Bundle());

        assertThat(tda).isEqualTo(mDefaultTaskDisplayArea);
        assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea());
    }

    @Test
    public void testGetTaskDisplayArea_DefaultFunction_InvalidTdaToken_ReturnsDefaultTda() {
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                        .setTaskDisplayAreas(mTaskDisplayAreaList);
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1)
                        .setImeContainer(mImeContainer)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda1));
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda2));
        final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
                .setRootHierarchy(hierarchy0)
                .addDisplayAreaGroupHierarchy(hierarchy1)
                .addDisplayAreaGroupHierarchy(hierarchy2)
                .build(mWms);
        final ActivityOptions options = ActivityOptions.makeBasic();
        final WindowContainerToken fakeToken = mRoot.mRemoteToken.toWindowContainerToken();
        options.setLaunchTaskDisplayArea(fakeToken);

        final TaskDisplayArea tda = policy.getTaskDisplayArea(options.toBundle());

        assertThat(tda).isEqualTo(mDefaultTaskDisplayArea);
        assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea());
    }

    @Test(expected = IllegalArgumentException.class)
    public void testGetTaskDisplayArea_DefaultFunction_TdaOnDifferentDisplay_ThrowException() {
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                        .setTaskDisplayAreas(mTaskDisplayAreaList);
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1)
                        .setImeContainer(mImeContainer)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda1));
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda2));
        final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
                .setRootHierarchy(hierarchy0)
                .addDisplayAreaGroupHierarchy(hierarchy1)
                .addDisplayAreaGroupHierarchy(hierarchy2)
                .build(mWms);
        final TaskDisplayArea tdaOnSecondaryDisplay = mock(TaskDisplayArea.class);
        doReturn(DEFAULT_DISPLAY + 1).when(tdaOnSecondaryDisplay).getDisplayId();
        doReturn(tdaOnSecondaryDisplay).when(tdaOnSecondaryDisplay).asTaskDisplayArea();
        tdaOnSecondaryDisplay.mRemoteToken = new WindowContainer.RemoteToken(tdaOnSecondaryDisplay);

        final WindowContainerToken tdaToken = tdaOnSecondaryDisplay.mRemoteToken
                .toWindowContainerToken();
        final ActivityOptions options = ActivityOptions.makeBasic();
        options.setLaunchTaskDisplayArea(tdaToken);
        final TaskDisplayArea tda = policy.getTaskDisplayArea(options.toBundle());

        assertThat(tda).isEqualTo(mDefaultTaskDisplayArea);
        assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea());
    }

    @Test
    public void testGetTaskDisplayArea_DefaultFunction_ContainsTdaToken_ReturnsTda() {
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                        .setTaskDisplayAreas(mTaskDisplayAreaList);
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1)
                        .setImeContainer(mImeContainer)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda1));
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda2));
        final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
                .setRootHierarchy(hierarchy0)
                .addDisplayAreaGroupHierarchy(hierarchy1)
                .addDisplayAreaGroupHierarchy(hierarchy2)
                .build(mWms);
        final ActivityOptions options = ActivityOptions.makeBasic();

        final WindowContainerToken defaultTdaToken = mDefaultTaskDisplayArea.mRemoteToken
                .toWindowContainerToken();
        options.setLaunchTaskDisplayArea(defaultTdaToken);
        TaskDisplayArea tda = policy.getTaskDisplayArea(options.toBundle());

        assertThat(tda).isEqualTo(mDefaultTaskDisplayArea);
        assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea());

        final WindowContainerToken tda1Token = mTda1.mRemoteToken.toWindowContainerToken();
        options.setLaunchTaskDisplayArea(tda1Token);
        tda = policy.getTaskDisplayArea(options.toBundle());

        assertThat(tda).isEqualTo(mTda1);

        final WindowContainerToken tda2Token = mTda2.mRemoteToken.toWindowContainerToken();
        options.setLaunchTaskDisplayArea(tda2Token);
        tda = policy.getTaskDisplayArea(options.toBundle());

        assertThat(tda).isEqualTo(mTda2);
    }

    @Test
    public void testBuilder_getTaskDisplayArea_setSelectTaskDisplayAreaFunc() {
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
                        .setTaskDisplayAreas(mTaskDisplayAreaList);
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1)
                        .setImeContainer(mImeContainer)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda1));
        final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
                new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2)
                        .setTaskDisplayAreas(Lists.newArrayList(mTda2));
        final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
                .setRootHierarchy(hierarchy0)
                .setSelectTaskDisplayAreaFunc((options) -> {
                    if (options == null) {
                        return mDefaultTaskDisplayArea;
                    }
                    final int tdaFeatureId =
                            options.getInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID);
                    if (tdaFeatureId == mTda1.mFeatureId) {
                        return mTda1;
                    }
                    if (tdaFeatureId == mTda2.mFeatureId) {
                        return mTda2;
                    }
                    return mDefaultTaskDisplayArea;
                })
                .addDisplayAreaGroupHierarchy(hierarchy1)
                .addDisplayAreaGroupHierarchy(hierarchy2)
                .build(mWms);

        TaskDisplayArea tda = policy.getTaskDisplayArea(null /* options */);

        assertThat(tda).isEqualTo(mDefaultTaskDisplayArea);
        assertThat(tda).isEqualTo(policy.getDefaultTaskDisplayArea());

        final Bundle options = new Bundle();
        options.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, -1);
        tda = policy.getTaskDisplayArea(options);
        assertThat(tda).isEqualTo(mDefaultTaskDisplayArea);

        options.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, mDefaultTaskDisplayArea.mFeatureId);
        tda = policy.getTaskDisplayArea(options);
        assertThat(tda).isEqualTo(mDefaultTaskDisplayArea);

        options.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, mTda1.mFeatureId);
        tda = policy.getTaskDisplayArea(options);
        assertThat(tda).isEqualTo(mTda1);

        options.putInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID, mTda2.mFeatureId);
        tda = policy.getTaskDisplayArea(options);
        assertThat(tda).isEqualTo(mTda2);
    }

    private static Resources resourcesWithProvider(String provider) {
        Resources mock = mock(Resources.class);
        when(mock.getString(