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

Commit 952d3c1e authored by Stefan Kuhne's avatar Stefan Kuhne Committed by Android (Google) Code Review
Browse files

Merge "Adding move window functionality for free form desktop"

parents 571663bf 81c524a6
Loading
Loading
Loading
Loading
+75 −5
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.view.ViewGroup;
@@ -63,18 +64,31 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList
    private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
    // The height of a window which has not in DIP.
    private final int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;

    private PhoneWindow mOwner = null;
    boolean mWindowHasShadow = false;
    boolean mShowDecor = false;
    private boolean mWindowHasShadow = false;
    private boolean mShowDecor = false;

    // True if the window is being dragged.
    private boolean mDragging = false;

    // The bounds of the window and the absolute mouse pointer coordinates from before we started to
    // drag the window. They will be used to determine the next window position.
    private final Rect mWindowOriginalBounds = new Rect();
    private float mStartDragX;
    private float mStartDragY;
    // True when the left mouse button got released while dragging.
    private boolean mLeftMouseButtonReleased;

    // Avoiding re-creation of Rect's by keeping a temporary window drag bound.
    private final Rect mWindowDragBounds = new Rect();

    // The current focus state of the window for updating the window elevation.
    boolean mWindowHasFocus = true;
    private boolean mWindowHasFocus = true;

    // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
    // size calculation takes the shadow size into account. We set the elevation currently
    // to max until the first layout command has been executed.
    boolean mAllowUpdateElevation = false;
    private boolean mAllowUpdateElevation = false;

    public NonClientDecorView(Context context) {
        super(context);
@@ -103,6 +117,62 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList
        findViewById(R.id.close_window).setOnClickListener(this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        // Note: There are no mixed events. When a new device gets used (e.g. 1. Mouse, 2. touch)
        // the old input device events get cancelled first. So no need to remember the kind of
        // input device we are listening to.
        switch (e.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                // A drag action is started if we aren't dragging already and the starting event is
                // either a left mouse button or any other input device.
                if (!mDragging &&
                        (e.getToolType(e.getActionIndex()) != MotionEvent.TOOL_TYPE_MOUSE ||
                                (e.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0)) {
                    mDragging = true;
                    mWindowOriginalBounds.set(getActivityBounds());
                    mLeftMouseButtonReleased = false;
                    mStartDragX = e.getRawX();
                    mStartDragY = e.getRawY();
                }
                break;

            case MotionEvent.ACTION_MOVE:
                if (mDragging && !mLeftMouseButtonReleased) {
                    if (e.getToolType(e.getActionIndex()) == MotionEvent.TOOL_TYPE_MOUSE &&
                            (e.getButtonState() & MotionEvent.BUTTON_PRIMARY) == 0) {
                        // There is no separate mouse button up call and if the user mixes mouse
                        // button drag actions, we stop dragging once he releases the button.
                        mLeftMouseButtonReleased = true;
                        break;
                    }
                    mWindowDragBounds.set(mWindowOriginalBounds);
                    mWindowDragBounds.offset(Math.round(e.getRawX() - mStartDragX),
                            Math.round(e.getRawY() - mStartDragY));
                    setActivityBounds(mWindowDragBounds);
                }
                break;

            case MotionEvent.ACTION_UP:
                if (mDragging) {
                    // Since the window is already where it should be we don't have to do anything
                    // special at this time.
                    mDragging = false;
                    return true;
                }
                break;

            case MotionEvent.ACTION_CANCEL:
                if (mDragging) {
                    mDragging = false;
                    setActivityBounds(mWindowOriginalBounds);
                    return true;
                }
                break;
        }
        return mDragging;
    }

    /**
     * The phone window configuration has changed and the decor needs to be updated.
     * @param showDecor True if the decor should be shown.
+59 −16
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
@@ -38,6 +39,7 @@ import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.SystemClock;
import android.os.WorkSource;
import android.util.DisplayMetrics;
import android.util.TimeUtils;
import android.view.Display;
import android.view.IWindowFocusObserver;
@@ -78,6 +80,10 @@ class WindowList extends ArrayList<WindowState> {
final class WindowState implements WindowManagerPolicy.WindowState {
    static final String TAG = "WindowState";

    // The minimal size of a window within the usable area of the freeform stack.
    static final int MINIMUM_VISIBLE_WIDTH_IN_DP = 48;
    static final int MINIMUM_VISIBLE_HEIGHT_IN_DP = 32;

    final WindowManagerService mService;
    final WindowManagerPolicy mPolicy;
    final Context mContext;
@@ -536,6 +542,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
        mHaveFrame = true;

        final Task task = mAppToken != null ? getTask() : null;
        final boolean isFreeFormWorkspace = task != null && task.mStack != null &&
                task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
        final boolean nonFullscreenTask = task != null && !task.isFullscreen();
        if (nonFullscreenTask) {
            task.getBounds(mContainingFrame);
@@ -545,11 +553,21 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                // IME is up and obscuring this window. Adjust the window position so it is visible.
                mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
            }

            if (isFreeFormWorkspace) {
                // In free form mode we have only to set the rectangle if it wasn't set already. No
                // need to intersect it with the (visible) "content frame" since it is allowed to
                // be outside the visible desktop.
                if (mContainingFrame.isEmpty()) {
                    mContainingFrame.set(cf);
                }
            } else {
                // Make sure the containing frame is within the content frame so we don't layout
                // resized window under screen decorations.
                if (!mContainingFrame.intersect(cf)) {
                    mContainingFrame.set(cf);
                }
            }
            mDisplayFrame.set(mContainingFrame);
        } else {
            mContainingFrame.set(pf);
@@ -652,6 +670,23 @@ final class WindowState implements WindowManagerPolicy.WindowState {

        // Make sure the content and visible frames are inside of the
        // final window frame.
        if (isFreeFormWorkspace && !mFrame.isEmpty()) {
            // Keep the frame out of the blocked system area, limit it in size to the content area
            // and make sure that there is always a minimum visible so that the user can drag it
            // into a usable area..
            final int height = Math.min(mFrame.height(), mContentFrame.height());
            final int width = Math.min(mContentFrame.width(), mFrame.width());
            final int minVisibleHeight = calculatePixelFromDp(MINIMUM_VISIBLE_HEIGHT_IN_DP);
            final int minVisibleWidth = calculatePixelFromDp(MINIMUM_VISIBLE_WIDTH_IN_DP);
            final int top = Math.max(mContentFrame.top,
                    Math.min(mFrame.top, mContentFrame.bottom - minVisibleHeight));
            final int left = Math.max(mContentFrame.left + minVisibleWidth - width,
                    Math.min(mFrame.left, mContentFrame.right - minVisibleWidth));
            mFrame.set(left, top, left + width, top + height);
            mContentFrame.set(mFrame);
            mVisibleFrame.set(mContentFrame);
            mStableFrame.set(mContentFrame);
        } else {
            mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
                    Math.max(mContentFrame.top, mFrame.top),
                    Math.min(mContentFrame.right, mFrame.right),
@@ -666,6 +701,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                    Math.max(mStableFrame.top, mFrame.top),
                    Math.min(mStableFrame.right, mFrame.right),
                    Math.min(mStableFrame.bottom, mFrame.bottom));
        }

        mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0),
                Math.max(mOverscanFrame.top - mFrame.top, 0),
@@ -1577,6 +1613,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
        }
    }

    private int calculatePixelFromDp(int dp) {
        final Configuration serviceConfig = mService.mCurConfiguration;
        // TODO(multidisplay): Update Dp to that of display stack is on.
        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
        return (int)(dp * density);
    }

    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
        final TaskStack stack = getStack();
        pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());