| /* |
| * Copyright (C) 2014 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 android.support.v4.view; |
| |
| import android.annotation.TargetApi; |
| import android.content.res.ColorStateList; |
| import android.graphics.PorterDuff; |
| import android.graphics.Rect; |
| import android.graphics.drawable.Drawable; |
| import android.os.Build; |
| import android.support.annotation.RequiresApi; |
| import android.view.View; |
| import android.view.ViewParent; |
| import android.view.WindowInsets; |
| |
| @RequiresApi(21) |
| @TargetApi(21) |
| class ViewCompatLollipop { |
| |
| public interface OnApplyWindowInsetsListenerBridge { |
| Object onApplyWindowInsets(View v, Object insets); |
| } |
| |
| private static ThreadLocal<Rect> sThreadLocalRect; |
| |
| public static void setTransitionName(View view, String transitionName) { |
| view.setTransitionName(transitionName); |
| } |
| |
| public static String getTransitionName(View view) { |
| return view.getTransitionName(); |
| } |
| |
| public static void requestApplyInsets(View view) { |
| view.requestApplyInsets(); |
| } |
| |
| public static void setElevation(View view, float elevation) { |
| view.setElevation(elevation); |
| } |
| |
| public static float getElevation(View view) { |
| return view.getElevation(); |
| } |
| |
| public static void setTranslationZ(View view, float translationZ) { |
| view.setTranslationZ(translationZ); |
| } |
| |
| public static float getTranslationZ(View view) { |
| return view.getTranslationZ(); |
| } |
| |
| public static void setOnApplyWindowInsetsListener( |
| View view, final OnApplyWindowInsetsListenerBridge bridge) { |
| if (bridge == null) { |
| view.setOnApplyWindowInsetsListener(null); |
| } else { |
| view.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { |
| @Override |
| public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) { |
| return (WindowInsets) bridge.onApplyWindowInsets(view, insets); |
| } |
| }); |
| } |
| } |
| |
| public static boolean isImportantForAccessibility(View view) { |
| return view.isImportantForAccessibility(); |
| } |
| |
| static ColorStateList getBackgroundTintList(View view) { |
| return view.getBackgroundTintList(); |
| } |
| |
| static void setBackgroundTintList(View view, ColorStateList tintList) { |
| view.setBackgroundTintList(tintList); |
| |
| if (Build.VERSION.SDK_INT == 21) { |
| // Work around a bug in L that did not update the state of the background |
| // after applying the tint |
| Drawable background = view.getBackground(); |
| boolean hasTint = (view.getBackgroundTintList() != null) |
| && (view.getBackgroundTintMode() != null); |
| if ((background != null) && hasTint) { |
| if (background.isStateful()) { |
| background.setState(view.getDrawableState()); |
| } |
| view.setBackground(background); |
| } |
| } |
| } |
| |
| static PorterDuff.Mode getBackgroundTintMode(View view) { |
| return view.getBackgroundTintMode(); |
| } |
| |
| static void setBackgroundTintMode(View view, PorterDuff.Mode mode) { |
| view.setBackgroundTintMode(mode); |
| |
| if (Build.VERSION.SDK_INT == 21) { |
| // Work around a bug in L that did not update the state of the background |
| // after applying the tint |
| Drawable background = view.getBackground(); |
| boolean hasTint = (view.getBackgroundTintList() != null) |
| && (view.getBackgroundTintMode() != null); |
| if ((background != null) && hasTint) { |
| if (background.isStateful()) { |
| background.setState(view.getDrawableState()); |
| } |
| view.setBackground(background); |
| } |
| } |
| } |
| |
| public static Object onApplyWindowInsets(View v, Object insets) { |
| WindowInsets unwrapped = (WindowInsets) insets; |
| WindowInsets result = v.onApplyWindowInsets(unwrapped); |
| if (result != unwrapped) { |
| insets = new WindowInsets(result); |
| } |
| return insets; |
| } |
| |
| public static Object dispatchApplyWindowInsets(View v, Object insets) { |
| WindowInsets unwrapped = (WindowInsets) insets; |
| WindowInsets result = v.dispatchApplyWindowInsets(unwrapped); |
| if (result != unwrapped) { |
| insets = new WindowInsets(result); |
| } |
| return insets; |
| } |
| |
| public static void setNestedScrollingEnabled(View view, boolean enabled) { |
| view.setNestedScrollingEnabled(enabled); |
| } |
| |
| public static boolean isNestedScrollingEnabled(View view) { |
| return view.isNestedScrollingEnabled(); |
| } |
| |
| public static boolean startNestedScroll(View view, int axes) { |
| return view.startNestedScroll(axes); |
| } |
| |
| public static void stopNestedScroll(View view) { |
| view.stopNestedScroll(); |
| } |
| |
| public static boolean hasNestedScrollingParent(View view) { |
| return view.hasNestedScrollingParent(); |
| } |
| |
| public static boolean dispatchNestedScroll(View view, int dxConsumed, int dyConsumed, |
| int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { |
| return view.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, |
| offsetInWindow); |
| } |
| |
| public static boolean dispatchNestedPreScroll(View view, int dx, int dy, int[] consumed, |
| int[] offsetInWindow) { |
| return view.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow); |
| } |
| |
| public static boolean dispatchNestedFling(View view, float velocityX, float velocityY, |
| boolean consumed) { |
| return view.dispatchNestedFling(velocityX, velocityY, consumed); |
| } |
| |
| public static boolean dispatchNestedPreFling(View view, float velocityX, float velocityY) { |
| return view.dispatchNestedPreFling(velocityX, velocityY); |
| } |
| |
| public static float getZ(View view) { |
| return view.getZ(); |
| } |
| |
| public static void setZ(View view, float z) { |
| view.setZ(z); |
| } |
| |
| static void offsetTopAndBottom(final View view, final int offset) { |
| final Rect parentRect = getEmptyTempRect(); |
| boolean needInvalidateWorkaround = false; |
| |
| final ViewParent parent = view.getParent(); |
| if (parent instanceof View) { |
| final View p = (View) parent; |
| parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom()); |
| // If the view currently does not currently intersect the parent (and is therefore |
| // not displayed) we may need need to invalidate |
| needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(), |
| view.getRight(), view.getBottom()); |
| } |
| |
| // Now offset, invoking the API 11+ implementation (which contains its own workarounds) |
| ViewCompatHC.offsetTopAndBottom(view, offset); |
| |
| // The view has now been offset, so let's intersect the Rect and invalidate where |
| // the View is now displayed |
| if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(), |
| view.getRight(), view.getBottom())) { |
| ((View) parent).invalidate(parentRect); |
| } |
| } |
| |
| static void offsetLeftAndRight(final View view, final int offset) { |
| final Rect parentRect = getEmptyTempRect(); |
| boolean needInvalidateWorkaround = false; |
| |
| final ViewParent parent = view.getParent(); |
| if (parent instanceof View) { |
| final View p = (View) parent; |
| parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom()); |
| // If the view currently does not currently intersect the parent (and is therefore |
| // not displayed) we may need need to invalidate |
| needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(), |
| view.getRight(), view.getBottom()); |
| } |
| |
| // Now offset, invoking the API 11+ implementation (which contains its own workarounds) |
| ViewCompatHC.offsetLeftAndRight(view, offset); |
| |
| // The view has now been offset, so let's intersect the Rect and invalidate where |
| // the View is now displayed |
| if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(), |
| view.getRight(), view.getBottom())) { |
| ((View) parent).invalidate(parentRect); |
| } |
| } |
| |
| private static Rect getEmptyTempRect() { |
| if (sThreadLocalRect == null) { |
| sThreadLocalRect = new ThreadLocal<>(); |
| } |
| Rect rect = sThreadLocalRect.get(); |
| if (rect == null) { |
| rect = new Rect(); |
| sThreadLocalRect.set(rect); |
| } |
| rect.setEmpty(); |
| return rect; |
| } |
| } |