diff --git a/core/java/com/android/internal/widget/ViewClippingUtil.java b/core/java/com/android/internal/widget/ViewClippingUtil.java new file mode 100644 index 0000000000000..efa11adf9b654 --- /dev/null +++ b/core/java/com/android/internal/widget/ViewClippingUtil.java @@ -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 clipSet = (ArraySet) 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) {}; + } +} diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index cd3624db9afaf..870868c355570 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -139,6 +139,15 @@ + + + + + + + + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index abca5e561ec62..a7ad81c38b958 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3111,6 +3111,9 @@ + + + diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index e5f802944ff34..cfd95b41825a6 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -66,9 +66,6 @@ - - - diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java index 2439c707647e2..cb59b39a2ff22 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java @@ -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 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 clipSet = (ArraySet) 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() {