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

Commit 992b1937 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add ViewTreeObserverWrapper"

parents d8b6ec5f 97fb595e
Loading
Loading
Loading
Loading
+172 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.systemui.shared.system;

import android.annotation.Nullable;
import android.graphics.Rect;
import android.graphics.Region;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;

import java.util.HashMap;

public class ViewTreeObserverWrapper {

    private static final HashMap<OnComputeInsetsListener, OnComputeInternalInsetsListener>
            sOnComputeInsetsListenerMap = new HashMap<>();

    /**
     * Register a callback to be invoked when the invoked when it is time to
     * compute the window's insets.
     *
     * @param listener The callback to add
     * @throws IllegalStateException If {@link ViewTreeObserver#isAlive()} returns false
     */
    public static void addOnComputeInsetsListener(
            ViewTreeObserver observer, OnComputeInsetsListener listener) {
        final OnComputeInternalInsetsListener internalListener = internalInOutInfo -> {
            final InsetsInfo inOutInfo = new InsetsInfo();
            inOutInfo.contentInsets.set(internalInOutInfo.contentInsets);
            inOutInfo.visibleInsets.set(internalInOutInfo.visibleInsets);
            inOutInfo.touchableRegion.set(internalInOutInfo.touchableRegion);
            listener.onComputeInsets(inOutInfo);
            internalInOutInfo.contentInsets.set(inOutInfo.contentInsets);
            internalInOutInfo.visibleInsets.set(inOutInfo.visibleInsets);
            internalInOutInfo.touchableRegion.set(inOutInfo.touchableRegion);
            internalInOutInfo.setTouchableInsets(inOutInfo.mTouchableInsets);
        };
        sOnComputeInsetsListenerMap.put(listener, internalListener);
        observer.addOnComputeInternalInsetsListener(internalListener);
    }

    /**
     * Remove a previously installed insets computation callback
     *
     * @param victim The callback to remove
     * @throws IllegalStateException If {@link ViewTreeObserver#isAlive()} returns false
     * @see #addOnComputeInsetsListener(ViewTreeObserver, OnComputeInsetsListener)
     */
    public void removeOnComputeInsetsListener(
            ViewTreeObserver observer, OnComputeInsetsListener victim) {
        final OnComputeInternalInsetsListener listener = sOnComputeInsetsListenerMap.get(victim);
        if (listener != null) {
            observer.removeOnComputeInternalInsetsListener(listener);
        }
    }

    /**
     * Interface definition for a callback to be invoked when layout has
     * completed and the client can compute its interior insets.
     */
    public interface OnComputeInsetsListener {
        /**
         * Callback method to be invoked when layout has completed and the
         * client can compute its interior insets.
         *
         * @param inoutInfo Should be filled in by the implementation with
         * the information about the insets of the window.  This is called
         * with whatever values the previous OnComputeInsetsListener
         * returned, if there are multiple such listeners in the window.
         */
        void onComputeInsets(InsetsInfo inoutInfo);
    }

    /**
     * Parameters used with OnComputeInsetsListener.
     */
    public final static class InsetsInfo {

        /**
         * Offsets from the frame of the window at which the content of
         * windows behind it should be placed.
         */
        public final Rect contentInsets = new Rect();

        /**
         * Offsets from the frame of the window at which windows behind it
         * are visible.
         */
        public final Rect visibleInsets = new Rect();

        /**
         * Touchable region defined relative to the origin of the frame of the window.
         * Only used when {@link #setTouchableInsets(int)} is called with
         * the option {@link #TOUCHABLE_INSETS_REGION}.
         */
        public final Region touchableRegion = new Region();

        /**
         * Option for {@link #setTouchableInsets(int)}: the entire window frame
         * can be touched.
         */
        public static final int TOUCHABLE_INSETS_FRAME =
                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;

        /**
         * Option for {@link #setTouchableInsets(int)}: the area inside of
         * the content insets can be touched.
         */
        public static final int TOUCHABLE_INSETS_CONTENT =
                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;

        /**
         * Option for {@link #setTouchableInsets(int)}: the area inside of
         * the visible insets can be touched.
         */
        public static final int TOUCHABLE_INSETS_VISIBLE =
                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;

        /**
         * Option for {@link #setTouchableInsets(int)}: the area inside of
         * the provided touchable region in {@link #touchableRegion} can be touched.
         */
        public static final int TOUCHABLE_INSETS_REGION =
                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;

        /**
         * Set which parts of the window can be touched: either
         * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
         * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
         */
        public void setTouchableInsets(int val) {
            mTouchableInsets = val;
        }

        int mTouchableInsets;

        @Override
        public int hashCode() {
            int result = contentInsets.hashCode();
            result = 31 * result + visibleInsets.hashCode();
            result = 31 * result + touchableRegion.hashCode();
            result = 31 * result + mTouchableInsets;
            return result;
        }

        @Override
        public boolean equals(@Nullable Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            final InsetsInfo other = (InsetsInfo) o;
            return mTouchableInsets == other.mTouchableInsets &&
                    contentInsets.equals(other.contentInsets) &&
                    visibleInsets.equals(other.visibleInsets) &&
                    touchableRegion.equals(other.touchableRegion);
        }
    }
}