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