Home | History | Annotate | Download | only in wm
      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 com.android.server.wm;
     18 
     19 import android.app.ActivityManager.TaskDescription;
     20 import android.app.ActivityManager.TaskSnapshot;
     21 import android.content.res.Configuration;
     22 import android.graphics.Rect;
     23 import android.os.Handler;
     24 import android.os.Looper;
     25 import android.os.Message;
     26 import android.util.EventLog;
     27 import android.util.Slog;
     28 import com.android.internal.annotations.VisibleForTesting;
     29 
     30 import java.lang.ref.WeakReference;
     31 
     32 import static com.android.server.EventLogTags.WM_TASK_CREATED;
     33 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
     34 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
     35 import static com.android.server.wm.WindowContainer.POSITION_TOP;
     36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
     37 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     38 
     39 /**
     40  * Controller for the task container. This is created by activity manager to link task records to
     41  * the task container they use in window manager.
     42  *
     43  * Test class: {@link TaskWindowContainerControllerTests}
     44  */
     45 public class TaskWindowContainerController
     46         extends WindowContainerController<Task, TaskWindowContainerListener> {
     47 
     48     private final int mTaskId;
     49     private final H mHandler;
     50 
     51     public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
     52             StackWindowController stackController, int userId, Rect bounds,
     53             Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
     54             boolean homeTask, boolean toTop, boolean showForAllUsers,
     55             TaskDescription taskDescription) {
     56         this(taskId, listener, stackController, userId, bounds, overrideConfig, resizeMode,
     57                 supportsPictureInPicture, homeTask, toTop, showForAllUsers, taskDescription,
     58                 WindowManagerService.getInstance());
     59     }
     60 
     61     public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
     62             StackWindowController stackController, int userId, Rect bounds,
     63             Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
     64             boolean homeTask, boolean toTop, boolean showForAllUsers,
     65             TaskDescription taskDescription, WindowManagerService service) {
     66         super(listener, service);
     67         mTaskId = taskId;
     68         mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
     69 
     70         synchronized(mWindowMap) {
     71             if (DEBUG_STACK) Slog.i(TAG_WM, "TaskWindowContainerController: taskId=" + taskId
     72                     + " stack=" + stackController + " bounds=" + bounds);
     73 
     74             final TaskStack stack = stackController.mContainer;
     75             if (stack == null) {
     76                 throw new IllegalArgumentException("TaskWindowContainerController: invalid stack="
     77                         + stackController);
     78             }
     79             EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
     80             final Task task = createTask(taskId, stack, userId, bounds, overrideConfig, resizeMode,
     81                     supportsPictureInPicture, homeTask, taskDescription);
     82             final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
     83             // We only want to move the parents to the parents if we are creating this task at the
     84             // top of its stack.
     85             stack.addTask(task, position, showForAllUsers, toTop /* moveParents */);
     86         }
     87     }
     88 
     89     @VisibleForTesting
     90     Task createTask(int taskId, TaskStack stack, int userId, Rect bounds,
     91             Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
     92             boolean homeTask, TaskDescription taskDescription) {
     93         return new Task(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
     94                 supportsPictureInPicture, homeTask, taskDescription, this);
     95     }
     96 
     97     @Override
     98     public void removeContainer() {
     99         synchronized(mWindowMap) {
    100             if (mContainer == null) {
    101                 if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId);
    102                 return;
    103             }
    104             mContainer.removeIfPossible();
    105             super.removeContainer();
    106         }
    107     }
    108 
    109     public void positionChildAt(AppWindowContainerController childController, int position) {
    110         synchronized(mService.mWindowMap) {
    111             final AppWindowToken aToken = childController.mContainer;
    112             if (aToken == null) {
    113                 Slog.w(TAG_WM,
    114                         "Attempted to position of non-existing app : " + childController);
    115                 return;
    116             }
    117 
    118             final Task task = mContainer;
    119             if (task == null) {
    120                 throw new IllegalArgumentException("positionChildAt: invalid task=" + this);
    121             }
    122             task.positionChildAt(position, aToken, false /* includeParents */);
    123         }
    124     }
    125 
    126     public void reparent(StackWindowController stackController, int position, boolean moveParents) {
    127         synchronized (mWindowMap) {
    128             if (DEBUG_STACK) Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId
    129                     + " to stack=" + stackController + " at " + position);
    130             if (mContainer == null) {
    131                 if (DEBUG_STACK) Slog.i(TAG_WM,
    132                         "reparent: could not find taskId=" + mTaskId);
    133                 return;
    134             }
    135             final TaskStack stack = stackController.mContainer;
    136             if (stack == null) {
    137                 throw new IllegalArgumentException("reparent: could not find stack="
    138                         + stackController);
    139             }
    140             mContainer.reparent(stack, position, moveParents);
    141             mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
    142         }
    143     }
    144 
    145     public void setResizeable(int resizeMode) {
    146         synchronized (mWindowMap) {
    147             if (mContainer != null) {
    148                 mContainer.setResizeable(resizeMode);
    149             }
    150         }
    151     }
    152 
    153     public void resize(Rect bounds, Configuration overrideConfig, boolean relayout,
    154             boolean forced) {
    155         synchronized (mWindowMap) {
    156             if (mContainer == null) {
    157                 throw new IllegalArgumentException("resizeTask: taskId " + mTaskId + " not found.");
    158             }
    159 
    160             if (mContainer.resizeLocked(bounds, overrideConfig, forced) && relayout) {
    161                 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
    162             }
    163         }
    164     }
    165 
    166     public void getBounds(Rect bounds) {
    167         synchronized (mWindowMap) {
    168             if (mContainer != null) {
    169                 mContainer.getBounds(bounds);
    170                 return;
    171             }
    172             bounds.setEmpty();
    173         }
    174     }
    175 
    176     /**
    177      * Puts this task into docked drag resizing mode. See {@link DragResizeMode}.
    178      *
    179      * @param resizing Whether to put the task into drag resize mode.
    180      */
    181     public void setTaskDockedResizing(boolean resizing) {
    182         synchronized (mWindowMap) {
    183             if (mContainer == null) {
    184                 Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found.");
    185                 return;
    186             }
    187             mContainer.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
    188         }
    189     }
    190 
    191     public void cancelWindowTransition() {
    192         synchronized (mWindowMap) {
    193             if (mContainer == null) {
    194                 Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found.");
    195                 return;
    196             }
    197             mContainer.cancelTaskWindowTransition();
    198         }
    199     }
    200 
    201     public void cancelThumbnailTransition() {
    202         synchronized (mWindowMap) {
    203             if (mContainer == null) {
    204                 Slog.w(TAG_WM, "cancelThumbnailTransition: taskId " + mTaskId + " not found.");
    205                 return;
    206             }
    207             mContainer.cancelTaskThumbnailTransition();
    208         }
    209     }
    210 
    211     public void setTaskDescription(TaskDescription taskDescription) {
    212         synchronized (mWindowMap) {
    213             if (mContainer == null) {
    214                 Slog.w(TAG_WM, "setTaskDescription: taskId " + mTaskId + " not found.");
    215                 return;
    216             }
    217             mContainer.setTaskDescription(taskDescription);
    218         }
    219     }
    220 
    221     void reportSnapshotChanged(TaskSnapshot snapshot) {
    222         mHandler.obtainMessage(H.REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget();
    223     }
    224 
    225     void requestResize(Rect bounds, int resizeMode) {
    226         mHandler.obtainMessage(H.REQUEST_RESIZE, resizeMode, 0, bounds).sendToTarget();
    227     }
    228 
    229     @Override
    230     public String toString() {
    231         return "{TaskWindowContainerController taskId=" + mTaskId + "}";
    232     }
    233 
    234     private static final class H extends Handler {
    235 
    236         static final int REPORT_SNAPSHOT_CHANGED = 0;
    237         static final int REQUEST_RESIZE = 1;
    238 
    239         private final WeakReference<TaskWindowContainerController> mController;
    240 
    241         H(WeakReference<TaskWindowContainerController> controller, Looper looper) {
    242             super(looper);
    243             mController = controller;
    244         }
    245 
    246         @Override
    247         public void handleMessage(Message msg) {
    248             final TaskWindowContainerController controller = mController.get();
    249             final TaskWindowContainerListener listener = (controller != null)
    250                     ? controller.mListener : null;
    251             if (listener == null) {
    252                 return;
    253             }
    254             switch (msg.what) {
    255                 case REPORT_SNAPSHOT_CHANGED:
    256                     listener.onSnapshotChanged((TaskSnapshot) msg.obj);
    257                     break;
    258                 case REQUEST_RESIZE:
    259                     listener.requestResize((Rect) msg.obj, msg.arg1);
    260                     break;
    261             }
    262         }
    263     }
    264 }
    265