Home | History | Annotate | Download | only in am
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.server.am;
     18 
     19 import android.annotation.IntDef;
     20 import android.app.ActivityOptions;
     21 import android.content.pm.ActivityInfo.WindowLayout;
     22 import android.graphics.Rect;
     23 
     24 import java.lang.annotation.Retention;
     25 import java.lang.annotation.RetentionPolicy;
     26 import java.util.ArrayList;
     27 import java.util.List;
     28 
     29 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
     30 import static android.view.Display.INVALID_DISPLAY;
     31 
     32 import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
     33 import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
     34 import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
     35 
     36 /**
     37  * {@link LaunchParamsController} calculates the {@link LaunchParams} by coordinating between
     38  * registered {@link LaunchParamsModifier}s.
     39  */
     40 class LaunchParamsController {
     41     private final ActivityManagerService mService;
     42     private final List<LaunchParamsModifier> mModifiers = new ArrayList<>();
     43 
     44     // Temporary {@link LaunchParams} for internal calculations. This is kept separate from
     45     // {@code mTmpCurrent} and {@code mTmpResult} to prevent clobbering values.
     46     private final LaunchParams mTmpParams = new LaunchParams();
     47 
     48     private final LaunchParams mTmpCurrent = new LaunchParams();
     49     private final LaunchParams mTmpResult = new LaunchParams();
     50 
     51     LaunchParamsController(ActivityManagerService service) {
     52        mService = service;
     53     }
     54 
     55     /**
     56      * Creates a {@link LaunchParamsController} with default registered
     57      * {@link LaunchParamsModifier}s.
     58      */
     59     void registerDefaultModifiers(ActivityStackSupervisor supervisor) {
     60         // {@link TaskLaunchParamsModifier} handles window layout preferences.
     61         registerModifier(new TaskLaunchParamsModifier());
     62 
     63         // {@link ActivityLaunchParamsModifier} is the most specific modifier and thus should be
     64         // registered last (applied first) out of the defaults.
     65         registerModifier(new ActivityLaunchParamsModifier(supervisor));
     66     }
     67 
     68     /**
     69      * Returns the {@link LaunchParams} calculated by the registered modifiers
     70      * @param task      The {@link TaskRecord} currently being positioned.
     71      * @param layout    The specified {@link WindowLayout}.
     72      * @param activity  The {@link ActivityRecord} currently being positioned.
     73      * @param source    The {@link ActivityRecord} from which activity was started from.
     74      * @param options   The {@link ActivityOptions} specified for the activity.
     75      * @param result    The resulting params.
     76      */
     77     void calculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
     78                    ActivityRecord source, ActivityOptions options, LaunchParams result) {
     79         result.reset();
     80 
     81         // We start at the last registered {@link LaunchParamsModifier} as this represents
     82         // The modifier closest to the product level. Moving back through the list moves closer to
     83         // the platform logic.
     84         for (int i = mModifiers.size() - 1; i >= 0; --i) {
     85             mTmpCurrent.set(result);
     86             mTmpResult.reset();
     87             final LaunchParamsModifier modifier = mModifiers.get(i);
     88 
     89             switch(modifier.onCalculate(task, layout, activity, source, options, mTmpCurrent,
     90                     mTmpResult)) {
     91                 case RESULT_SKIP:
     92                     // Do not apply any results when we are told to skip
     93                     continue;
     94                 case RESULT_DONE:
     95                     // Set result and return immediately.
     96                     result.set(mTmpResult);
     97                     return;
     98                 case RESULT_CONTINUE:
     99                     // Set result and continue
    100                     result.set(mTmpResult);
    101                     break;
    102             }
    103         }
    104     }
    105 
    106     /**
    107      * A convenience method for laying out a task.
    108      * @return {@code true} if bounds were set on the task. {@code false} otherwise.
    109      */
    110     boolean layoutTask(TaskRecord task, WindowLayout layout) {
    111         return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
    112     }
    113 
    114     boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
    115             ActivityRecord source, ActivityOptions options) {
    116         calculate(task, layout, activity, source, options, mTmpParams);
    117 
    118         // No changes, return.
    119         if (mTmpParams.isEmpty()) {
    120             return false;
    121         }
    122 
    123         mService.mWindowManager.deferSurfaceLayout();
    124 
    125         try {
    126             if (mTmpParams.hasPreferredDisplay()
    127                     && mTmpParams.mPreferredDisplayId != task.getStack().getDisplay().mDisplayId) {
    128                 mService.moveStackToDisplay(task.getStackId(), mTmpParams.mPreferredDisplayId);
    129             }
    130 
    131             if (mTmpParams.hasWindowingMode()
    132                     && mTmpParams.mWindowingMode != task.getStack().getWindowingMode()) {
    133                 task.getStack().setWindowingMode(mTmpParams.mWindowingMode);
    134             }
    135 
    136             if (!mTmpParams.mBounds.isEmpty()) {
    137                 task.updateOverrideConfiguration(mTmpParams.mBounds);
    138                 return true;
    139             } else {
    140                 return false;
    141             }
    142         } finally {
    143             mService.mWindowManager.continueSurfaceLayout();
    144         }
    145     }
    146 
    147     /**
    148      * Adds a modifier to participate in future bounds calculation. Note that the last registered
    149      * {@link LaunchParamsModifier} will be the first to calculate the bounds.
    150      */
    151     void registerModifier(LaunchParamsModifier modifier) {
    152         if (mModifiers.contains(modifier)) {
    153             return;
    154         }
    155 
    156         mModifiers.add(modifier);
    157     }
    158 
    159     /**
    160      * A container for holding launch related fields.
    161      */
    162     static class LaunchParams {
    163         /** The bounds within the parent container. */
    164         final Rect mBounds = new Rect();
    165 
    166         /** The id of the display the {@link TaskRecord} would prefer to be on. */
    167         int mPreferredDisplayId;
    168 
    169         /** The windowing mode to be in. */
    170         int mWindowingMode;
    171 
    172         /** Sets values back to default. {@link #isEmpty} will return {@code true} once called. */
    173         void reset() {
    174             mBounds.setEmpty();
    175             mPreferredDisplayId = INVALID_DISPLAY;
    176             mWindowingMode = WINDOWING_MODE_UNDEFINED;
    177         }
    178 
    179         /** Copies the values set on the passed in {@link LaunchParams}. */
    180         void set(LaunchParams params) {
    181             mBounds.set(params.mBounds);
    182             mPreferredDisplayId = params.mPreferredDisplayId;
    183             mWindowingMode = params.mWindowingMode;
    184         }
    185 
    186         /** Returns {@code true} if no values have been explicitly set. */
    187         boolean isEmpty() {
    188             return mBounds.isEmpty() && mPreferredDisplayId == INVALID_DISPLAY
    189                     && mWindowingMode == WINDOWING_MODE_UNDEFINED;
    190         }
    191 
    192         boolean hasWindowingMode() {
    193             return mWindowingMode != WINDOWING_MODE_UNDEFINED;
    194         }
    195 
    196         boolean hasPreferredDisplay() {
    197             return mPreferredDisplayId != INVALID_DISPLAY;
    198         }
    199 
    200         @Override
    201         public boolean equals(Object o) {
    202             if (this == o) return true;
    203             if (o == null || getClass() != o.getClass()) return false;
    204 
    205             LaunchParams that = (LaunchParams) o;
    206 
    207             if (mPreferredDisplayId != that.mPreferredDisplayId) return false;
    208             if (mWindowingMode != that.mWindowingMode) return false;
    209             return mBounds != null ? mBounds.equals(that.mBounds) : that.mBounds == null;
    210         }
    211 
    212         @Override
    213         public int hashCode() {
    214             int result = mBounds != null ? mBounds.hashCode() : 0;
    215             result = 31 * result + mPreferredDisplayId;
    216             result = 31 * result + mWindowingMode;
    217             return result;
    218         }
    219     }
    220 
    221     /**
    222      * An interface implemented by those wanting to participate in bounds calculation.
    223      */
    224     interface LaunchParamsModifier {
    225         @Retention(RetentionPolicy.SOURCE)
    226         @IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
    227         @interface Result {}
    228 
    229         // Returned when the modifier does not want to influence the bounds calculation
    230         int RESULT_SKIP = 0;
    231         // Returned when the modifier has changed the bounds and would like its results to be the
    232         // final bounds applied.
    233         int RESULT_DONE = 1;
    234         // Returned when the modifier has changed the bounds but is okay with other modifiers
    235         // influencing the bounds.
    236         int RESULT_CONTINUE = 2;
    237 
    238         /**
    239          * Called when asked to calculate {@link LaunchParams}.
    240          * @param task            The {@link TaskRecord} currently being positioned.
    241          * @param layout          The specified {@link WindowLayout}.
    242          * @param activity        The {@link ActivityRecord} currently being positioned.
    243          * @param source          The {@link ActivityRecord} activity was started from.
    244          * @param options         The {@link ActivityOptions} specified for the activity.
    245          * @param currentParams   The current {@link LaunchParams}. This can differ from the initial
    246          *                        params as it represents the modified params up to this point.
    247          * @param outParams       The resulting {@link LaunchParams} after all calculations.
    248          * @return                A {@link Result} representing the result of the
    249          *                        {@link LaunchParams} calculation.
    250          */
    251         @Result
    252         int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
    253                 ActivityRecord source, ActivityOptions options, LaunchParams currentParams,
    254                 LaunchParams outParams);
    255     }
    256 }
    257