15ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek/*
25ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * Copyright (C) 2017 The Android Open Source Project
35ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek *
45ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * Licensed under the Apache License, Version 2.0 (the "License");
55ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * you may not use this file except in compliance with the License.
65ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * You may obtain a copy of the License at
75ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek *
85ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek *      http://www.apache.org/licenses/LICENSE-2.0
95ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek *
105ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * Unless required by applicable law or agreed to in writing, software
115ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * distributed under the License is distributed on an "AS IS" BASIS,
125ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * See the License for the specific language governing permissions and
145ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * limitations under the License
155ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek */
165ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek
175ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinekpackage com.android.internal.widget;
185ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek
195ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinekimport android.util.ArraySet;
205ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinekimport android.view.View;
215ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinekimport android.view.ViewGroup;
225ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinekimport android.view.ViewParent;
235ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek
245ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinekimport com.android.internal.R;
255ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek
265ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek/**
275ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek * A utility class that allows to clip views and their parents to allow for better transitions
285ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek */
295ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinekpublic class ViewClippingUtil {
305ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek    private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
315ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek    private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
325ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek    private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
335ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek
345ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek    public static void setClippingDeactivated(final View transformedView, boolean deactivated,
355ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        ClippingParameters clippingParameters) {
365ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        if (!deactivated && !clippingParameters.isClippingEnablingAllowed(transformedView)) {
375ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            return;
385ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        }
395ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        if (!(transformedView.getParent() instanceof ViewGroup)) {
405ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            return;
415ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        }
425ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        ViewGroup parent = (ViewGroup) transformedView.getParent();
435ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        while (true) {
445ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            if (!deactivated && !clippingParameters.isClippingEnablingAllowed(transformedView)) {
455ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                return;
465ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            }
475ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            ArraySet<View> clipSet = (ArraySet<View>) parent.getTag(CLIP_CLIPPING_SET);
485ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            if (clipSet == null) {
495ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                clipSet = new ArraySet<>();
505ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                parent.setTagInternal(CLIP_CLIPPING_SET, clipSet);
515ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            }
525ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            Boolean clipChildren = (Boolean) parent.getTag(CLIP_CHILDREN_TAG);
535ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            if (clipChildren == null) {
545ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                clipChildren = parent.getClipChildren();
555ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                parent.setTagInternal(CLIP_CHILDREN_TAG, clipChildren);
565ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            }
575ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            Boolean clipToPadding = (Boolean) parent.getTag(CLIP_TO_PADDING);
585ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            if (clipToPadding == null) {
595ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                clipToPadding = parent.getClipToPadding();
605ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                parent.setTagInternal(CLIP_TO_PADDING, clipToPadding);
615ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            }
625ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            if (!deactivated) {
635ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                clipSet.remove(transformedView);
645ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                if (clipSet.isEmpty()) {
655ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                    parent.setClipChildren(clipChildren);
665ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                    parent.setClipToPadding(clipToPadding);
675ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                    parent.setTagInternal(CLIP_CLIPPING_SET, null);
685ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                    clippingParameters.onClippingStateChanged(parent, true);
695ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                }
705ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            } else {
715ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                clipSet.add(transformedView);
725ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                parent.setClipChildren(false);
735ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                parent.setClipToPadding(false);
745ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                clippingParameters.onClippingStateChanged(parent, false);
755ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            }
765ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            if (clippingParameters.shouldFinish(parent)) {
775ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                return;
785ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            }
795ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            final ViewParent viewParent = parent.getParent();
805ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            if (viewParent instanceof ViewGroup) {
815ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                parent = (ViewGroup) viewParent;
825ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            } else {
835ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek                return;
845ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek            }
855ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        }
865ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek    }
875ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek
885ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek    public interface ClippingParameters {
895ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        /**
905ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek         * Should we stop clipping at this view? If true is returned, {@param view} is the last view
915ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek         * where clipping is activated / deactivated.
925ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek         */
935ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        boolean shouldFinish(View view);
945ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek
955ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        /**
965ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek         * Is it allowed to enable clipping on this view.
975ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek         */
985ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        default boolean isClippingEnablingAllowed(View view) {
99d3809996af29764776fe069406f85756e53c7eacSelim Cinek            return !MessagingPropertyAnimator.isAnimatingTranslation(view);
1005ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        }
1015ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek
1025ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        /**
1035ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek         * A method that is called whenever the view starts clipping again / stops clipping to the
1045ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek         * children and padding.
1055ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek         */
1065ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek        default void onClippingStateChanged(View view, boolean isClipping) {};
1075ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek    }
1085ec560a12acd6f2df67ad3ac8090809a4501bcceSelim Cinek}
109