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

Commit b6030954 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

A brave new world for window insets (2 and 3/n)

Implements basic API's to control windows generating insets in
the new insets world.

Test: CTS tests will be added at some point in the future
Bug: 118118435
Change-Id: I722d2e58c68734ac131b12da3d9978e946292130
parent 4bcd414e
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.DisplayCutout;
import android.view.InsetsState;
import android.view.InsetsSourceControl;

import com.android.internal.os.IResultReceiver;
import android.util.MergedConfiguration;
@@ -60,6 +61,11 @@ oneway interface IWindow {
     */
    void insetsChanged(in InsetsState insetsState);

    /**
     * Called when this window retrieved control over a specified set of inset sources.
     */
    void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);

    void moved(int newX, int newY);
    void dispatchAppVisibility(boolean visible);
    void dispatchGetNewSurface();
+69 −1
Original line number Diff line number Diff line
@@ -16,17 +16,30 @@

package android.view;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.util.ArraySet;
import android.util.SparseArray;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type.InsetType;
import android.view.InsetsState.InternalInsetType;

import com.android.internal.annotations.VisibleForTesting;

import java.io.PrintWriter;

/**
 * Implements {@link WindowInsetsController} on the client.
 * @hide
 */
class InsetsController {
public class InsetsController implements WindowInsetsController {

    private final InsetsState mState = new InsetsState();
    private final Rect mFrame = new Rect();
    private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();

    private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();

    void onFrameChanged(Rect frame) {
        mFrame.set(frame);
@@ -48,6 +61,61 @@ class InsetsController {
        return mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout);
    }

    /**
     * Called when the server has dispatched us a new set of inset controls.
     */
    public void onControlsChanged(InsetsSourceControl[] activeControls) {
        if (activeControls != null) {
            for (InsetsSourceControl activeControl : activeControls) {
                mTmpControlArray.put(activeControl.getType(), activeControl);
            }
        }

        // Ensure to update all existing source consumers
        for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
            final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
            final InsetsSourceControl control = mTmpControlArray.get(consumer.getType());

            // control may be null, but we still need to update the control to null if it got
            // revoked.
            consumer.setControl(control);
        }

        // Ensure to create source consumers if not available yet.
        for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
            final InsetsSourceControl control = mTmpControlArray.valueAt(i);
            getSourceConsumer(control.getType()).setControl(control);
        }
        mTmpControlArray.clear();
    }

    @Override
    public void show(@InsetType int types) {
        final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
        for (int i = internalTypes.size() - 1; i >= 0; i--) {
            getSourceConsumer(internalTypes.valueAt(i)).show();
        }
    }

    @Override
    public void hide(@InsetType int types) {
        final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
        for (int i = internalTypes.size() - 1; i >= 0; i--) {
            getSourceConsumer(internalTypes.valueAt(i)).hide();
        }
    }

    @VisibleForTesting
    public @NonNull InsetsSourceConsumer getSourceConsumer(@InternalInsetType int type) {
        InsetsSourceConsumer controller = mSourceConsumers.get(type);
        if (controller != null) {
            return controller;
        }
        controller = new InsetsSourceConsumer(type, mState, Transaction::new);
        mSourceConsumers.put(type, controller);
        return controller;
    }

    void dump(String prefix, PrintWriter pw) {
        pw.println(prefix); pw.println("InsetsController:");
        mState.dump(prefix + "  ", pw);
+95 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package android.view;

import android.annotation.Nullable;
import android.view.SurfaceControl.Transaction;
import android.view.InsetsState.InternalInsetType;

import com.android.internal.annotations.VisibleForTesting;

import java.util.function.Supplier;

/**
 * Controls the visibility and animations of a single window insets source.
 * @hide
 */
public class InsetsSourceConsumer {

    private final Supplier<Transaction> mTransactionSupplier;
    private final @InternalInsetType int mType;
    private final InsetsState mState;
    private @Nullable InsetsSourceControl mControl;
    private boolean mHidden;

    public InsetsSourceConsumer(@InternalInsetType int type, InsetsState state,
            Supplier<Transaction> transactionSupplier) {
        mType = type;
        mState = state;
        mTransactionSupplier = transactionSupplier;
    }

    public void setControl(@Nullable InsetsSourceControl control) {
        if (mControl == control) {
            return;
        }
        mControl = control;
        applyHiddenToControl();
    }

    @VisibleForTesting
    public InsetsSourceControl getControl() {
        return mControl;
    }

    int getType() {
        return mType;
    }

    @VisibleForTesting
    public void show() {
        setHidden(false);
    }

    @VisibleForTesting
    public void hide() {
        setHidden(true);
    }

    private void setHidden(boolean hidden) {
        if (mHidden == hidden) {
            return;
        }
        mHidden = hidden;
        applyHiddenToControl();
    }

    private void applyHiddenToControl() {
        if (mControl == null) {
            return;
        }

        // TODO: Animation
        final Transaction t = mTransactionSupplier.get();
        if (mHidden) {
            t.hide(mControl.getLeash());
        } else {
            t.show(mControl.getLeash());
        }
        t.apply();
    }
}
+19 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 2018, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

parcelable InsetsSourceControl;
+72 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.graphics.Point;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.InsetsState.InternalInsetType;

/**
 * Represents a parcelable object to allow controlling a single {@link InsetsSource}.
 * @hide
 */
public class InsetsSourceControl implements Parcelable {

    private final @InternalInsetType int mType;
    private final SurfaceControl mLeash;

    public InsetsSourceControl(@InternalInsetType int type, SurfaceControl leash) {
        mType = type;
        mLeash = leash;
    }

    public int getType() {
        return mType;
    }

    public SurfaceControl getLeash() {
        return mLeash;
    }

    public InsetsSourceControl(Parcel in) {
        mType = in.readInt();
        mLeash = in.readParcelable(null /* loader */);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mType);
        dest.writeParcelable(mLeash, 0 /* flags*/);
    }

    public static final Creator<InsetsSourceControl> CREATOR
            = new Creator<InsetsSourceControl>() {
        public InsetsSourceControl createFromParcel(Parcel in) {
            return new InsetsSourceControl(in);
        }

        public InsetsSourceControl[] newArray(int size) {
            return new InsetsSourceControl[size];
        }
    };
}
Loading