Merge "Fix issue with loading state, add tests for it" into pi-preview1-androidx-dev
diff --git a/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
index 53e6154..10c2566 100644
--- a/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
@@ -45,6 +45,6 @@
// Nullaway
"-XepIgnoreUnknownCheckNames", // https://github.com/uber/NullAway/issues/25
"-Xep:NullAway:ERROR",
- "-XepOpt:NullAway:AnnotatedPackages=android.arch,android.support"
+ "-XepOpt:NullAway:AnnotatedPackages=android.arch,android.support,androidx"
)
}
diff --git a/compat/src/main/java/androidx/core/view/ViewCompat.java b/compat/src/main/java/androidx/core/view/ViewCompat.java
index ca61b74..bde4f9a 100644
--- a/compat/src/main/java/androidx/core/view/ViewCompat.java
+++ b/compat/src/main/java/androidx/core/view/ViewCompat.java
@@ -19,6 +19,7 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.Context;
@@ -49,6 +50,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.Px;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
@@ -439,25 +441,24 @@
*/
public static final int SCROLL_INDICATOR_END = 0x20;
+ private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
+
+ private static Field sMinWidthField;
+ private static boolean sMinWidthFieldFetched;
+ private static Field sMinHeightField;
+ private static boolean sMinHeightFieldFetched;
+
+ private static Method sDispatchStartTemporaryDetach;
+ private static Method sDispatchFinishTemporaryDetach;
+ private static boolean sTempDetachBound;
+
static class ViewCompatBaseImpl {
- private static Field sMinWidthField;
- private static boolean sMinWidthFieldFetched;
- private static Field sMinHeightField;
- private static boolean sMinHeightFieldFetched;
private static WeakHashMap<View, String> sTransitionNameMap;
- private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
- private Method mDispatchStartTemporaryDetach;
- private Method mDispatchFinishTemporaryDetach;
- private boolean mTempDetachBound;
WeakHashMap<View, ViewPropertyAnimatorCompat> mViewPropertyAnimatorCompatMap = null;
private static Method sChildrenDrawingOrderMethod;
static Field sAccessibilityDelegateField;
static boolean sAccessibilityDelegateCheckFailed = false;
- public void setAutofillHints(@NonNull View v, @Nullable String... autofillHints) {
- // no-op
- }
-
public void setAccessibilityDelegate(View v,
@Nullable AccessibilityDelegateCompat delegate) {
v.setAccessibilityDelegate(delegate == null ? null : delegate.getBridge());
@@ -489,209 +490,10 @@
v.onInitializeAccessibilityNodeInfo(info.unwrap());
}
- @SuppressWarnings("deprecation")
- public boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
- Object localState, int flags) {
- return v.startDrag(data, shadowBuilder, localState, flags);
- }
-
- public void cancelDragAndDrop(View v) {
- // no-op
- }
-
- public void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder) {
- // no-op
- }
-
- public boolean hasTransientState(View view) {
- // A view can't have transient state if transient state wasn't supported.
- return false;
- }
-
- public void setHasTransientState(View view, boolean hasTransientState) {
- // Do nothing; API doesn't exist
- }
-
- public void postInvalidateOnAnimation(View view) {
- view.postInvalidate();
- }
-
- public void postInvalidateOnAnimation(View view, int left, int top, int right, int bottom) {
- view.postInvalidate(left, top, right, bottom);
- }
-
- public void postOnAnimation(View view, Runnable action) {
- view.postDelayed(action, getFrameTime());
- }
-
- public void postOnAnimationDelayed(View view, Runnable action, long delayMillis) {
- view.postDelayed(action, getFrameTime() + delayMillis);
- }
-
- long getFrameTime() {
- return ValueAnimator.getFrameDelay();
- }
-
- public int getImportantForAccessibility(View view) {
- return 0;
- }
-
- public void setImportantForAccessibility(View view, int mode) {
- }
-
public boolean isImportantForAccessibility(View view) {
return true;
}
- public boolean performAccessibilityAction(View view, int action, Bundle arguments) {
- return false;
- }
-
- public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View view) {
- return null;
- }
-
- public int getLabelFor(View view) {
- return 0;
- }
-
- public void setLabelFor(View view, int id) {
- }
-
- public void setLayerPaint(View view, Paint paint) {
- // Make sure the paint is correct; this will be cheap if it's the same
- // instance as was used to call setLayerType earlier.
- view.setLayerType(view.getLayerType(), paint);
- // This is expensive, but the only way to accomplish this before JB-MR1.
- view.invalidate();
- }
-
- public int getLayoutDirection(View view) {
- return LAYOUT_DIRECTION_LTR;
- }
-
- public void setLayoutDirection(View view, int layoutDirection) {
- // No-op
- }
-
- public ViewParent getParentForAccessibility(View view) {
- return view.getParent();
- }
-
- public int getAccessibilityLiveRegion(View view) {
- return ACCESSIBILITY_LIVE_REGION_NONE;
- }
-
- public void setAccessibilityLiveRegion(View view, int mode) {
- // No-op
- }
-
- public int getPaddingStart(View view) {
- return view.getPaddingLeft();
- }
-
- public int getPaddingEnd(View view) {
- return view.getPaddingRight();
- }
-
- public void setPaddingRelative(View view, int start, int top, int end, int bottom) {
- view.setPadding(start, top, end, bottom);
- }
-
- public void dispatchStartTemporaryDetach(View view) {
- if (!mTempDetachBound) {
- bindTempDetach();
- }
- if (mDispatchStartTemporaryDetach != null) {
- try {
- mDispatchStartTemporaryDetach.invoke(view);
- } catch (Exception e) {
- Log.d(TAG, "Error calling dispatchStartTemporaryDetach", e);
- }
- } else {
- // Try this instead
- view.onStartTemporaryDetach();
- }
- }
-
- public void dispatchFinishTemporaryDetach(View view) {
- if (!mTempDetachBound) {
- bindTempDetach();
- }
- if (mDispatchFinishTemporaryDetach != null) {
- try {
- mDispatchFinishTemporaryDetach.invoke(view);
- } catch (Exception e) {
- Log.d(TAG, "Error calling dispatchFinishTemporaryDetach", e);
- }
- } else {
- // Try this instead
- view.onFinishTemporaryDetach();
- }
- }
-
- public boolean hasOverlappingRendering(View view) {
- return true;
- }
-
- private void bindTempDetach() {
- try {
- mDispatchStartTemporaryDetach = View.class.getDeclaredMethod(
- "dispatchStartTemporaryDetach");
- mDispatchFinishTemporaryDetach = View.class.getDeclaredMethod(
- "dispatchFinishTemporaryDetach");
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "Couldn't find method", e);
- }
- mTempDetachBound = true;
- }
-
- public int getMinimumWidth(View view) {
- if (!sMinWidthFieldFetched) {
- try {
- sMinWidthField = View.class.getDeclaredField("mMinWidth");
- sMinWidthField.setAccessible(true);
- } catch (NoSuchFieldException e) {
- // Couldn't find the field. Abort!
- }
- sMinWidthFieldFetched = true;
- }
-
- if (sMinWidthField != null) {
- try {
- return (int) sMinWidthField.get(view);
- } catch (Exception e) {
- // Field get failed. Oh well...
- }
- }
-
- // We failed, return 0
- return 0;
- }
-
- public int getMinimumHeight(View view) {
- if (!sMinHeightFieldFetched) {
- try {
- sMinHeightField = View.class.getDeclaredField("mMinHeight");
- sMinHeightField.setAccessible(true);
- } catch (NoSuchFieldException e) {
- // Couldn't find the field. Abort!
- }
- sMinHeightFieldFetched = true;
- }
-
- if (sMinHeightField != null) {
- try {
- return (int) sMinHeightField.get(view);
- } catch (Exception e) {
- // Field get failed. Oh well...
- }
- }
-
- // We failed, return 0
- return 0;
- }
-
public ViewPropertyAnimatorCompat animate(View view) {
if (mViewPropertyAnimatorCompatMap == null) {
mViewPropertyAnimatorCompatMap = new WeakHashMap<>();
@@ -718,13 +520,6 @@
return sTransitionNameMap.get(view);
}
- public int getWindowSystemUiVisibility(View view) {
- return 0;
- }
-
- public void requestApplyInsets(View view) {
- }
-
public void setElevation(View view, float elevation) {
}
@@ -739,13 +534,6 @@
return 0f;
}
- public void setClipBounds(View view, Rect clipBounds) {
- }
-
- public Rect getClipBounds(View view) {
- return null;
- }
-
public void setChildrenDrawingOrderEnabled(ViewGroup viewGroup, boolean enabled) {
if (sChildrenDrawingOrderMethod == null) {
try {
@@ -767,10 +555,6 @@
}
}
- public boolean getFitsSystemWindows(View view) {
- return false;
- }
-
public void setOnApplyWindowInsetsListener(View view,
OnApplyWindowInsetsListener listener) {
// noop
@@ -784,10 +568,6 @@
return insets;
}
- public boolean isPaddingRelative(View view) {
- return false;
- }
-
public void setNestedScrollingEnabled(View view, boolean enabled) {
if (view instanceof NestedScrollingChild) {
((NestedScrollingChild) view).setNestedScrollingEnabled(enabled);
@@ -801,10 +581,6 @@
return false;
}
- public void setBackground(View view, Drawable background) {
- view.setBackgroundDrawable(background);
- }
-
public ColorStateList getBackgroundTintList(View view) {
return (view instanceof TintableBackgroundView)
? ((TintableBackgroundView) view).getSupportBackgroundTintList()
@@ -883,18 +659,6 @@
return false;
}
- public boolean isInLayout(View view) {
- return false;
- }
-
- public boolean isLaidOut(View view) {
- return view.getWidth() > 0 && view.getHeight() > 0;
- }
-
- public boolean isLayoutDirectionResolved(View view) {
- return false;
- }
-
public float getZ(View view) {
return getTranslationZ(view) + getElevation(view);
}
@@ -903,14 +667,6 @@
// no-op
}
- public boolean isAttachedToWindow(View view) {
- return view.getWindowToken() != null;
- }
-
- public boolean hasOnClickListeners(View view) {
- return false;
- }
-
public int getScrollIndicators(View view) {
return 0;
}
@@ -952,310 +708,10 @@
view.setTranslationY(y + 1);
view.setTranslationY(y);
}
-
- public void setPointerIcon(View view, PointerIconCompat pointerIcon) {
- // no-op
- }
-
- public Display getDisplay(View view) {
- if (isAttachedToWindow(view)) {
- final WindowManager wm = (WindowManager) view.getContext().getSystemService(
- Context.WINDOW_SERVICE);
- return wm.getDefaultDisplay();
- }
- return null;
- }
-
- public void setTooltipText(View view, CharSequence tooltipText) {
- }
-
- public int getNextClusterForwardId(@NonNull View view) {
- return View.NO_ID;
- }
-
- public void setNextClusterForwardId(@NonNull View view, int nextClusterForwardId) {
- // no-op
- }
-
- public boolean isKeyboardNavigationCluster(@NonNull View view) {
- return false;
- }
-
- public void setKeyboardNavigationCluster(@NonNull View view, boolean isCluster) {
- // no-op
- }
-
- public boolean isFocusedByDefault(@NonNull View view) {
- return false;
- }
-
- public void setFocusedByDefault(@NonNull View view, boolean isFocusedByDefault) {
- // no-op
- }
-
- public View keyboardNavigationClusterSearch(@NonNull View view, View currentCluster,
- @FocusDirection int direction) {
- return null;
- }
-
- public void addKeyboardNavigationClusters(@NonNull View view,
- @NonNull Collection<View> views, int direction) {
- // no-op
- }
-
- public boolean restoreDefaultFocus(@NonNull View view) {
- return view.requestFocus();
- }
-
- public boolean hasExplicitFocusable(@NonNull View view) {
- return view.hasFocusable();
- }
-
- @TargetApi(Build.VERSION_CODES.O)
- public @AutofillImportance int getImportantForAutofill(@NonNull View v) {
- return View.IMPORTANT_FOR_AUTOFILL_AUTO;
- }
-
- public void setImportantForAutofill(@NonNull View v, @AutofillImportance int mode) {
- // no-op
- }
-
- public boolean isImportantForAutofill(@NonNull View v) {
- return true;
- }
-
- /**
- * {@link ViewCompat#generateViewId()}
- */
- public int generateViewId() {
- for (;;) {
- final int result = sNextGeneratedId.get();
- // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
- int newValue = result + 1;
- if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
- if (sNextGeneratedId.compareAndSet(result, newValue)) {
- return result;
- }
- }
- }
- }
-
- @RequiresApi(15)
- static class ViewCompatApi15Impl extends ViewCompatBaseImpl {
- @Override
- public boolean hasOnClickListeners(View view) {
- return view.hasOnClickListeners();
- }
- }
-
- @RequiresApi(16)
- static class ViewCompatApi16Impl extends ViewCompatApi15Impl {
- @Override
- public boolean hasTransientState(View view) {
- return view.hasTransientState();
- }
- @Override
- public void setHasTransientState(View view, boolean hasTransientState) {
- view.setHasTransientState(hasTransientState);
- }
- @Override
- public void postInvalidateOnAnimation(View view) {
- view.postInvalidateOnAnimation();
- }
- @Override
- public void postInvalidateOnAnimation(View view, int left, int top, int right, int bottom) {
- view.postInvalidateOnAnimation(left, top, right, bottom);
- }
- @Override
- public void postOnAnimation(View view, Runnable action) {
- view.postOnAnimation(action);
- }
- @Override
- public void postOnAnimationDelayed(View view, Runnable action, long delayMillis) {
- view.postOnAnimationDelayed(action, delayMillis);
- }
- @Override
- public int getImportantForAccessibility(View view) {
- return view.getImportantForAccessibility();
- }
- @Override
- public void setImportantForAccessibility(View view, int mode) {
- // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS is not available
- // on this platform so replace with IMPORTANT_FOR_ACCESSIBILITY_NO
- // which is closer semantically.
- if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
- mode = IMPORTANT_FOR_ACCESSIBILITY_NO;
- }
- //noinspection WrongConstant
- view.setImportantForAccessibility(mode);
- }
- @Override
- public boolean performAccessibilityAction(View view, int action, Bundle arguments) {
- return view.performAccessibilityAction(action, arguments);
- }
- @Override
- public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View view) {
- AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
- if (provider != null) {
- return new AccessibilityNodeProviderCompat(provider);
- }
- return null;
- }
-
- @Override
- public ViewParent getParentForAccessibility(View view) {
- return view.getParentForAccessibility();
- }
-
- @Override
- public int getMinimumWidth(View view) {
- return view.getMinimumWidth();
- }
-
- @Override
- public int getMinimumHeight(View view) {
- return view.getMinimumHeight();
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public void requestApplyInsets(View view) {
- view.requestFitSystemWindows();
- }
-
- @Override
- public boolean getFitsSystemWindows(View view) {
- return view.getFitsSystemWindows();
- }
-
- @Override
- public boolean hasOverlappingRendering(View view) {
- return view.hasOverlappingRendering();
- }
-
- @Override
- public void setBackground(View view, Drawable background) {
- view.setBackground(background);
- }
- }
-
- @RequiresApi(17)
- static class ViewCompatApi17Impl extends ViewCompatApi16Impl {
-
- @Override
- public int getLabelFor(View view) {
- return view.getLabelFor();
- }
-
- @Override
- public void setLabelFor(View view, int id) {
- view.setLabelFor(id);
- }
-
- @Override
- public void setLayerPaint(View view, Paint paint) {
- view.setLayerPaint(paint);
- }
-
- @Override
- public int getLayoutDirection(View view) {
- return view.getLayoutDirection();
- }
-
- @Override
- public void setLayoutDirection(View view, int layoutDirection) {
- view.setLayoutDirection(layoutDirection);
- }
-
- @Override
- public int getPaddingStart(View view) {
- return view.getPaddingStart();
- }
-
- @Override
- public int getPaddingEnd(View view) {
- return view.getPaddingEnd();
- }
-
- @Override
- public void setPaddingRelative(View view, int start, int top, int end, int bottom) {
- view.setPaddingRelative(start, top, end, bottom);
- }
-
- @Override
- public int getWindowSystemUiVisibility(View view) {
- return view.getWindowSystemUiVisibility();
- }
-
- @Override
- public boolean isPaddingRelative(View view) {
- return view.isPaddingRelative();
- }
-
- @Override
- public Display getDisplay(View view) {
- return view.getDisplay();
- }
-
- @Override
- public int generateViewId() {
- return View.generateViewId();
- }
- }
-
- @RequiresApi(18)
- static class ViewCompatApi18Impl extends ViewCompatApi17Impl {
- @Override
- public void setClipBounds(View view, Rect clipBounds) {
- view.setClipBounds(clipBounds);
- }
-
- @Override
- public Rect getClipBounds(View view) {
- return view.getClipBounds();
- }
-
- @Override
- public boolean isInLayout(View view) {
- return view.isInLayout();
- }
- }
-
- @RequiresApi(19)
- static class ViewCompatApi19Impl extends ViewCompatApi18Impl {
- @Override
- public int getAccessibilityLiveRegion(View view) {
- return view.getAccessibilityLiveRegion();
- }
-
- @Override
- public void setAccessibilityLiveRegion(View view, int mode) {
- view.setAccessibilityLiveRegion(mode);
- }
-
- @Override
- public void setImportantForAccessibility(View view, int mode) {
- view.setImportantForAccessibility(mode);
- }
-
- @Override
- public boolean isLaidOut(View view) {
- return view.isLaidOut();
- }
-
- @Override
- public boolean isLayoutDirectionResolved(View view) {
- return view.isLayoutDirectionResolved();
- }
-
- @Override
- public boolean isAttachedToWindow(View view) {
- return view.isAttachedToWindow();
- }
}
@RequiresApi(21)
- static class ViewCompatApi21Impl extends ViewCompatApi19Impl {
+ static class ViewCompatApi21Impl extends ViewCompatBaseImpl {
private static ThreadLocal<Rect> sThreadLocalRect;
@Override
@@ -1269,11 +725,6 @@
}
@Override
- public void requestApplyInsets(View view) {
- view.requestApplyInsets();
- }
-
- @Override
public void setElevation(View view, float elevation) {
view.setElevation(elevation);
}
@@ -1538,142 +989,12 @@
}
}
- @RequiresApi(24)
- static class ViewCompatApi24Impl extends ViewCompatApi23Impl {
- @Override
- public void dispatchStartTemporaryDetach(View view) {
- view.dispatchStartTemporaryDetach();
- }
-
- @Override
- public void dispatchFinishTemporaryDetach(View view) {
- view.dispatchFinishTemporaryDetach();
- }
-
- @Override
- public void setPointerIcon(View view, PointerIconCompat pointerIconCompat) {
- view.setPointerIcon((PointerIcon) (pointerIconCompat != null
- ? pointerIconCompat.getPointerIcon() : null));
- }
-
- @Override
- public boolean startDragAndDrop(View view, ClipData data,
- View.DragShadowBuilder shadowBuilder, Object localState, int flags) {
- return view.startDragAndDrop(data, shadowBuilder, localState, flags);
- }
-
- @Override
- public void cancelDragAndDrop(View view) {
- view.cancelDragAndDrop();
- }
-
- @Override
- public void updateDragShadow(View view, View.DragShadowBuilder shadowBuilder) {
- view.updateDragShadow(shadowBuilder);
- }
- }
-
- @RequiresApi(26)
- static class ViewCompatApi26Impl extends ViewCompatApi24Impl {
-
- @Override
- public void setAutofillHints(@NonNull View v, @Nullable String... autofillHints) {
- v.setAutofillHints(autofillHints);
- }
-
- @Override
- public @AutofillImportance int getImportantForAutofill(@NonNull View v) {
- return v.getImportantForAutofill();
- }
-
- @Override
- public void setImportantForAutofill(@NonNull View v, @AutofillImportance int mode) {
- v.setImportantForAutofill(mode);
- }
-
- @Override
- public boolean isImportantForAutofill(@NonNull View v) {
- return v.isImportantForAutofill();
- }
-
- @Override
- public void setTooltipText(View view, CharSequence tooltipText) {
- view.setTooltipText(tooltipText);
- }
-
- @Override
- public int getNextClusterForwardId(@NonNull View view) {
- return view.getNextClusterForwardId();
- }
-
- @Override
- public void setNextClusterForwardId(@NonNull View view, int nextClusterForwardId) {
- view.setNextClusterForwardId(nextClusterForwardId);
- }
-
- @Override
- public boolean isKeyboardNavigationCluster(@NonNull View view) {
- return view.isKeyboardNavigationCluster();
- }
-
- @Override
- public void setKeyboardNavigationCluster(@NonNull View view, boolean isCluster) {
- view.setKeyboardNavigationCluster(isCluster);
- }
-
- @Override
- public boolean isFocusedByDefault(@NonNull View view) {
- return view.isFocusedByDefault();
- }
-
- @Override
- public void setFocusedByDefault(@NonNull View view, boolean isFocusedByDefault) {
- view.setFocusedByDefault(isFocusedByDefault);
- }
-
- @Override
- public View keyboardNavigationClusterSearch(@NonNull View view, View currentCluster,
- @FocusDirection int direction) {
- return view.keyboardNavigationClusterSearch(currentCluster, direction);
- }
-
- @Override
- public void addKeyboardNavigationClusters(@NonNull View view,
- @NonNull Collection<View> views, int direction) {
- view.addKeyboardNavigationClusters(views, direction);
- }
-
- @Override
- public boolean restoreDefaultFocus(@NonNull View view) {
- return view.restoreDefaultFocus();
- }
-
- @Override
- public boolean hasExplicitFocusable(@NonNull View view) {
- return view.hasExplicitFocusable();
- }
- }
-
static final ViewCompatBaseImpl IMPL;
static {
- if (Build.VERSION.SDK_INT >= 26) {
- IMPL = new ViewCompatApi26Impl();
- } else if (Build.VERSION.SDK_INT >= 24) {
- IMPL = new ViewCompatApi24Impl();
- } else if (Build.VERSION.SDK_INT >= 23) {
+ if (Build.VERSION.SDK_INT >= 23) {
IMPL = new ViewCompatApi23Impl();
} else if (Build.VERSION.SDK_INT >= 21) {
IMPL = new ViewCompatApi21Impl();
- } else if (Build.VERSION.SDK_INT >= 19) {
- IMPL = new ViewCompatApi19Impl();
- } else if (Build.VERSION.SDK_INT >= 18) {
- IMPL = new ViewCompatApi18Impl();
- } else if (Build.VERSION.SDK_INT >= 17) {
- IMPL = new ViewCompatApi17Impl();
- } else if (Build.VERSION.SDK_INT >= 16) {
- IMPL = new ViewCompatApi16Impl();
- } else if (Build.VERSION.SDK_INT >= 15) {
- IMPL = new ViewCompatApi15Impl();
} else {
IMPL = new ViewCompatBaseImpl();
}
@@ -1842,7 +1163,8 @@
* @param v The View against which to invoke the method.
* @param info The instance to initialize.
*/
- public static void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info) {
+ public static void onInitializeAccessibilityNodeInfo(@NonNull View v,
+ AccessibilityNodeInfoCompat info) {
IMPL.onInitializeAccessibilityNodeInfo(v, info);
}
@@ -1867,7 +1189,8 @@
* delegated
* @see AccessibilityDelegateCompat
*/
- public static void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate) {
+ public static void setAccessibilityDelegate(@NonNull View v,
+ AccessibilityDelegateCompat delegate) {
IMPL.setAccessibilityDelegate(v, delegate);
}
@@ -1901,7 +1224,9 @@
* @attr ref android.R.styleable#View_autofillHints
*/
public static void setAutofillHints(@NonNull View v, @Nullable String... autofillHints) {
- IMPL.setAutofillHints(v, autofillHints);
+ if (Build.VERSION.SDK_INT >= 26) {
+ v.setAutofillHints(autofillHints);
+ }
}
/**
@@ -1918,8 +1243,12 @@
*
* @attr ref android.R.styleable#View_importantForAutofill
*/
+ @SuppressLint("InlinedApi")
public static @AutofillImportance int getImportantForAutofill(@NonNull View v) {
- return IMPL.getImportantForAutofill(v);
+ if (Build.VERSION.SDK_INT >= 26) {
+ return v.getImportantForAutofill();
+ }
+ return View.IMPORTANT_FOR_AUTOFILL_AUTO;
}
/**
@@ -1960,7 +1289,9 @@
* @attr ref android.R.styleable#View_importantForAutofill
*/
public static void setImportantForAutofill(@NonNull View v, @AutofillImportance int mode) {
- IMPL.setImportantForAutofill(v, mode);
+ if (Build.VERSION.SDK_INT >= 26) {
+ v.setImportantForAutofill(mode);
+ }
}
/**
@@ -2027,7 +1358,10 @@
* @see android.view.autofill.AutofillManager#requestAutofill(View)
*/
public static boolean isImportantForAutofill(@NonNull View v) {
- return IMPL.isImportantForAutofill(v);
+ if (Build.VERSION.SDK_INT >= 26) {
+ return v.isImportantForAutofill();
+ }
+ return true;
}
/**
@@ -2036,7 +1370,7 @@
* @param v The View instance to check
* @return True if the View has an accessibility delegate
*/
- public static boolean hasAccessibilityDelegate(View v) {
+ public static boolean hasAccessibilityDelegate(@NonNull View v) {
return IMPL.hasAccessibilityDelegate(v);
}
@@ -2048,8 +1382,11 @@
* @param view View to check for transient state
* @return true if the view has transient state
*/
- public static boolean hasTransientState(View view) {
- return IMPL.hasTransientState(view);
+ public static boolean hasTransientState(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return view.hasTransientState();
+ }
+ return false;
}
/**
@@ -2059,8 +1396,10 @@
* @param view View tracking transient state
* @param hasTransientState true if this view has transient state
*/
- public static void setHasTransientState(View view, boolean hasTransientState) {
- IMPL.setHasTransientState(view, hasTransientState);
+ public static void setHasTransientState(@NonNull View view, boolean hasTransientState) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ view.setHasTransientState(hasTransientState);
+ }
}
/**
@@ -2072,8 +1411,12 @@
*
* @param view View to invalidate
*/
- public static void postInvalidateOnAnimation(View view) {
- IMPL.postInvalidateOnAnimation(view);
+ public static void postInvalidateOnAnimation(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ view.postInvalidateOnAnimation();
+ } else {
+ view.postInvalidate();
+ }
}
/**
@@ -2089,9 +1432,13 @@
* @param right The right coordinate of the rectangle to invalidate.
* @param bottom The bottom coordinate of the rectangle to invalidate.
*/
- public static void postInvalidateOnAnimation(View view, int left, int top,
+ public static void postInvalidateOnAnimation(@NonNull View view, int left, int top,
int right, int bottom) {
- IMPL.postInvalidateOnAnimation(view, left, top, right, bottom);
+ if (Build.VERSION.SDK_INT >= 16) {
+ view.postInvalidateOnAnimation(left, top, right, bottom);
+ } else {
+ view.postInvalidate(left, top, right, bottom);
+ }
}
/**
@@ -2104,8 +1451,12 @@
* @param view View to post this Runnable to
* @param action The Runnable that will be executed.
*/
- public static void postOnAnimation(View view, Runnable action) {
- IMPL.postOnAnimation(view, action);
+ public static void postOnAnimation(@NonNull View view, Runnable action) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ view.postOnAnimation(action);
+ } else {
+ view.postDelayed(action, ValueAnimator.getFrameDelay());
+ }
}
/**
@@ -2121,8 +1472,13 @@
* @param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*/
- public static void postOnAnimationDelayed(View view, Runnable action, long delayMillis) {
- IMPL.postOnAnimationDelayed(view, action, delayMillis);
+ public static void postOnAnimationDelayed(@NonNull View view, Runnable action,
+ long delayMillis) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ view.postOnAnimationDelayed(action, delayMillis);
+ } else {
+ view.postDelayed(action, ValueAnimator.getFrameDelay() + delayMillis);
+ }
}
/**
@@ -2139,9 +1495,11 @@
* @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
*/
@ImportantForAccessibility
- public static int getImportantForAccessibility(View view) {
- //noinspection ResourceType
- return IMPL.getImportantForAccessibility(view);
+ public static int getImportantForAccessibility(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return view.getImportantForAccessibility();
+ }
+ return 0;
}
/**
@@ -2163,9 +1521,20 @@
* @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
* @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
*/
- public static void setImportantForAccessibility(View view,
+ public static void setImportantForAccessibility(@NonNull View view,
@ImportantForAccessibility int mode) {
- IMPL.setImportantForAccessibility(view, mode);
+ if (Build.VERSION.SDK_INT >= 19) {
+ view.setImportantForAccessibility(mode);
+ } else if (Build.VERSION.SDK_INT >= 16) {
+ // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS is not available
+ // on this platform so replace with IMPORTANT_FOR_ACCESSIBILITY_NO
+ // which is closer semantically.
+ if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
+ mode = IMPORTANT_FOR_ACCESSIBILITY_NO;
+ }
+ //noinspection WrongConstant
+ view.setImportantForAccessibility(mode);
+ }
}
/**
@@ -2204,7 +1573,7 @@
* @see #setImportantForAccessibility(View, int)
* @see #getImportantForAccessibility(View)
*/
- public static boolean isImportantForAccessibility(View view) {
+ public static boolean isImportantForAccessibility(@NonNull View view) {
return IMPL.isImportantForAccessibility(view);
}
@@ -2222,8 +1591,12 @@
* @param arguments Optional action arguments.
* @return Whether the action was performed.
*/
- public static boolean performAccessibilityAction(View view, int action, Bundle arguments) {
- return IMPL.performAccessibilityAction(view, action, arguments);
+ public static boolean performAccessibilityAction(@NonNull View view, int action,
+ Bundle arguments) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return view.performAccessibilityAction(action, arguments);
+ }
+ return false;
}
/**
@@ -2249,8 +1622,14 @@
*
* @see AccessibilityNodeProviderCompat
*/
- public static AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View view) {
- return IMPL.getAccessibilityNodeProvider(view);
+ public static AccessibilityNodeProviderCompat getAccessibilityNodeProvider(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+ if (provider != null) {
+ return new AccessibilityNodeProviderCompat(provider);
+ }
+ }
+ return null;
}
/**
@@ -2338,8 +1717,11 @@
* @param view The view on which to invoke the corresponding method.
* @return The labeled view id.
*/
- public static int getLabelFor(View view) {
- return IMPL.getLabelFor(view);
+ public static int getLabelFor(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ return view.getLabelFor();
+ }
+ return 0;
}
/**
@@ -2349,8 +1731,10 @@
* @param view The view on which to invoke the corresponding method.
* @param labeledId The labeled view id.
*/
- public static void setLabelFor(View view, @IdRes int labeledId) {
- IMPL.setLabelFor(view, labeledId);
+ public static void setLabelFor(@NonNull View view, @IdRes int labeledId) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ view.setLabelFor(labeledId);
+ }
}
/**
@@ -2383,8 +1767,16 @@
*
* @see #setLayerType(View, int, android.graphics.Paint)
*/
- public static void setLayerPaint(View view, Paint paint) {
- IMPL.setLayerPaint(view, paint);
+ public static void setLayerPaint(@NonNull View view, Paint paint) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ view.setLayerPaint(paint);
+ } else {
+ // Make sure the paint is correct; this will be cheap if it's the same
+ // instance as was used to call setLayerType earlier.
+ view.setLayerType(view.getLayerType(), paint);
+ // This is expensive, but the only way to accomplish this before JB-MR1.
+ view.invalidate();
+ }
}
/**
@@ -2398,9 +1790,11 @@
* is lower than Jellybean MR1 (API 17)
*/
@ResolvedLayoutDirectionMode
- public static int getLayoutDirection(View view) {
- //noinspection ResourceType
- return IMPL.getLayoutDirection(view);
+ public static int getLayoutDirection(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ return view.getLayoutDirection();
+ }
+ return LAYOUT_DIRECTION_LTR;
}
/**
@@ -2419,8 +1813,11 @@
* proceeds up the parent chain of the view to get the value. If there is no parent, then it
* will return the default {@link #LAYOUT_DIRECTION_LTR}.
*/
- public static void setLayoutDirection(View view, @LayoutDirectionMode int layoutDirection) {
- IMPL.setLayoutDirection(view, layoutDirection);
+ public static void setLayoutDirection(@NonNull View view,
+ @LayoutDirectionMode int layoutDirection) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ view.setLayoutDirection(layoutDirection);
+ }
}
/**
@@ -2431,8 +1828,11 @@
* @param view View to retrieve parent for
* @return The parent for use in accessibility inspection
*/
- public static ViewParent getParentForAccessibility(View view) {
- return IMPL.getParentForAccessibility(view);
+ public static ViewParent getParentForAccessibility(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return view.getParentForAccessibility();
+ }
+ return view.getParent();
}
/**
@@ -2564,9 +1964,11 @@
* @see ViewCompat#setAccessibilityLiveRegion(View, int)
*/
@AccessibilityLiveRegion
- public static int getAccessibilityLiveRegion(View view) {
- //noinspection ResourceType
- return IMPL.getAccessibilityLiveRegion(view);
+ public static int getAccessibilityLiveRegion(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 19) {
+ return view.getAccessibilityLiveRegion();
+ }
+ return ACCESSIBILITY_LIVE_REGION_NONE;
}
/**
@@ -2597,8 +1999,11 @@
* <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}
* </ul>
*/
- public static void setAccessibilityLiveRegion(View view, @AccessibilityLiveRegion int mode) {
- IMPL.setAccessibilityLiveRegion(view, mode);
+ public static void setAccessibilityLiveRegion(@NonNull View view,
+ @AccessibilityLiveRegion int mode) {
+ if (Build.VERSION.SDK_INT >= 19) {
+ view.setAccessibilityLiveRegion(mode);
+ }
}
/**
@@ -2609,8 +2014,12 @@
* @param view The view to get padding for
* @return the start padding in pixels
*/
- public static int getPaddingStart(View view) {
- return IMPL.getPaddingStart(view);
+ @Px
+ public static int getPaddingStart(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ return view.getPaddingStart();
+ }
+ return view.getPaddingLeft();
}
/**
@@ -2621,8 +2030,12 @@
* @param view The view to get padding for
* @return the end padding in pixels
*/
- public static int getPaddingEnd(View view) {
- return IMPL.getPaddingEnd(view);
+ @Px
+ public static int getPaddingEnd(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ return view.getPaddingEnd();
+ }
+ return view.getPaddingRight();
}
/**
@@ -2638,22 +2051,71 @@
* @param end the end padding in pixels
* @param bottom the bottom padding in pixels
*/
- public static void setPaddingRelative(View view, int start, int top, int end, int bottom) {
- IMPL.setPaddingRelative(view, start, top, end, bottom);
+ public static void setPaddingRelative(@NonNull View view, @Px int start, @Px int top,
+ @Px int end, @Px int bottom) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ view.setPaddingRelative(start, top, end, bottom);
+ } else {
+ view.setPadding(start, top, end, bottom);
+ }
+ }
+
+ private static void bindTempDetach() {
+ try {
+ sDispatchStartTemporaryDetach = View.class.getDeclaredMethod(
+ "dispatchStartTemporaryDetach");
+ sDispatchFinishTemporaryDetach = View.class.getDeclaredMethod(
+ "dispatchFinishTemporaryDetach");
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Couldn't find method", e);
+ }
+ sTempDetachBound = true;
}
/**
* Notify a view that it is being temporarily detached.
*/
- public static void dispatchStartTemporaryDetach(View view) {
- IMPL.dispatchStartTemporaryDetach(view);
+ public static void dispatchStartTemporaryDetach(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 24) {
+ view.dispatchStartTemporaryDetach();
+ } else {
+ if (!sTempDetachBound) {
+ bindTempDetach();
+ }
+ if (sDispatchStartTemporaryDetach != null) {
+ try {
+ sDispatchStartTemporaryDetach.invoke(view);
+ } catch (Exception e) {
+ Log.d(TAG, "Error calling dispatchStartTemporaryDetach", e);
+ }
+ } else {
+ // Try this instead
+ view.onStartTemporaryDetach();
+ }
+ }
}
/**
* Notify a view that its temporary detach has ended; the view is now reattached.
*/
- public static void dispatchFinishTemporaryDetach(View view) {
- IMPL.dispatchFinishTemporaryDetach(view);
+ public static void dispatchFinishTemporaryDetach(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 24) {
+ view.dispatchFinishTemporaryDetach();
+ } else {
+ if (!sTempDetachBound) {
+ bindTempDetach();
+ }
+ if (sDispatchFinishTemporaryDetach != null) {
+ try {
+ sDispatchFinishTemporaryDetach.invoke(view);
+ } catch (Exception e) {
+ Log.d(TAG, "Error calling dispatchFinishTemporaryDetach", e);
+ }
+ } else {
+ // Try this instead
+ view.onFinishTemporaryDetach();
+ }
+ }
}
/**
@@ -2713,8 +2175,31 @@
*
* @return the minimum width the view will try to be.
*/
- public static int getMinimumWidth(View view) {
- return IMPL.getMinimumWidth(view);
+ public static int getMinimumWidth(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return view.getMinimumWidth();
+ }
+
+ if (!sMinWidthFieldFetched) {
+ try {
+ sMinWidthField = View.class.getDeclaredField("mMinWidth");
+ sMinWidthField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ // Couldn't find the field. Abort!
+ }
+ sMinWidthFieldFetched = true;
+ }
+
+ if (sMinWidthField != null) {
+ try {
+ return (int) sMinWidthField.get(view);
+ } catch (Exception e) {
+ // Field get failed. Oh well...
+ }
+ }
+
+ // We failed, return 0
+ return 0;
}
/**
@@ -2724,8 +2209,31 @@
*
* @return the minimum height the view will try to be.
*/
- public static int getMinimumHeight(View view) {
- return IMPL.getMinimumHeight(view);
+ public static int getMinimumHeight(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return view.getMinimumHeight();
+ }
+
+ if (!sMinHeightFieldFetched) {
+ try {
+ sMinHeightField = View.class.getDeclaredField("mMinHeight");
+ sMinHeightField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ // Couldn't find the field. Abort!
+ }
+ sMinHeightFieldFetched = true;
+ }
+
+ if (sMinHeightField != null) {
+ try {
+ return (int) sMinHeightField.get(view);
+ } catch (Exception e) {
+ // Field get failed. Oh well...
+ }
+ }
+
+ // We failed, return 0
+ return 0;
}
/**
@@ -2734,7 +2242,8 @@
*
* @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
*/
- public static ViewPropertyAnimatorCompat animate(View view) {
+ @NonNull
+ public static ViewPropertyAnimatorCompat animate(@NonNull View view) {
return IMPL.animate(view);
}
@@ -2999,7 +2508,7 @@
/**
* Sets the base elevation of this view, in pixels.
*/
- public static void setElevation(View view, float elevation) {
+ public static void setElevation(@NonNull View view, float elevation) {
IMPL.setElevation(view, elevation);
}
@@ -3008,14 +2517,14 @@
*
* @return The base depth position of the view, in pixels.
*/
- public static float getElevation(View view) {
+ public static float getElevation(@NonNull View view) {
return IMPL.getElevation(view);
}
/**
* Sets the depth location of this view relative to its {@link #getElevation(View) elevation}.
*/
- public static void setTranslationZ(View view, float translationZ) {
+ public static void setTranslationZ(@NonNull View view, float translationZ) {
IMPL.setTranslationZ(view, translationZ);
}
@@ -3024,7 +2533,7 @@
*
* @return The depth of this view relative to its elevation.
*/
- public static float getTranslationZ(View view) {
+ public static float getTranslationZ(@NonNull View view) {
return IMPL.getTranslationZ(view);
}
@@ -3035,7 +2544,7 @@
* @param view The View against which to invoke the method.
* @param transitionName The name of the View to uniquely identify it for Transitions.
*/
- public static void setTransitionName(View view, String transitionName) {
+ public static void setTransitionName(@NonNull View view, String transitionName) {
IMPL.setTransitionName(view, transitionName);
}
@@ -3049,23 +2558,31 @@
* @return The name used of the View to be used to identify Views in Transitions or null
* if no name has been given.
*/
- public static String getTransitionName(View view) {
+ @Nullable
+ public static String getTransitionName(@NonNull View view) {
return IMPL.getTransitionName(view);
}
/**
* Returns the current system UI visibility that is currently set for the entire window.
*/
- public static int getWindowSystemUiVisibility(View view) {
- return IMPL.getWindowSystemUiVisibility(view);
+ public static int getWindowSystemUiVisibility(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return view.getWindowSystemUiVisibility();
+ }
+ return 0;
}
/**
* Ask that a new dispatch of {@code View.onApplyWindowInsets(WindowInsets)} be performed. This
* falls back to {@code View.requestFitSystemWindows()} where available.
*/
- public static void requestApplyInsets(View view) {
- IMPL.requestApplyInsets(view);
+ public static void requestApplyInsets(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 20) {
+ view.requestApplyInsets();
+ } else if (Build.VERSION.SDK_INT >= 16) {
+ view.requestFitSystemWindows();
+ }
}
/**
@@ -3088,8 +2605,11 @@
* Returns true if this view should adapt to fit system window insets. This method will always
* return false before API 16 (Jellybean).
*/
- public static boolean getFitsSystemWindows(View v) {
- return IMPL.getFitsSystemWindows(v);
+ public static boolean getFitsSystemWindows(@NonNull View v) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return v.getFitsSystemWindows();
+ }
+ return false;
}
/**
@@ -3123,7 +2643,7 @@
* Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
* window insets to this view. This will only take effect on devices with API 21 or above.
*/
- public static void setOnApplyWindowInsetsListener(View v,
+ public static void setOnApplyWindowInsetsListener(@NonNull View v,
OnApplyWindowInsetsListener listener) {
IMPL.setOnApplyWindowInsetsListener(v, listener);
}
@@ -3140,7 +2660,8 @@
* @param insets Insets to apply
* @return The supplied insets with any applied insets consumed
*/
- public static WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
+ public static WindowInsetsCompat onApplyWindowInsets(@NonNull View view,
+ WindowInsetsCompat insets) {
return IMPL.onApplyWindowInsets(view, insets);
}
@@ -3156,7 +2677,7 @@
* @param insets Insets to apply
* @return The provided insets minus the insets that were consumed
*/
- public static WindowInsetsCompat dispatchApplyWindowInsets(View view,
+ public static WindowInsetsCompat dispatchApplyWindowInsets(@NonNull View view,
WindowInsetsCompat insets) {
return IMPL.dispatchApplyWindowInsets(view, insets);
}
@@ -3205,8 +2726,11 @@
*
* @return true if the content in this view might overlap, false otherwise.
*/
- public static boolean hasOverlappingRendering(View view) {
- return IMPL.hasOverlappingRendering(view);
+ public static boolean hasOverlappingRendering(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ return view.hasOverlappingRendering();
+ }
+ return true;
}
/**
@@ -3215,8 +2739,11 @@
*
* @return true if the padding is relative or false if it is not.
*/
- public static boolean isPaddingRelative(View view) {
- return IMPL.isPaddingRelative(view);
+ public static boolean isPaddingRelative(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ return view.isPaddingRelative();
+ }
+ return false;
}
/**
@@ -3225,8 +2752,12 @@
* when a background is removed, this View's padding isn't touched. If setting the padding is
* desired, please use{@code setPadding(int, int, int, int)}.
*/
- public static void setBackground(View view, Drawable background) {
- IMPL.setBackground(view, background);
+ public static void setBackground(@NonNull View view, @Nullable Drawable background) {
+ if (Build.VERSION.SDK_INT >= 16) {
+ view.setBackground(background);
+ } else {
+ view.setBackgroundDrawable(background);
+ }
}
/**
@@ -3235,7 +2766,7 @@
* Only returns meaningful info when running on API v21 or newer, or if {@code view}
* implements the {@code TintableBackgroundView} interface.
*/
- public static ColorStateList getBackgroundTintList(View view) {
+ public static ColorStateList getBackgroundTintList(@NonNull View view) {
return IMPL.getBackgroundTintList(view);
}
@@ -3246,7 +2777,7 @@
* previous to API v21, it will only take effect if {@code view} implements the
* {@code TintableBackgroundView} interface.
*/
- public static void setBackgroundTintList(View view, ColorStateList tintList) {
+ public static void setBackgroundTintList(@NonNull View view, ColorStateList tintList) {
IMPL.setBackgroundTintList(view, tintList);
}
@@ -3257,7 +2788,7 @@
* Only returns meaningful info when running on API v21 or newer, or if {@code view}
* implements the {@code TintableBackgroundView} interface.
*/
- public static PorterDuff.Mode getBackgroundTintMode(View view) {
+ public static PorterDuff.Mode getBackgroundTintMode(@NonNull View view) {
return IMPL.getBackgroundTintMode(view);
}
@@ -3270,7 +2801,7 @@
* previous to API v21, it will only take effect if {@code view} implement the
* {@code TintableBackgroundView} interface.
*/
- public static void setBackgroundTintMode(View view, PorterDuff.Mode mode) {
+ public static void setBackgroundTintMode(@NonNull View view, PorterDuff.Mode mode) {
IMPL.setBackgroundTintMode(view, mode);
}
@@ -3614,16 +3145,22 @@
*
* @return whether the view hierarchy is currently undergoing a layout pass
*/
- public static boolean isInLayout(View view) {
- return IMPL.isInLayout(view);
+ public static boolean isInLayout(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 18) {
+ return view.isInLayout();
+ }
+ return false;
}
/**
* Returns true if {@code view} has been through at least one layout since it
* was last attached to or detached from a window.
*/
- public static boolean isLaidOut(View view) {
- return IMPL.isLaidOut(view);
+ public static boolean isLaidOut(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 19) {
+ return view.isLaidOut();
+ }
+ return view.getWidth() > 0 && view.getHeight() > 0;
}
/**
@@ -3636,8 +3173,11 @@
*
* @return true if layout direction has been resolved.
*/
- public static boolean isLayoutDirectionResolved(View view) {
- return IMPL.isLayoutDirectionResolved(view);
+ public static boolean isLayoutDirectionResolved(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 19) {
+ return view.isLayoutDirectionResolved();
+ }
+ return false;
}
/**
@@ -3647,7 +3187,7 @@
*
* @return The visual z position of this view, in pixels.
*/
- public static float getZ(View view) {
+ public static float getZ(@NonNull View view) {
return IMPL.getZ(view);
}
@@ -3663,7 +3203,7 @@
*
* @param z The visual z position of this view, in pixels.
*/
- public static void setZ(View view, float z) {
+ public static void setZ(@NonNull View view, float z) {
IMPL.setZ(view, z);
}
@@ -3672,7 +3212,7 @@
*
* @param offset the number of pixels to offset the view by
*/
- public static void offsetTopAndBottom(View view, int offset) {
+ public static void offsetTopAndBottom(@NonNull View view, int offset) {
IMPL.offsetTopAndBottom(view, offset);
}
@@ -3681,7 +3221,7 @@
*
* @param offset the number of pixels to offset the view by
*/
- public static void offsetLeftAndRight(View view, int offset) {
+ public static void offsetLeftAndRight(@NonNull View view, int offset) {
IMPL.offsetLeftAndRight(view, offset);
}
@@ -3696,8 +3236,10 @@
* @param clipBounds The rectangular area, in the local coordinates of
* this view, to which future drawing operations will be clipped.
*/
- public static void setClipBounds(View view, Rect clipBounds) {
- IMPL.setClipBounds(view, clipBounds);
+ public static void setClipBounds(@NonNull View view, Rect clipBounds) {
+ if (Build.VERSION.SDK_INT >= 18) {
+ view.setClipBounds(clipBounds);
+ }
}
/**
@@ -3708,15 +3250,22 @@
* @return A copy of the current clip bounds if clip bounds are set,
* otherwise null.
*/
- public static Rect getClipBounds(View view) {
- return IMPL.getClipBounds(view);
+ @Nullable
+ public static Rect getClipBounds(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 18) {
+ return view.getClipBounds();
+ }
+ return null;
}
/**
* Returns true if the provided view is currently attached to a window.
*/
- public static boolean isAttachedToWindow(View view) {
- return IMPL.isAttachedToWindow(view);
+ public static boolean isAttachedToWindow(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 19) {
+ return view.isAttachedToWindow();
+ }
+ return view.getWindowToken() != null;
}
/**
@@ -3724,8 +3273,11 @@
*
* @return true if there is a listener, false if there is none.
*/
- public static boolean hasOnClickListeners(View view) {
- return IMPL.hasOnClickListeners(view);
+ public static boolean hasOnClickListeners(@NonNull View view) {
+ if (Build.VERSION.SDK_INT >= 15) {
+ return view.hasOnClickListeners();
+ }
+ return false;
}
/**
@@ -3796,7 +3348,10 @@
* @param pointerIcon A PointerIconCompat instance which will be shown when the mouse hovers.
*/
public static void setPointerIcon(@NonNull View view, PointerIconCompat pointerIcon) {
- IMPL.setPointerIcon(view, pointerIcon);
+ if (Build.VERSION.SDK_INT >= 24) {
+ view.setPointerIcon((PointerIcon) (pointerIcon != null
+ ? pointerIcon.getPointerIcon() : null));
+ }
}
/**
@@ -3809,8 +3364,17 @@
*
* @return The logical display, or null if the view is not currently attached to a window.
*/
+ @Nullable
public static Display getDisplay(@NonNull View view) {
- return IMPL.getDisplay(view);
+ if (Build.VERSION.SDK_INT >= 17) {
+ return view.getDisplay();
+ }
+ if (isAttachedToWindow(view)) {
+ final WindowManager wm = (WindowManager) view.getContext().getSystemService(
+ Context.WINDOW_SERVICE);
+ return wm.getDefaultDisplay();
+ }
+ return null;
}
/**
@@ -3822,29 +3386,39 @@
* @param tooltipText the tooltip text
*/
public static void setTooltipText(@NonNull View view, @Nullable CharSequence tooltipText) {
- IMPL.setTooltipText(view, tooltipText);
+ if (Build.VERSION.SDK_INT >= 26) {
+ view.setTooltipText(tooltipText);
+ }
}
/**
* Start the drag and drop operation.
*/
- public static boolean startDragAndDrop(View v, ClipData data,
+ public static boolean startDragAndDrop(@NonNull View v, ClipData data,
View.DragShadowBuilder shadowBuilder, Object localState, int flags) {
- return IMPL.startDragAndDrop(v, data, shadowBuilder, localState, flags);
+ if (Build.VERSION.SDK_INT >= 24) {
+ return v.startDragAndDrop(data, shadowBuilder, localState, flags);
+ } else {
+ return v.startDrag(data, shadowBuilder, localState, flags);
+ }
}
/**
* Cancel the drag and drop operation.
*/
- public static void cancelDragAndDrop(View v) {
- IMPL.cancelDragAndDrop(v);
+ public static void cancelDragAndDrop(@NonNull View v) {
+ if (Build.VERSION.SDK_INT >= 24) {
+ v.cancelDragAndDrop();
+ }
}
/**
* Update the drag shadow while drag and drop is in progress.
*/
- public static void updateDragShadow(View v, View.DragShadowBuilder shadowBuilder) {
- IMPL.updateDragShadow(v, shadowBuilder);
+ public static void updateDragShadow(@NonNull View v, View.DragShadowBuilder shadowBuilder) {
+ if (Build.VERSION.SDK_INT >= 24) {
+ v.updateDragShadow(shadowBuilder);
+ }
}
/**
@@ -3854,7 +3428,10 @@
* should decide automatically or API < 26.
*/
public static int getNextClusterForwardId(@NonNull View view) {
- return IMPL.getNextClusterForwardId(view);
+ if (Build.VERSION.SDK_INT >= 26) {
+ return view.getNextClusterForwardId();
+ }
+ return View.NO_ID;
}
/**
@@ -3865,7 +3442,9 @@
* should decide automatically.
*/
public static void setNextClusterForwardId(@NonNull View view, int nextClusterForwardId) {
- IMPL.setNextClusterForwardId(view, nextClusterForwardId);
+ if (Build.VERSION.SDK_INT >= 26) {
+ view.setNextClusterForwardId(nextClusterForwardId);
+ }
}
/**
@@ -3875,7 +3454,10 @@
* @return {@code true} if this view is a root of a cluster, or {@code false} otherwise.
*/
public static boolean isKeyboardNavigationCluster(@NonNull View view) {
- return IMPL.isKeyboardNavigationCluster(view);
+ if (Build.VERSION.SDK_INT >= 26) {
+ return view.isKeyboardNavigationCluster();
+ }
+ return false;
}
/**
@@ -3886,7 +3468,9 @@
* to unmark.
*/
public static void setKeyboardNavigationCluster(@NonNull View view, boolean isCluster) {
- IMPL.setKeyboardNavigationCluster(view, isCluster);
+ if (Build.VERSION.SDK_INT >= 26) {
+ view.setKeyboardNavigationCluster(isCluster);
+ }
}
/**
@@ -3899,7 +3483,10 @@
* @return {@code true} if {@code view} is the default-focus view, {@code false} otherwise.
*/
public static boolean isFocusedByDefault(@NonNull View view) {
- return IMPL.isFocusedByDefault(view);
+ if (Build.VERSION.SDK_INT >= 26) {
+ return view.isFocusedByDefault();
+ }
+ return false;
}
/**
@@ -3915,7 +3502,9 @@
* {@code false} otherwise.
*/
public static void setFocusedByDefault(@NonNull View view, boolean isFocusedByDefault) {
- IMPL.setFocusedByDefault(view, isFocusedByDefault);
+ if (Build.VERSION.SDK_INT >= 26) {
+ view.setFocusedByDefault(isFocusedByDefault);
+ }
}
/**
@@ -3931,7 +3520,10 @@
*/
public static View keyboardNavigationClusterSearch(@NonNull View view, View currentCluster,
@FocusDirection int direction) {
- return IMPL.keyboardNavigationClusterSearch(view, currentCluster, direction);
+ if (Build.VERSION.SDK_INT >= 26) {
+ return view.keyboardNavigationClusterSearch(currentCluster, direction);
+ }
+ return null;
}
/**
@@ -3944,7 +3536,9 @@
*/
public static void addKeyboardNavigationClusters(@NonNull View view,
@NonNull Collection<View> views, int direction) {
- IMPL.addKeyboardNavigationClusters(view, views, direction);
+ if (Build.VERSION.SDK_INT >= 26) {
+ view.addKeyboardNavigationClusters(views, direction);
+ }
}
/**
@@ -3956,7 +3550,10 @@
* otherwise.
*/
public static boolean restoreDefaultFocus(@NonNull View view) {
- return IMPL.restoreDefaultFocus(view);
+ if (Build.VERSION.SDK_INT >= 26) {
+ return view.restoreDefaultFocus();
+ }
+ return view.requestFocus();
}
/**
@@ -3975,7 +3572,10 @@
* view, {@code false} otherwise
*/
public static boolean hasExplicitFocusable(@NonNull View view) {
- return IMPL.hasExplicitFocusable(view);
+ if (Build.VERSION.SDK_INT >= 26) {
+ return view.hasExplicitFocusable();
+ }
+ return view.hasFocusable();
}
/**
@@ -3985,7 +3585,18 @@
* @return a generated ID value
*/
public static int generateViewId() {
- return IMPL.generateViewId();
+ if (Build.VERSION.SDK_INT >= 17) {
+ return View.generateViewId();
+ }
+ for (;;) {
+ final int result = sNextGeneratedId.get();
+ // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
+ int newValue = result + 1;
+ if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
+ if (sNextGeneratedId.compareAndSet(result, newValue)) {
+ return result;
+ }
+ }
}
protected ViewCompat() {}
diff --git a/compat/src/main/java/androidx/core/view/ViewGroupCompat.java b/compat/src/main/java/androidx/core/view/ViewGroupCompat.java
index 95783cc..bd1d0ed 100644
--- a/compat/src/main/java/androidx/core/view/ViewGroupCompat.java
+++ b/compat/src/main/java/androidx/core/view/ViewGroupCompat.java
@@ -181,7 +181,7 @@
*
* @see #setLayoutMode(ViewGroup, int)
*/
- public static int getLayoutMode(ViewGroup group) {
+ public static int getLayoutMode(@NonNull ViewGroup group) {
return IMPL.getLayoutMode(group);
}
@@ -194,7 +194,7 @@
*
* @see #getLayoutMode(ViewGroup)
*/
- public static void setLayoutMode(ViewGroup group, int mode) {
+ public static void setLayoutMode(@NonNull ViewGroup group, int mode) {
IMPL.setLayoutMode(group, mode);
}
@@ -206,7 +206,7 @@
* only its children. If true, the entire ViewGroup will transition
* together.
*/
- public static void setTransitionGroup(ViewGroup group, boolean isTransitionGroup) {
+ public static void setTransitionGroup(@NonNull ViewGroup group, boolean isTransitionGroup) {
IMPL.setTransitionGroup(group, isTransitionGroup);
}
@@ -215,7 +215,7 @@
* when executing an Activity transition. If this is false, child elements will move
* individually during the transition.
*/
- public static boolean isTransitionGroup(ViewGroup group) {
+ public static boolean isTransitionGroup(@NonNull ViewGroup group) {
return IMPL.isTransitionGroup(group);
}
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
index 36a29ee..dfb82f5 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
@@ -293,7 +293,8 @@
DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);
SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
"See contact info"), Icon.createWithResource(getContext(),
- R.drawable.mady), "Mady");
+ R.drawable.mady), SMALL_IMAGE, "Mady");
+
return new ListBuilder(getContext(), sliceUri)
.setColor(0xff3949ab)
.setHeader(b -> b
diff --git a/slices/builders/api/current.txt b/slices/builders/api/current.txt
index 03b7c6b..96b8d75 100644
--- a/slices/builders/api/current.txt
+++ b/slices/builders/api/current.txt
@@ -111,6 +111,7 @@
public class SliceAction {
ctor public SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence);
+ ctor public SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, int, java.lang.CharSequence);
ctor public SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence, boolean);
ctor public SliceAction(android.app.PendingIntent, java.lang.CharSequence, boolean);
method public android.app.PendingIntent getAction();
diff --git a/slices/builders/src/main/java/androidx/slice/builders/SliceAction.java b/slices/builders/src/main/java/androidx/slice/builders/SliceAction.java
index 0b70ceb..00adbd4 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/SliceAction.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/SliceAction.java
@@ -16,21 +16,24 @@
package androidx.slice.builders;
+import static android.app.slice.Slice.HINT_NO_TINT;
import static android.app.slice.Slice.HINT_SELECTED;
import static android.app.slice.Slice.HINT_SHORTCUT;
import static android.app.slice.Slice.HINT_TITLE;
import static android.app.slice.Slice.SUBTYPE_CONTENT_DESCRIPTION;
import static android.app.slice.Slice.SUBTYPE_PRIORITY;
import static android.app.slice.Slice.SUBTYPE_TOGGLE;
+
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
import android.app.PendingIntent;
import android.graphics.drawable.Icon;
+
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
-
import androidx.slice.Slice;
/**
@@ -40,6 +43,7 @@
private PendingIntent mAction;
private Icon mIcon;
+ private int mImageMode;
private CharSequence mTitle;
private CharSequence mContentDescription;
private boolean mIsToggle;
@@ -56,9 +60,32 @@
*/
public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
@NonNull CharSequence actionTitle) {
+ this(action, actionIcon, ICON_IMAGE, actionTitle);
+ }
+
+ /**
+ * Construct a SliceAction representing a tappable icon. Use this method to specify the
+ * format of the image, {@link ListBuilder#ICON_IMAGE} will be presented as a tintable icon.
+ * Note that there is no difference between {@link ListBuilder#SMALL_IMAGE} and
+ * {@link ListBuilder#LARGE_IMAGE} for actions; these will just be represented as an
+ * non-tintable image.
+ *
+ * @param action the pending intent to invoke for this action.
+ * @param actionIcon the icon to display for this action.
+ * @param imageMode the mode this icon should be displayed in.
+ * @param actionTitle the title for this action, also used for content description if one hasn't
+ * been set via {@link #setContentDescription(CharSequence)}.
+ *
+ * @see ListBuilder#ICON_IMAGE
+ * @see ListBuilder#SMALL_IMAGE
+ * @see ListBuilder#LARGE_IMAGE
+ */
+ public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+ @ListBuilder.ImageMode int imageMode, @NonNull CharSequence actionTitle) {
mAction = action;
mIcon = actionIcon;
mTitle = actionTitle;
+ mImageMode = imageMode;
}
/**
@@ -73,7 +100,7 @@
*/
public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
@NonNull CharSequence actionTitle, boolean isChecked) {
- this(action, actionIcon, actionTitle);
+ this(action, actionIcon, ICON_IMAGE, actionTitle);
mIsChecked = isChecked;
mIsToggle = true;
}
@@ -194,7 +221,10 @@
public Slice buildSlice(@NonNull Slice.Builder builder) {
Slice.Builder sb = new Slice.Builder(builder);
if (mIcon != null) {
- sb.addIcon(mIcon, null);
+ @Slice.SliceHint String[] hints = mImageMode == ICON_IMAGE
+ ? new String[] {}
+ : new String[] {HINT_NO_TINT};
+ sb.addIcon(mIcon, null, hints);
}
if (mTitle != null) {
sb.addText(mTitle, null, HINT_TITLE);
diff --git a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
index 26c7704..aa60b38 100644
--- a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
+++ b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
@@ -34,8 +34,6 @@
import android.text.format.DateUtils;
import android.text.style.ForegroundColorSpan;
-import java.util.Arrays;
-
import androidx.slice.Slice;
import androidx.slice.builders.GridBuilder;
import androidx.slice.builders.ListBuilder;
@@ -43,6 +41,8 @@
import androidx.slice.builders.SliceAction;
import androidx.slice.view.test.R;
+import java.util.Arrays;
+
/**
* Examples of using slice template builders.
*/
@@ -220,13 +220,15 @@
private Slice createContact(Uri sliceUri) {
ListBuilder b = new ListBuilder(getContext(), sliceUri);
ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(b);
+ SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
+ "See contact info"), Icon.createWithResource(getContext(),
+ R.drawable.mady), SMALL_IMAGE, "Mady");
GridBuilder gb = new GridBuilder(b);
return b.setColor(0xff3949ab)
.addRow(rb
.setTitle("Mady Pitza")
.setSubtitle("Frequently contacted contact")
- .addEndItem(Icon.createWithResource(getContext(), R.drawable.mady),
- SMALL_IMAGE))
+ .addEndItem(primaryAction))
.addGrid(gb
.addCell(new GridBuilder.CellBuilder(gb)
.addImage(Icon.createWithResource(getContext(), R.drawable.ic_call),
diff --git a/slices/view/src/main/java/androidx/slice/widget/ListContent.java b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
index 5259ce7..1a0f069 100644
--- a/slices/view/src/main/java/androidx/slice/widget/ListContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
@@ -31,9 +31,6 @@
import android.content.Context;
-import java.util.ArrayList;
-import java.util.List;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
@@ -42,6 +39,9 @@
import androidx.slice.SliceUtils;
import androidx.slice.core.SliceQuery;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Extracts information required to present content in a list format from a slice.
* @hide
@@ -208,6 +208,15 @@
return mHeaderItem != null && isValidHeader(mHeaderItem);
}
+ /**
+ * @return the primary action for this list; i.e. action on the header or first row.
+ */
+ @Nullable
+ public SliceItem getPrimaryAction() {
+ RowContent rc = new RowContent(mContext, mHeaderItem, false);
+ return rc.getPrimaryAction();
+ }
+
@Nullable
private static SliceItem findHeaderItem(@NonNull Slice slice) {
// See if header is specified
diff --git a/slices/view/src/main/java/androidx/slice/widget/ShortcutView.java b/slices/view/src/main/java/androidx/slice/widget/ShortcutView.java
index 2235e92..b068c26 100644
--- a/slices/view/src/main/java/androidx/slice/widget/ShortcutView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/ShortcutView.java
@@ -39,9 +39,9 @@
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.net.Uri;
-import androidx.annotation.RestrictTo;
import android.widget.ImageView;
+import androidx.annotation.RestrictTo;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
import androidx.slice.core.SliceQuery;
@@ -141,15 +141,15 @@
* Looks at the slice and determines which items are best to use to compose the shortcut.
*/
private void determineShortcutItems(Context context, Slice slice) {
- SliceItem titleItem = SliceQuery.find(slice, FORMAT_ACTION,
- HINT_TITLE, null);
+ ListContent lc = new ListContent(context, slice);
+ SliceItem primaryAction = lc.getPrimaryAction();
- if (titleItem != null) {
- // Preferred case: hinted action containing hinted image and text
- mActionItem = titleItem;
- mIcon = SliceQuery.find(titleItem.getSlice(), FORMAT_IMAGE, HINT_TITLE,
+ if (primaryAction != null) {
+ // Preferred case: slice has a primary action
+ mActionItem = primaryAction.getSlice().getItems().get(0);
+ mIcon = SliceQuery.find(primaryAction.getSlice(), FORMAT_IMAGE, (String) null,
null);
- mLabel = SliceQuery.find(titleItem.getSlice(), FORMAT_TEXT, HINT_TITLE,
+ mLabel = SliceQuery.find(primaryAction.getSlice(), FORMAT_TEXT, (String) null,
null);
} else {
// No hinted action; just use the first one