blob: f38fec0bb9cb6e331b950f9db6fc7d05d56fb917 [file] [log] [blame]
/*
* 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 it's 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 it's 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;
}
}