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
This commit is contained in:
Selim Cinek
2017-10-27 15:32:30 -07:00
parent e62255ccc5
commit 5ec560a12a
5 changed files with 146 additions and 59 deletions

View File

@@ -0,0 +1,108 @@
/*
* 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) {};
}
}

View File

@@ -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" />

View File

@@ -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" />

View File

@@ -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" />

View File

@@ -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() {