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

Commit 5ec560a1 authored by Selim Cinek's avatar Selim Cinek
Browse files

Refactored clipping util to be used in core

We need the possibility to disable clipping
up a view hierarchy also in core, so I'm
moving it and refactoring it.

Test: expand, observe normal clipping
Bug: 63708826
Change-Id: I157395be8f2b7ac75afc0a3967cb0f2068a02fb6
parent e62255cc
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.internal.widget;

import android.util.ArraySet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import com.android.internal.R;

/**
 * A utility class that allows to clip views and their parents to allow for better transitions
 */
public class ViewClippingUtil {
    private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
    private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
    private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;

    public static void setClippingDeactivated(final View transformedView, boolean deactivated,
        ClippingParameters clippingParameters) {
        if (!deactivated && !clippingParameters.isClippingEnablingAllowed(transformedView)) {
            return;
        }
        if (!(transformedView.getParent() instanceof ViewGroup)) {
            return;
        }
        ViewGroup parent = (ViewGroup) transformedView.getParent();
        while (true) {
            if (!deactivated && !clippingParameters.isClippingEnablingAllowed(transformedView)) {
                return;
            }
            ArraySet<View> clipSet = (ArraySet<View>) parent.getTag(CLIP_CLIPPING_SET);
            if (clipSet == null) {
                clipSet = new ArraySet<>();
                parent.setTagInternal(CLIP_CLIPPING_SET, clipSet);
            }
            Boolean clipChildren = (Boolean) parent.getTag(CLIP_CHILDREN_TAG);
            if (clipChildren == null) {
                clipChildren = parent.getClipChildren();
                parent.setTagInternal(CLIP_CHILDREN_TAG, clipChildren);
            }
            Boolean clipToPadding = (Boolean) parent.getTag(CLIP_TO_PADDING);
            if (clipToPadding == null) {
                clipToPadding = parent.getClipToPadding();
                parent.setTagInternal(CLIP_TO_PADDING, clipToPadding);
            }
            if (!deactivated) {
                clipSet.remove(transformedView);
                if (clipSet.isEmpty()) {
                    parent.setClipChildren(clipChildren);
                    parent.setClipToPadding(clipToPadding);
                    parent.setTagInternal(CLIP_CLIPPING_SET, null);
                    clippingParameters.onClippingStateChanged(parent, true);
                }
            } else {
                clipSet.add(transformedView);
                parent.setClipChildren(false);
                parent.setClipToPadding(false);
                clippingParameters.onClippingStateChanged(parent, false);
            }
            if (clippingParameters.shouldFinish(parent)) {
                return;
            }
            final ViewParent viewParent = parent.getParent();
            if (viewParent instanceof ViewGroup) {
                parent = (ViewGroup) viewParent;
            } else {
                return;
            }
        }
    }

    public interface ClippingParameters {
        /**
         * Should we stop clipping at this view? If true is returned, {@param view} is the last view
         * where clipping is activated / deactivated.
         */
        boolean shouldFinish(View view);

        /**
         * Is it allowed to enable clipping on this view.
         */
        default boolean isClippingEnablingAllowed(View view) {
            return true;
        }

        /**
         * A method that is called whenever the view starts clipping again / stops clipping to the
         * children and padding.
         */
        default void onClippingStateChanged(View view, boolean isClipping) {};
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -139,6 +139,15 @@
  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_MOVE_WINDOW}. -->
  <item type="id" name="accessibilityActionMoveWindow" />

  <!-- A tag used to save the clip children in a tag -->
  <item type="id" name="clip_children_tag" />

  <!-- A tag used to save the set of deactivated children that clip -->
  <item type="id" name="clip_children_set_tag" />

  <!-- A tag used to save the clip to padding in a tag -->
  <item type="id" name="clip_to_padding_tag" />

  <!-- Action used to manually trigger an autofill request -->
  <item type="id" name="autofill" />

+3 −0
Original line number Diff line number Diff line
@@ -3111,6 +3111,9 @@
  <java-symbol type="id" name="message_name" />
  <java-symbol type="id" name="message_icon" />
  <java-symbol type="id" name="group_message_container" />
  <java-symbol type="id" name="clip_children_set_tag" />
  <java-symbol type="id" name="clip_to_padding_tag" />
  <java-symbol type="id" name="clip_children_tag" />
  <java-symbol type="drawable" name="ic_reply_notification_large" />
  <java-symbol type="dimen" name="messaging_avatar_size" />

+0 −3
Original line number Diff line number Diff line
@@ -66,9 +66,6 @@

