Home | History | Annotate | Download | only in wm
      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.wm;
     18 
     19 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
     20 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     21 
     22 import android.annotation.Nullable;
     23 import android.app.IActivityManager;
     24 import android.os.RemoteException;
     25 import android.os.Handler;
     26 import android.os.Looper;
     27 import android.util.Slog;
     28 import android.view.Display;
     29 import android.view.IWindow;
     30 import com.android.internal.annotations.GuardedBy;
     31 import com.android.server.input.InputManagerService;
     32 import com.android.server.input.InputWindowHandle;
     33 
     34 /**
     35  * Controller for task positioning by drag.
     36  */
     37 class TaskPositioningController {
     38     private final WindowManagerService mService;
     39     private final InputManagerService mInputManager;
     40     private final InputMonitor mInputMonitor;
     41     private final IActivityManager mActivityManager;
     42     private final Handler mHandler;
     43 
     44     @GuardedBy("WindowManagerSerivce.mWindowMap")
     45     private @Nullable TaskPositioner mTaskPositioner;
     46 
     47     boolean isPositioningLocked() {
     48         return mTaskPositioner != null;
     49     }
     50 
     51     InputWindowHandle getDragWindowHandleLocked() {
     52         return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
     53     }
     54 
     55     TaskPositioningController(WindowManagerService service, InputManagerService inputManager,
     56             InputMonitor inputMonitor, IActivityManager activityManager, Looper looper) {
     57         mService = service;
     58         mInputMonitor = inputMonitor;
     59         mInputManager = inputManager;
     60         mActivityManager = activityManager;
     61         mHandler = new Handler(looper);
     62     }
     63 
     64     boolean startMovingTask(IWindow window, float startX, float startY) {
     65         WindowState win = null;
     66         synchronized (mService.mWindowMap) {
     67             win = mService.windowForClientLocked(null, window, false);
     68             // win shouldn't be null here, pass it down to startPositioningLocked
     69             // to get warning if it's null.
     70             if (!startPositioningLocked(
     71                     win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
     72                 return false;
     73             }
     74         }
     75         try {
     76             mActivityManager.setFocusedTask(win.getTask().mTaskId);
     77         } catch(RemoteException e) {}
     78         return true;
     79     }
     80 
     81     void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
     82         mHandler.post(() -> {
     83             int taskId = -1;
     84             synchronized (mService.mWindowMap) {
     85                 final Task task = displayContent.findTaskForResizePoint(x, y);
     86                 if (task != null) {
     87                     if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
     88                             task.preserveOrientationOnResize(), x, y)) {
     89                         return;
     90                     }
     91                     taskId = task.mTaskId;
     92                 } else {
     93                     taskId = displayContent.taskIdFromPoint(x, y);
     94                 }
     95             }
     96             if (taskId >= 0) {
     97                 try {
     98                     mActivityManager.setFocusedTask(taskId);
     99                 } catch (RemoteException e) {
    100                 }
    101             }
    102         });
    103     }
    104 
    105     private boolean startPositioningLocked(WindowState win, boolean resize,
    106             boolean preserveOrientation, float startX, float startY) {
    107         if (DEBUG_TASK_POSITIONING)
    108             Slog.d(TAG_WM, "startPositioningLocked: "
    109                     + "win=" + win + ", resize=" + resize + ", preserveOrientation="
    110                     + preserveOrientation + ", {" + startX + ", " + startY + "}");
    111 
    112         if (win == null || win.getAppToken() == null) {
    113             Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
    114             return false;
    115         }
    116         if (win.mInputChannel == null) {
    117             Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
    118                     + " probably being removed");
    119             return false;
    120         }
    121 
    122         final DisplayContent displayContent = win.getDisplayContent();
    123         if (displayContent == null) {
    124             Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
    125             return false;
    126         }
    127 
    128         Display display = displayContent.getDisplay();
    129         mTaskPositioner = TaskPositioner.create(mService);
    130         mTaskPositioner.register(displayContent);
    131         mInputMonitor.updateInputWindowsLw(true /*force*/);
    132 
    133         // We need to grab the touch focus so that the touch events during the
    134         // resizing/scrolling are not sent to the app. 'win' is the main window
    135         // of the app, it may not have focus since there might be other windows
    136         // on top (eg. a dialog window).
    137         WindowState transferFocusFromWin = win;
    138         if (mService.mCurrentFocus != null && mService.mCurrentFocus != win
    139                 && mService.mCurrentFocus.mAppToken == win.mAppToken) {
    140             transferFocusFromWin = mService.mCurrentFocus;
    141         }
    142         if (!mInputManager.transferTouchFocus(
    143                 transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) {
    144             Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
    145             mTaskPositioner.unregister();
    146             mTaskPositioner = null;
    147             mInputMonitor.updateInputWindowsLw(true /*force*/);
    148             return false;
    149         }
    150 
    151         mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
    152         return true;
    153     }
    154 
    155     void finishTaskPositioning() {
    156         mHandler.post(() -> {
    157             if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning");
    158 
    159             synchronized (mService.mWindowMap) {
    160                 if (mTaskPositioner != null) {
    161                     mTaskPositioner.unregister();
    162                     mTaskPositioner = null;
    163                     mInputMonitor.updateInputWindowsLw(true /*force*/);
    164                 }
    165             }
    166         });
    167     }
    168 }
    169