    <!-- For notification icons for which targetSdk < L, this caches whether the icon is grayscale -->
    <item type="id" name="icon_is_grayscale" />
    <item type="id" name="clip_children_tag" />
    <item type="id" name="clip_children_set_tag" />
    <item type="id" name="clip_to_padding_tag" />
    <item type="id" name="image_icon_tag" />
    <item type="id" name="contains_transformed_view" />
    <item type="id" name="is_clicked_heads_up_tag" />
+26 −56
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -43,14 +44,34 @@ public class TransformState {
    public static final int TRANSFORM_ALL = TRANSFORM_X | TRANSFORM_Y;

    private static final float UNDEFINED = -1f;
    private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
    private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
    private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
    private static final int TRANSFORMATION_START_X = R.id.transformation_start_x_tag;
    private static final int TRANSFORMATION_START_Y = R.id.transformation_start_y_tag;
    private static final int TRANSFORMATION_START_SCLALE_X = R.id.transformation_start_scale_x_tag;
    private static final int TRANSFORMATION_START_SCLALE_Y = R.id.transformation_start_scale_y_tag;
    private static Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40);
    private static ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS
            = new ViewClippingUtil.ClippingParameters() {
        @Override
        public boolean shouldFinish(View view) {
            if (view instanceof ExpandableNotificationRow) {
                ExpandableNotificationRow row = (ExpandableNotificationRow) view;
                return !row.isChildInGroup();
            }
            return false;
        }

        @Override
        public void onClippingStateChanged(View view, boolean isClipping) {
            if (view instanceof ExpandableNotificationRow) {
                ExpandableNotificationRow row = (ExpandableNotificationRow) view;
                if (isClipping) {
                    row.setClipToActualHeight(true);
                } else if (row.isChildInGroup()) {
                    row.setClipToActualHeight(false);
                }
            }
        }
    };

    protected View mTransformedView;
    private int[] mOwnPosition = new int[2];
@@ -357,59 +378,8 @@ public class TransformState {
        }
    }

    public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
        if (!(transformedView.getParent() instanceof ViewGroup)) {
            return;
        }
        ViewGroup view = (ViewGroup) transformedView.getParent();
        while (true) {
            ArraySet<View> clipSet = (ArraySet<View>) view.getTag(CLIP_CLIPPING_SET);
            if (clipSet == null) {
                clipSet = new ArraySet<>();
                view.setTag(CLIP_CLIPPING_SET, clipSet);
            }
            Boolean clipChildren = (Boolean) view.getTag(CLIP_CHILDREN_TAG);
            if (clipChildren == null) {
                clipChildren = view.getClipChildren();
                view.setTag(CLIP_CHILDREN_TAG, clipChildren);
            }
            Boolean clipToPadding = (Boolean) view.getTag(CLIP_TO_PADDING);
            if (clipToPadding == null) {
                clipToPadding = view.getClipToPadding();
                view.setTag(CLIP_TO_PADDING, clipToPadding);
            }
            ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
                    ? (ExpandableNotificationRow) view
                    : null;
            if (!deactivated) {
                clipSet.remove(transformedView);
                if (clipSet.isEmpty()) {
                    view.setClipChildren(clipChildren);
                    view.setClipToPadding(clipToPadding);
                    view.setTag(CLIP_CLIPPING_SET, null);
                    if (row != null) {
                        row.setClipToActualHeight(true);
                    }
                }
            } else {
                clipSet.add(transformedView);
                view.setClipChildren(false);
                view.setClipToPadding(false);
                if (row != null && row.isChildInGroup()) {
                    // We still want to clip to the parent's height
                    row.setClipToActualHeight(false);
                }
            }
            if (row != null && !row.isChildInGroup()) {
                return;
            }
            final ViewParent parent = view.getParent();
            if (parent instanceof ViewGroup) {
                view = (ViewGroup) parent;
            } else {
                return;
            }
        }
    protected void setClippingDeactivated(final View transformedView, boolean deactivated) {
        ViewClippingUtil.setClippingDeactivated(transformedView, deactivated, CLIPPING_PARAMETERS);
    }

    public int[] getLaidOutLocationOnScreen() {