Merge "Use the correct prebuilts for lifecycles."
diff --git a/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt b/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
new file mode 100644
index 0000000..55f010f
--- /dev/null
+++ b/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 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
+
+import net.ltgt.gradle.errorprone.ErrorProneToolChain
+import org.gradle.api.tasks.compile.JavaCompile
+
+fun JavaCompile.configureWithErrorProne(toolChain: ErrorProneToolChain) {
+ this.toolChain = toolChain
+
+ val compilerArgs = this.options.compilerArgs
+ compilerArgs += listOf(
+ "-XDcompilePolicy=simple", // Workaround for b/36098770
+
+ // Enforce the following checks.
+ "-Xep:RestrictTo:OFF",
+ "-Xep:ParameterNotNullable:ERROR",
+ "-Xep:MissingOverride:ERROR",
+ "-Xep:JdkObsolete:ERROR",
+ "-Xep:NarrowingCompoundAssignment:ERROR",
+ "-Xep:ClassNewInstance:ERROR",
+ "-Xep:ClassCanBeStatic:ERROR",
+ "-Xep:SynchronizeOnNonFinalField:ERROR",
+ "-Xep:OperatorPrecedence:ERROR",
+ "-Xep:IntLongMath:ERROR",
+ "-Xep:MissingFail:ERROR",
+
+ // Nullaway
+ "-XepIgnoreUnknownCheckNames", // https://github.com/uber/NullAway/issues/25
+ "-Xep:NullAway:ERROR",
+ "-XepOpt:NullAway:AnnotatedPackages=android.arch,android.support"
+ )
+}
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
index 8f3fdc5..a9cb293 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
@@ -143,30 +143,7 @@
library.libraryVariants.all { libraryVariant ->
if (libraryVariant.getBuildType().getName().equals("errorProne")) {
@Suppress("DEPRECATION")
- libraryVariant.getJavaCompile().toolChain = toolChain
-
- @Suppress("DEPRECATION")
- val compilerArgs = libraryVariant.javaCompile.options.compilerArgs
- compilerArgs += arrayListOf(
- "-XDcompilePolicy=simple", // Workaround for b/36098770
-
- // Enforce the following checks.
- "-Xep:RestrictTo:OFF",
- "-Xep:ParameterNotNullable:ERROR",
- "-Xep:MissingOverride:ERROR",
- "-Xep:JdkObsolete:ERROR",
- "-Xep:NarrowingCompoundAssignment:ERROR",
- "-Xep:ClassNewInstance:ERROR",
- "-Xep:ClassCanBeStatic:ERROR",
- "-Xep:SynchronizeOnNonFinalField:ERROR",
- "-Xep:OperatorPrecedence:ERROR",
- "-Xep:IntLongMath:ERROR",
-
- // Nullaway
- "-XepIgnoreUnknownCheckNames", // https://github.com/uber/NullAway/issues/25
- "-Xep:NullAway:ERROR",
- "-XepOpt:NullAway:AnnotatedPackages=android.arch,android.support"
- )
+ libraryVariant.javaCompile.configureWithErrorProne(toolChain)
}
}
}
@@ -207,4 +184,4 @@
if (baseline.exists()) {
lintOptions.baseline(baseline)
}
-}
\ No newline at end of file
+}
diff --git a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
index 0701433..cc2f985 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
@@ -16,10 +16,13 @@
package android.support
+import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
+import net.ltgt.gradle.errorprone.ErrorProneToolChain
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
+import org.gradle.api.tasks.compile.JavaCompile
/**
* Support java library specific plugin that sets common configurations needed for
@@ -44,6 +47,11 @@
}
}
+ project.apply(mapOf("plugin" to ErrorProneBasePlugin::class.java))
+ val toolChain = ErrorProneToolChain.create(project)
+ val compileTasks = project.tasks.withType(JavaCompile::class.java)
+ compileTasks.all { it.configureWithErrorProne(toolChain) }
+
setUpSourceJarTaskForJavaProject(project)
}
-}
\ No newline at end of file
+}
diff --git a/car/src/androidTest/java/androidx/car/widget/TextListItemTest.java b/car/src/androidTest/java/androidx/car/widget/TextListItemTest.java
index 529a9f0..97706a0 100644
--- a/car/src/androidTest/java/androidx/car/widget/TextListItemTest.java
+++ b/car/src/androidTest/java/androidx/car/widget/TextListItemTest.java
@@ -38,6 +38,7 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.v7.widget.LinearLayoutManager;
+import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
@@ -587,6 +588,43 @@
}
@Test
+ public void testRevertingViewBinder() throws Throwable {
+ TextListItem item0 = new TextListItem(mActivity);
+ item0.setBody("one item");
+ item0.addViewBinder(
+ (viewHolder) -> viewHolder.getBody().setEllipsize(TextUtils.TruncateAt.END),
+ (viewHolder -> viewHolder.getBody().setEllipsize(null)));
+
+ List<TextListItem> items = Arrays.asList(item0);
+ setupPagedListView(items);
+
+ TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0);
+
+ // Bind view holder to a new item - the customization made by item0 should be reverted.
+ TextListItem item1 = new TextListItem(mActivity);
+ item1.setBody("new item");
+ mActivityRule.runOnUiThread(() -> item1.bind(viewHolder));
+
+ assertThat(viewHolder.getBody().getEllipsize(), is(equalTo(null)));
+ }
+
+ @Test
+ public void testRemovingViewBinder() {
+ TextListItem item0 = new TextListItem(mActivity);
+ item0.setBody("one item");
+ ListItem.ViewBinder<TextListItem.ViewHolder> binder =
+ (viewHolder) -> viewHolder.getTitle().setEllipsize(TextUtils.TruncateAt.END);
+ item0.addViewBinder(binder);
+
+ assertTrue(item0.removeViewBinder(binder));
+
+ List<TextListItem> items = Arrays.asList(item0);
+ setupPagedListView(items);
+
+ assertThat(getViewHolderAtPosition(0).getBody().getEllipsize(), is(equalTo(null)));
+ }
+
+ @Test
public void testSettingTitleOrBodyAsPrimaryText() {
// Create 2 items, one with Title as primary (default) and one with Body.
// The primary text, regardless of view, should have consistent look (as primary).
diff --git a/car/src/main/java/androidx/car/widget/ListItem.java b/car/src/main/java/androidx/car/widget/ListItem.java
index 74ff2dd..97e8fca 100644
--- a/car/src/main/java/androidx/car/widget/ListItem.java
+++ b/car/src/main/java/androidx/car/widget/ListItem.java
@@ -1,15 +1,19 @@
package androidx.car.widget;
+import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Function;
/**
* Definition of items that can be inserted into {@link ListItemAdapter}.
*
- * @param <VH> ViewHolder.
+ * @param <VH> ViewHolder that extends {@link ListItem.ViewHolder}.
*/
-public abstract class ListItem<VH extends RecyclerView.ViewHolder> {
+public abstract class ListItem<VH extends ListItem.ViewHolder> {
// Whether the item should calculate view layout params. This usually happens when the item is
// updated after bind() is called. Calling bind() resets to false.
@@ -18,6 +22,11 @@
// Tag for indicating whether to hide the divider.
private boolean mHideDivider;
+ private final List<ViewBinder<VH>> mCustomBinders = new ArrayList<>();
+ // Stores ViewBinders to revert customization. Does not guarantee to 1:1 match ViewBinders
+ // in mCustomerBinders.
+ private final List<ViewBinder<VH>> mCustomBinderCleanUps = new ArrayList<>();
+
/**
* Classes that extends {@code ListItem} should register its view type in
* {@link ListItemAdapter#registerListItemViewType(int, int, Function)}.
@@ -29,27 +38,44 @@
/**
* Called when ListItem is bound to its ViewHolder.
*/
- public abstract void bind(VH viewHolder);
+ final void bind(VH viewHolder) {
+ // Attempt to clean up custom view binder from previous item (if any).
+ // Then save the clean up binders for next item.
+ viewHolder.cleanUp();
+ for (ViewBinder cleanUp : mCustomBinderCleanUps) {
+ viewHolder.addCleanUp(cleanUp);
+ }
+
+ if (isDirty()) {
+ resolveDirtyState();
+ markClean();
+ }
+ onBind(viewHolder);
+
+ // Custom view binders are applied after view layout.
+ for (ViewBinder<VH> binder: mCustomBinders) {
+ binder.bind(viewHolder);
+ }
+ }
/**
- * Marks this item so that sub-views in ViewHolder will need layout params re-calculated
- * in next bind().
+ * Marks this item as dirty so {@link #resolveDirtyState()} is required in next bind() call.
*
- * This method should be called in each setter.
+ * <p>This method should be called in each setter.
*/
protected void markDirty() {
mDirty = true;
}
/**
- * Marks this item as not dirty - no need to calculate sub-view layout params in bind().
+ * Marks this item as not dirty. No need to call {@link #resolveDirtyState()} in next bind().
*/
protected void markClean() {
mDirty = false;
}
/**
- * @return {@code true} if this item needs to calculate sub-view layout params.
+ * @return {@code true} if next bind() should call {@link #resolveDirtyState()}.
*/
protected boolean isDirty() {
return mDirty;
@@ -75,16 +101,118 @@
return mHideDivider;
};
+
+ /**
+ * Does the work that moves the ListItem from dirty state to clean state, i.e. the work required
+ * the first time this ListItem {@code bind}s to {@link ListItem.ViewHolder}.
+ * This method will transition ListItem to clean state. ListItem in clean state should move to
+ * dirty state when it is modified by calling {@link #markDirty()}.
+ */
+ protected abstract void resolveDirtyState();
+
+ /**
+ * Binds this ListItem to {@code viewHolder} by applying data in ListItem to sub-views.
+ * Assume {@link ViewHolder#cleanUp()} has already been invoked.
+ */
+ protected abstract void onBind(VH viewHolder);
+
+ /**
+ * Same as {@link #addViewBinder(ViewBinder, ViewBinder)} when {@code cleanUp} ViewBinder
+ * is null.
+ *
+ * @param binder to interact with subviews in {@code ViewHolder}.
+ *
+ * @see #addViewBinder(ViewBinder, ViewBinder)
+ */
+ public final void addViewBinder(ViewBinder<VH> binder) {
+ addViewBinder(binder, null);
+ }
+
+ /**
+ * Adds {@link ViewBinder} to interact with sub-views in {@link ViewHolder}. These ViewBinders
+ * will always be applied after {@link #onBind(ViewHolder)}.
+ *
+ * <p>To interact with a foobar sub-view in {@code ViewHolder}, make sure to first set its
+ * visibility, or call setFoobar() setter method.
+ *
+ * <p>Example:
+ * <pre>
+ * {@code
+ * TextListItem item = new TextListItem(context);
+ * item.setTitle("title");
+ * item.addViewBinder((viewHolder) -> {
+ * viewHolder.getTitle().doFoobar();
+ * }, (viewHolder) -> {
+ * viewHolder.getTitle().revertFoobar();
+ * });
+ * }
+ * </pre>
+ *
+ * @params binder to interact with subviews in {@code ViewHolder}.
+ * @params cleanUp view binder to revert the effect of {@code binder}. cleanUp binders will be
+ * stored in {@link ListItem.ViewHolder} and should be invoked via
+ * {@link ViewHolder#cleanUp()} before {@code ViewHolder} is recycled.
+ * This is to avoid changed made to ViewHolder lingers around when ViewHolder is
+ * recycled. Pass in null to skip.
+ */
+ public final void addViewBinder(ViewBinder<VH> binder, @Nullable ViewBinder<VH> cleanUp) {
+ mCustomBinders.add(binder);
+ if (cleanUp != null) {
+ mCustomBinderCleanUps.add(cleanUp);
+ }
+ markDirty();
+ }
+
+ /**
+ * Removes the first occurrence of the specified item.
+ *
+ * @param binder to be removed.
+ * @return {@code true} if {@code binder} exists. {@code false} otherwise.
+ */
+ public boolean removeViewBinder(ViewBinder<VH> binder) {
+ return mCustomBinders.remove(binder);
+ }
+
/**
* Functional interface to provide a way to interact with views in {@code ViewHolder}.
* {@code ListItem} calls all added ViewBinders when it {@code bind}s to {@code ViewHolder}.
*
- * @param <VH> extends {@link RecyclerView.ViewHolder}.
+ * @param <VH> class that extends {@link RecyclerView.ViewHolder}.
*/
- public interface ViewBinder<VH extends RecyclerView.ViewHolder> {
+ public interface ViewBinder<VH> {
/**
* Provides a way to interact with views in view holder.
*/
void bind(VH viewHolder);
}
+
+ /**
+ * ViewHolder that supports {@link ViewBinder}.
+ */
+ public abstract static class ViewHolder extends RecyclerView.ViewHolder {
+ private final List<ViewBinder> mCleanUps = new ArrayList<>();
+
+ public ViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ /**
+ * Removes customization from previous ListItem. Intended to be used when this ViewHolder is
+ * bound to a ListItem.
+ */
+ public final void cleanUp() {
+ for (ViewBinder binder : mCleanUps) {
+ binder.bind(this);
+ }
+ }
+
+ /**
+ * Stores clean up ViewBinders that will be called in {@code cleanUp()}.
+ */
+ public final void addCleanUp(@Nullable ViewBinder<ViewHolder> cleanUp) {
+ if (cleanUp != null) {
+ mCleanUps.add(cleanUp);
+ }
+ }
+ }
}
diff --git a/car/src/main/java/androidx/car/widget/ListItemAdapter.java b/car/src/main/java/androidx/car/widget/ListItemAdapter.java
index 8dedbf5..78b1d6e 100644
--- a/car/src/main/java/androidx/car/widget/ListItemAdapter.java
+++ b/car/src/main/java/androidx/car/widget/ListItemAdapter.java
@@ -43,7 +43,7 @@
*
*/
public class ListItemAdapter extends
- RecyclerView.Adapter<RecyclerView.ViewHolder> implements PagedListView.ItemCap,
+ RecyclerView.Adapter<ListItem.ViewHolder> implements PagedListView.ItemCap,
PagedListView.DividerVisibilityManager {
/**
@@ -74,7 +74,7 @@
static final int LIST_ITEM_TYPE_SEEKBAR = 2;
private final SparseIntArray mViewHolderLayoutResIds = new SparseIntArray();
- private final SparseArray<Function<View, RecyclerView.ViewHolder>> mViewHolderCreator =
+ private final SparseArray<Function<View, ListItem.ViewHolder>> mViewHolderCreator =
new SparseArray<>();
/**
@@ -90,7 +90,7 @@
* @param function function to create ViewHolder for {@code viewType}.
*/
public void registerListItemViewType(int viewType, @LayoutRes int layoutResId,
- Function<View, RecyclerView.ViewHolder> function) {
+ Function<View, ListItem.ViewHolder> function) {
if (mViewHolderLayoutResIds.get(viewType) != 0
|| mViewHolderCreator.get(viewType) != null) {
throw new IllegalArgumentException("View type is already registered.");
@@ -121,7 +121,7 @@
}
@Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ public ListItem.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (mViewHolderLayoutResIds.get(viewType) == 0
|| mViewHolderCreator.get(viewType) == null) {
throw new IllegalArgumentException("Unregistered view type.");
@@ -175,7 +175,7 @@
}
@Override
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ public void onBindViewHolder(ListItem.ViewHolder holder, int position) {
ListItem item = mItemProvider.get(position);
item.bind(holder);
diff --git a/car/src/main/java/androidx/car/widget/PagedSnapHelper.java b/car/src/main/java/androidx/car/widget/PagedSnapHelper.java
index 9bf1fb6..610894c 100644
--- a/car/src/main/java/androidx/car/widget/PagedSnapHelper.java
+++ b/car/src/main/java/androidx/car/widget/PagedSnapHelper.java
@@ -29,6 +29,12 @@
* the start of the attached {@link RecyclerView}. The start of the view is defined as the top
* if the RecyclerView is scrolling vertically; it is defined as the left (or right if RTL) if the
* RecyclerView is scrolling horizontally.
+ *
+ * <p>Snapping may be disabled for views whose height is greater than that of the
+ * {@code RecyclerView} that contains them. In this case, the view will only be snapped to when it
+ * is first encountered. Otherwise, the user will be allowed to scroll freely through that view
+ * when it appears in the list. The snapping behavior will resume when the large view is scrolled
+ * off-screen.
*/
public class PagedSnapHelper extends LinearSnapHelper {
/**
@@ -41,11 +47,8 @@
private RecyclerView mRecyclerView;
// Orientation helpers are lazily created per LayoutManager.
- @Nullable
- private OrientationHelper mVerticalHelper;
-
- @Nullable
- private OrientationHelper mHorizontalHelper;
+ @Nullable private OrientationHelper mVerticalHelper;
+ @Nullable private OrientationHelper mHorizontalHelper;
public PagedSnapHelper(Context context) {
mSmoothScroller = new PagedSmoothScroller(context);
@@ -85,15 +88,14 @@
return null;
}
+ OrientationHelper orientationHelper = getOrientationHelper(layoutManager);
+
// If there's only one child, then that will be the snap target.
if (childCount == 1) {
- return layoutManager.getChildAt(0);
+ View firstChild = layoutManager.getChildAt(0);
+ return isValidSnapView(firstChild, orientationHelper) ? firstChild : null;
}
- OrientationHelper orientationHelper = layoutManager.canScrollVertically()
- ? getVerticalHelper(layoutManager)
- : getHorizontalHelper(layoutManager);
-
View lastVisibleChild = layoutManager.getChildAt(childCount - 1);
// Check if the last child visible is the last item in the list.
@@ -108,6 +110,7 @@
int closestDistanceToStart = Integer.MAX_VALUE;
float closestPercentageVisible = 0.f;
+ // Iterate to find the child closest to the top and more than half way visible.
for (int i = 0; i < childCount; i++) {
View child = layoutManager.getChildAt(i);
int startOffset = orientationHelper.getDecoratedStart(child);
@@ -115,8 +118,6 @@
if (Math.abs(startOffset) < closestDistanceToStart) {
float percentageVisible = getPercentageVisible(child, orientationHelper);
- // Only snap to the child that is closest to the top and is more than
- // half-way visible.
if (percentageVisible > VIEW_VISIBLE_THRESHOLD
&& percentageVisible > closestPercentageVisible) {
closestDistanceToStart = startOffset;
@@ -126,11 +127,43 @@
}
}
- // Snap to the last child in the list if it's the last item in the list, and it's more
- // visible than the closest item to the top of the list.
- return (lastItemVisible && lastItemPercentageVisible > closestPercentageVisible)
- ? lastVisibleChild
- : closestChild;
+ View childToReturn = closestChild;
+
+ // If closestChild is null, then that means we were unable to find a closest child that
+ // is over the VIEW_VISIBLE_THRESHOLD. This could happen if the views are larger than
+ // the given area. In this case, consider returning the lastVisibleChild so that the screen
+ // scrolls. Also, check if the last item should be displayed anyway if it is mostly visible.
+ if ((childToReturn == null
+ || (lastItemVisible && lastItemPercentageVisible > closestPercentageVisible))) {
+ childToReturn = lastVisibleChild;
+ }
+
+ // Return null if the childToReturn is not valid. This allows the user to scroll freely
+ // with no snapping. This can allow them to see the entire view.
+ return isValidSnapView(childToReturn, orientationHelper) ? childToReturn : null;
+ }
+
+ /**
+ * Returns whether or not the given View is a valid snapping view. A view is considered valid
+ * for snapping if:
+ *
+ * <ol>
+ * <li>It can fit entirely within the height of the RecyclerView it is contained within.
+ * <li>Or the start of the view is not above the start of the RecyclerView.
+ * </ol>
+ *
+ * <p>If the view is larger than the RecyclerView, then it might not want to be snapped to
+ * to allow the user to scroll and see the rest of the View. Likewise, if the start of the
+ * view is above the start of the RecyclerView, it implies that the user has already scrolled
+ * past it and might want to see the rest of it. Thus, the view should not be snapped to.
+ *
+ * @param view The view to determine the snapping potential.
+ * @param helper The {@link OrientationHelper} associated with the current RecyclerView.
+ * @return {@code true} if the given view is a valid snapping view; {@code false} otherwise.
+ */
+ private boolean isValidSnapView(View view, OrientationHelper helper) {
+ return helper.getDecoratedMeasurement(view) <= helper.getLayoutManager().getHeight()
+ || helper.getDecoratedStart(view) >= 0;
}
/**
@@ -210,12 +243,19 @@
int lastChildPosition = isAtEnd(layoutManager) ? 0 : layoutManager.getChildCount() - 1;
- // The max and min distance is the total height of the RecyclerView minus the height of
- // the last child. This ensures that each scroll will never scroll more than a single
- // page on the RecyclerView. That is, the max scroll will make the last child the
- // first child and vice versa when scrolling the opposite way.
- int maxDistance = layoutManager.getHeight() - layoutManager.getDecoratedMeasuredHeight(
- layoutManager.getChildAt(lastChildPosition));
+ OrientationHelper orientationHelper = getOrientationHelper(layoutManager);
+ View lastChild = layoutManager.getChildAt(lastChildPosition);
+ float percentageVisible = getPercentageVisible(lastChild, orientationHelper);
+
+ int maxDistance = layoutManager.getHeight();
+ if (percentageVisible > 0.f) {
+ // The max and min distance is the total height of the RecyclerView minus the height of
+ // the last child. This ensures that each scroll will never scroll more than a single
+ // page on the RecyclerView. That is, the max scroll will make the last child the
+ // first child and vice versa when scrolling the opposite way.
+ maxDistance -= layoutManager.getDecoratedMeasuredHeight(lastChild);
+ }
+
int minDistance = -maxDistance;
outDist[0] = clamp(outDist[0], minDistance, maxDistance);
@@ -255,6 +295,18 @@
&& layoutManager.getDecoratedBottom(lastVisibleChild) <= layoutManager.getHeight();
}
+ /**
+ * Returns an {@link OrientationHelper} that corresponds to the current scroll direction of
+ * the given {@link android.support.v7.widget.RecyclerView.LayoutManager}.
+ */
+ @NonNull
+ private OrientationHelper getOrientationHelper(
+ @NonNull RecyclerView.LayoutManager layoutManager) {
+ return layoutManager.canScrollVertically()
+ ? getVerticalHelper(layoutManager)
+ : getHorizontalHelper(layoutManager);
+ }
+
@NonNull
private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
if (mVerticalHelper == null || mVerticalHelper.getLayoutManager() != layoutManager) {
diff --git a/car/src/main/java/androidx/car/widget/SeekbarListItem.java b/car/src/main/java/androidx/car/widget/SeekbarListItem.java
index 54c37ef..2e98817 100644
--- a/car/src/main/java/androidx/car/widget/SeekbarListItem.java
+++ b/car/src/main/java/androidx/car/widget/SeekbarListItem.java
@@ -24,7 +24,6 @@
import android.support.annotation.IdRes;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
@@ -93,8 +92,6 @@
private final Context mContext;
private final List<ViewBinder<ViewHolder>> mBinders = new ArrayList<>();
- // Store custom binders separately so they will bind after binders created by setters.
- private final List<ViewBinder<ViewHolder>> mCustomBinders = new ArrayList<>();
@PrimaryActionType private int mPrimaryActionType = PRIMARY_ACTION_TYPE_NO_ICON;
private int mPrimaryActionIconResId;
@@ -156,33 +153,32 @@
}
/**
- * Applies all {@link ViewBinder} to {@code ViewHolder}.
+ * Calculates the layout params for views in {@link ViewHolder}.
*/
@Override
- public void bind(ViewHolder viewHolder) {
- if (isDirty()) {
- mBinders.clear();
+ protected void resolveDirtyState() {
+ mBinders.clear();
- // Create binders that adjust layout params of each view.
- setItemLayoutHeight();
- setPrimaryAction();
- setSeekBarAndText();
- setSupplementalAction();
+ // Create binders that adjust layout params of each view.
+ setItemLayoutHeight();
+ setPrimaryAction();
+ setSeekBarAndText();
+ setSupplementalAction();
+ }
- // Custom view binders are always applied after the one created by this class.
- mBinders.addAll(mCustomBinders);
-
- markClean();
- }
-
+ /**
+ * Hides all views in {@link ViewHolder} then applies ViewBinders to adjust view layout params.
+ */
+ @Override
+ protected void onBind(ViewHolder viewHolder) {
// Hide all subviews then apply view binders to adjust subviews.
- setSubViewsGone(viewHolder);
+ hideSubViews(viewHolder);
for (ViewBinder binder : mBinders) {
binder.bind(viewHolder);
}
}
- private void setSubViewsGone(ViewHolder vh) {
+ private void hideSubViews(ViewHolder vh) {
View[] subviews = new View[] {
vh.getPrimaryIcon(),
// SeekBar is always visible.
@@ -499,31 +495,9 @@
}
/**
- * Adds {@code ViewBinder} to interact with sub-views in {@link ViewHolder}. These ViewBinders
- * will always be applied after other {@code setFoobar} methods have bound.
- *
- * <p>Make sure to call setFoobar() method on the intended sub-view first.
- *
- * <p>Example:
- * <pre>
- * {@code
- * SeekbarListItem item = new SeebarListItem(context);
- * item.setPrimaryActionIcon(R.drawable.icon);
- * item.addViewBinder((viewHolder) -> {
- * viewHolder.getPrimaryIcon().doMoreStuff();
- * });
- * }
- * </pre>
- */
- public void addViewBinder(ViewBinder<ViewHolder> viewBinder) {
- mCustomBinders.add(viewBinder);
- markDirty();
- }
-
- /**
* Holds views of SeekbarListItem.
*/
- public static class ViewHolder extends RecyclerView.ViewHolder {
+ public static class ViewHolder extends ListItem.ViewHolder {
private RelativeLayout mContainerLayout;
diff --git a/car/src/main/java/androidx/car/widget/TextListItem.java b/car/src/main/java/androidx/car/widget/TextListItem.java
index 71b6c96..871c14b 100644
--- a/car/src/main/java/androidx/car/widget/TextListItem.java
+++ b/car/src/main/java/androidx/car/widget/TextListItem.java
@@ -101,8 +101,6 @@
private final Context mContext;
private final List<ViewBinder<ViewHolder>> mBinders = new ArrayList<>();
- // Store custom binders separately so they will bind after binders created by setters.
- private final List<ViewBinder<ViewHolder>> mCustomBinders = new ArrayList<>();
private View.OnClickListener mOnClickListener;
@@ -151,34 +149,32 @@
}
/**
- * Applies all {@link ViewBinder} to {@code ViewHolder}.
+ * Calculates the layout params for views in {@link ViewHolder}.
*/
@Override
- public void bind(ViewHolder viewHolder) {
- if (isDirty()) {
- mBinders.clear();
+ protected void resolveDirtyState() {
+ mBinders.clear();
- // Create binders that adjust layout params of each view.
- setItemLayoutHeight();
- setPrimaryAction();
- setText();
- setSupplementalActions();
- setOnClickListener();
+ // Create binders that adjust layout params of each view.
+ setItemLayoutHeight();
+ setPrimaryAction();
+ setText();
+ setSupplementalActions();
+ setOnClickListener();
+ }
- // Custom view binders are always applied after the one created by this class.
- mBinders.addAll(mCustomBinders);
-
- markClean();
- }
-
- // Hide all subviews then apply view binders to adjust subviews.
- setAllSubViewsGone(viewHolder);
+ /**
+ * Hides all views in {@link ViewHolder} then applies ViewBinders to adjust view layout params.
+ */
+ @Override
+ public void onBind(ViewHolder viewHolder) {
+ hideSubViews(viewHolder);
for (ViewBinder binder : mBinders) {
binder.bind(viewHolder);
}
}
- void setAllSubViewsGone(ViewHolder vh) {
+ private void hideSubViews(ViewHolder vh) {
View[] subviews = new View[] {
vh.getPrimaryIcon(),
vh.getTitle(), vh.getBody(),
@@ -709,31 +705,9 @@
}
/**
- * Adds {@link ViewBinder} to interact with sub-views in {@link ViewHolder}. These ViewBinders
- * will always bind after other {@code setFoobar} methods have bound.
- *
- * <p>Make sure to call setFoobar() method on the intended sub-view first.
- *
- * <p>Example:
- * <pre>
- * {@code
- * TextListItem item = new TextListItem(context);
- * item.setTitle("title");
- * item.addViewBinder((viewHolder) -> {
- * viewHolder.getTitle().doMoreStuff();
- * });
- * }
- * </pre>
- */
- public void addViewBinder(ViewBinder<ViewHolder> binder) {
- mCustomBinders.add(binder);
- markDirty();
- }
-
- /**
* Holds views of TextListItem.
*/
- public static class ViewHolder extends RecyclerView.ViewHolder {
+ public static class ViewHolder extends ListItem.ViewHolder {
private RelativeLayout mContainerLayout;
diff --git a/compat/api/current.txt b/compat/api/current.txt
index f4423f1..f298c72 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -689,13 +689,13 @@
method public static int checkSelfPermission(android.content.Context, java.lang.String);
method public static android.content.Context createDeviceProtectedStorageContext(android.content.Context);
method public static java.io.File getCodeCacheDir(android.content.Context);
- method public static final int getColor(android.content.Context, int);
- method public static final android.content.res.ColorStateList getColorStateList(android.content.Context, int);
+ method public static int getColor(android.content.Context, int);
+ method public static android.content.res.ColorStateList getColorStateList(android.content.Context, int);
method public static java.io.File getDataDir(android.content.Context);
- method public static final android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
+ method public static android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
method public static java.io.File[] getExternalCacheDirs(android.content.Context);
method public static java.io.File[] getExternalFilesDirs(android.content.Context, java.lang.String);
- method public static final java.io.File getNoBackupFilesDir(android.content.Context);
+ method public static java.io.File getNoBackupFilesDir(android.content.Context);
method public static java.io.File[] getObbDirs(android.content.Context);
method public static boolean isDeviceProtectedStorage(android.content.Context);
method public static boolean startActivities(android.content.Context, android.content.Intent[]);
@@ -1103,14 +1103,14 @@
package android.support.v4.text.util {
public final class LinkifyCompat {
- method public static final boolean addLinks(android.text.Spannable, int);
- method public static final boolean addLinks(android.widget.TextView, int);
- method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
- method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
- method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
- method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
- method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
- method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+ method public static boolean addLinks(android.text.Spannable, int);
+ method public static boolean addLinks(android.widget.TextView, int);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+ method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
+ method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
}
}
diff --git a/compat/src/main/java/android/support/v4/app/ActivityCompat.java b/compat/src/main/java/android/support/v4/app/ActivityCompat.java
index 333871a..5599360 100644
--- a/compat/src/main/java/android/support/v4/app/ActivityCompat.java
+++ b/compat/src/main/java/android/support/v4/app/ActivityCompat.java
@@ -575,7 +575,7 @@
protected SharedElementCallback mCallback;
- public SharedElementCallback21Impl(SharedElementCallback callback) {
+ SharedElementCallback21Impl(SharedElementCallback callback) {
mCallback = callback;
}
@@ -618,7 +618,7 @@
@RequiresApi(23)
private static class SharedElementCallback23Impl extends SharedElementCallback21Impl {
- public SharedElementCallback23Impl(SharedElementCallback callback) {
+ SharedElementCallback23Impl(SharedElementCallback callback) {
super(callback);
}
diff --git a/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java b/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java
index 7099cb9..8ddb5c3 100644
--- a/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java
+++ b/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java
@@ -317,7 +317,7 @@
new HashMap<ComponentName, ListenerRecord>();
private Set<String> mCachedEnabledPackages = new HashSet<String>();
- public SideChannelManager(Context context) {
+ SideChannelManager(Context context) {
mContext = context;
mHandlerThread = new HandlerThread("NotificationManagerCompat");
mHandlerThread.start();
@@ -554,17 +554,17 @@
/** A per-side-channel-service listener state record */
private static class ListenerRecord {
- public final ComponentName componentName;
+ final ComponentName componentName;
/** Whether the service is currently bound to. */
- public boolean bound = false;
+ boolean bound = false;
/** The service stub provided by onServiceConnected */
- public INotificationSideChannel service;
+ INotificationSideChannel service;
/** Queue of pending tasks to send to this listener service */
- public ArrayDeque<Task> taskQueue = new ArrayDeque<>();
+ ArrayDeque<Task> taskQueue = new ArrayDeque<>();
/** Number of retries attempted while connecting to this listener service */
- public int retryCount = 0;
+ int retryCount = 0;
- public ListenerRecord(ComponentName componentName) {
+ ListenerRecord(ComponentName componentName) {
this.componentName = componentName;
}
}
diff --git a/compat/src/main/java/android/support/v4/content/ContextCompat.java b/compat/src/main/java/android/support/v4/content/ContextCompat.java
index 8a4fd7a..6aba339 100644
--- a/compat/src/main/java/android/support/v4/content/ContextCompat.java
+++ b/compat/src/main/java/android/support/v4/content/ContextCompat.java
@@ -353,7 +353,7 @@
* @return Drawable An object that can be used to draw this resource.
*/
@Nullable
- public static final Drawable getDrawable(@NonNull Context context, @DrawableRes int id) {
+ public static Drawable getDrawable(@NonNull Context context, @DrawableRes int id) {
if (Build.VERSION.SDK_INT >= 21) {
return context.getDrawable(id);
} else if (Build.VERSION.SDK_INT >= 16) {
@@ -390,7 +390,7 @@
* does not exist.
*/
@Nullable
- public static final ColorStateList getColorStateList(@NonNull Context context,
+ public static ColorStateList getColorStateList(@NonNull Context context,
@ColorRes int id) {
if (Build.VERSION.SDK_INT >= 23) {
return context.getColorStateList(id);
@@ -413,7 +413,7 @@
* does not exist.
*/
@ColorInt
- public static final int getColor(@NonNull Context context, @ColorRes int id) {
+ public static int getColor(@NonNull Context context, @ColorRes int id) {
if (Build.VERSION.SDK_INT >= 23) {
return context.getColor(id);
} else {
@@ -454,7 +454,7 @@
* @see android.content.Context#getFilesDir()
*/
@Nullable
- public static final File getNoBackupFilesDir(@NonNull Context context) {
+ public static File getNoBackupFilesDir(@NonNull Context context) {
if (Build.VERSION.SDK_INT >= 21) {
return context.getNoBackupFilesDir();
} else {
diff --git a/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java b/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
index 39acf68..7fff1d0 100644
--- a/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
+++ b/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
@@ -220,7 +220,7 @@
* @hide
**/
@RestrictTo(LIBRARY_GROUP)
- public static final void resetCache() {
+ public static void resetCache() {
sTypefaceCache.evictAll();
}
diff --git a/compat/src/main/java/android/support/v4/text/TextDirectionHeuristicsCompat.java b/compat/src/main/java/android/support/v4/text/TextDirectionHeuristicsCompat.java
index d55ae8a..10c6b76 100644
--- a/compat/src/main/java/android/support/v4/text/TextDirectionHeuristicsCompat.java
+++ b/compat/src/main/java/android/support/v4/text/TextDirectionHeuristicsCompat.java
@@ -111,7 +111,7 @@
private static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristicCompat {
private final TextDirectionAlgorithm mAlgorithm;
- public TextDirectionHeuristicImpl(TextDirectionAlgorithm algorithm) {
+ TextDirectionHeuristicImpl(TextDirectionAlgorithm algorithm) {
mAlgorithm = algorithm;
}
@@ -166,7 +166,7 @@
/**
* Interface for an algorithm to guess the direction of a paragraph of text.
*/
- private static interface TextDirectionAlgorithm {
+ private interface TextDirectionAlgorithm {
/**
* Returns whether the range of text is RTL according to the algorithm.
*/
@@ -190,7 +190,7 @@
private FirstStrong() {
}
- public static final FirstStrong INSTANCE = new FirstStrong();
+ static final FirstStrong INSTANCE = new FirstStrong();
}
/**
@@ -232,8 +232,8 @@
this.mLookForRtl = lookForRtl;
}
- public static final AnyStrong INSTANCE_RTL = new AnyStrong(true);
- public static final AnyStrong INSTANCE_LTR = new AnyStrong(false);
+ static final AnyStrong INSTANCE_RTL = new AnyStrong(true);
+ static final AnyStrong INSTANCE_LTR = new AnyStrong(false);
}
/**
@@ -241,7 +241,7 @@
*/
private static class TextDirectionHeuristicLocale extends TextDirectionHeuristicImpl {
- public TextDirectionHeuristicLocale() {
+ TextDirectionHeuristicLocale() {
super(null);
}
@@ -251,7 +251,7 @@
return (dir == ViewCompat.LAYOUT_DIRECTION_RTL);
}
- public static final TextDirectionHeuristicLocale INSTANCE =
+ static final TextDirectionHeuristicLocale INSTANCE =
new TextDirectionHeuristicLocale();
}
diff --git a/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java b/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java
index b7bf352..efd4c85 100644
--- a/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java
+++ b/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java
@@ -56,7 +56,7 @@
private static final Comparator<LinkSpec> COMPARATOR = new Comparator<LinkSpec>() {
@Override
- public final int compare(LinkSpec a, LinkSpec b) {
+ public int compare(LinkSpec a, LinkSpec b) {
if (a.start < b.start) {
return -1;
}
@@ -96,7 +96,7 @@
*
* @return True if at least one link is found and applied.
*/
- public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
+ public static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
if (Build.VERSION.SDK_INT >= 27) {
return Linkify.addLinks(text, mask);
}
@@ -160,7 +160,7 @@
*
* @return True if at least one link is found and applied.
*/
- public static final boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
+ public static boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
if (Build.VERSION.SDK_INT >= 26) {
return Linkify.addLinks(text, mask);
}
@@ -202,7 +202,7 @@
* @param scheme URL scheme string (eg <code>http://</code>) to be
* prepended to the links that do not start with this scheme.
*/
- public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
+ public static void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
@Nullable String scheme) {
if (Build.VERSION.SDK_INT >= 26) {
Linkify.addLinks(text, pattern, scheme);
@@ -225,7 +225,7 @@
* additional control over which pattern matches are
* to be converted into links.
*/
- public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
+ public static void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
@Nullable String scheme, @Nullable MatchFilter matchFilter,
@Nullable TransformFilter transformFilter) {
if (Build.VERSION.SDK_INT >= 26) {
@@ -252,7 +252,7 @@
* over which pattern matches are to be converted into links.
* @param transformFilter Filter to allow the client code to update the link found.
*/
- public static final void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
+ public static void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
@Nullable String defaultScheme, @Nullable String[] schemes,
@Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
if (Build.VERSION.SDK_INT >= 26) {
@@ -278,7 +278,7 @@
* @param scheme URL scheme string (eg <code>http://</code>) to be
* prepended to the links that do not start with this scheme.
*/
- public static final boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern,
+ public static boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern,
@Nullable String scheme) {
if (Build.VERSION.SDK_INT >= 26) {
return Linkify.addLinks(text, pattern, scheme);
@@ -301,7 +301,7 @@
*
* @return True if at least one link is found and applied.
*/
- public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
+ public static boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
@Nullable String scheme, @Nullable MatchFilter matchFilter,
@Nullable TransformFilter transformFilter) {
if (Build.VERSION.SDK_INT >= 26) {
@@ -327,7 +327,7 @@
*
* @return True if at least one link is found and applied.
*/
- public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
+ public static boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
@Nullable String defaultScheme, @Nullable String[] schemes,
@Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
if (Build.VERSION.SDK_INT >= 26) {
@@ -436,7 +436,7 @@
text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- private static final void gatherMapLinks(ArrayList<LinkSpec> links, Spannable s) {
+ private static void gatherMapLinks(ArrayList<LinkSpec> links, Spannable s) {
String string = s.toString();
String address;
int base = 0;
@@ -477,7 +477,7 @@
}
}
- private static final void pruneOverlaps(ArrayList<LinkSpec> links, Spannable text) {
+ private static void pruneOverlaps(ArrayList<LinkSpec> links, Spannable text) {
// Append spans added by framework
URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
for (int i = 0; i < urlSpans.length; i++) {
diff --git a/compat/src/main/java/android/support/v4/util/MapCollections.java b/compat/src/main/java/android/support/v4/util/MapCollections.java
index 1a0ab6b..f20b098 100644
--- a/compat/src/main/java/android/support/v4/util/MapCollections.java
+++ b/compat/src/main/java/android/support/v4/util/MapCollections.java
@@ -131,7 +131,7 @@
}
@Override
- public final boolean equals(Object o) {
+ public boolean equals(Object o) {
if (!mEntryValid) {
throw new IllegalStateException(
"This container does not support retaining Map.Entry objects");
@@ -145,7 +145,7 @@
}
@Override
- public final int hashCode() {
+ public int hashCode() {
if (!mEntryValid) {
throw new IllegalStateException(
"This container does not support retaining Map.Entry objects");
@@ -157,7 +157,7 @@
}
@Override
- public final String toString() {
+ public String toString() {
return getKey() + "=" + getValue();
}
}
diff --git a/compat/src/main/java/android/support/v4/util/Pools.java b/compat/src/main/java/android/support/v4/util/Pools.java
index 99fd888..678663a 100644
--- a/compat/src/main/java/android/support/v4/util/Pools.java
+++ b/compat/src/main/java/android/support/v4/util/Pools.java
@@ -51,13 +51,13 @@
*
* @param <T> The pooled type.
*/
- public static interface Pool<T> {
+ public interface Pool<T> {
/**
* @return An instance from the pool if such, null otherwise.
*/
@Nullable
- public T acquire();
+ T acquire();
/**
* Release an instance to the pool.
@@ -67,7 +67,7 @@
*
* @throws IllegalStateException If the instance is already in the pool.
*/
- public boolean release(@NonNull T instance);
+ boolean release(@NonNull T instance);
}
private Pools() {
diff --git a/compat/src/main/java/android/support/v4/view/ActionProvider.java b/compat/src/main/java/android/support/v4/view/ActionProvider.java
index e6ffd98..fd82740 100644
--- a/compat/src/main/java/android/support/v4/view/ActionProvider.java
+++ b/compat/src/main/java/android/support/v4/view/ActionProvider.java
@@ -318,7 +318,7 @@
@RestrictTo(LIBRARY_GROUP)
public interface SubUiVisibilityListener {
- public void onSubUiVisibilityChanged(boolean isVisible);
+ void onSubUiVisibilityChanged(boolean isVisible);
}
/**
@@ -328,6 +328,6 @@
* @see ActionProvider#isVisible()
*/
public interface VisibilityListener {
- public void onActionProviderVisibilityChanged(boolean isVisible);
+ void onActionProviderVisibilityChanged(boolean isVisible);
}
}
diff --git a/compat/src/main/java/android/support/v4/view/GestureDetectorCompat.java b/compat/src/main/java/android/support/v4/view/GestureDetectorCompat.java
index fbecce9..4bf2446 100644
--- a/compat/src/main/java/android/support/v4/view/GestureDetectorCompat.java
+++ b/compat/src/main/java/android/support/v4/view/GestureDetectorCompat.java
@@ -148,7 +148,7 @@
*
* @throws NullPointerException if {@code listener} is null.
*/
- public GestureDetectorCompatImplBase(Context context, OnGestureListener listener,
+ GestureDetectorCompatImplBase(Context context, OnGestureListener listener,
Handler handler) {
if (handler != null) {
mHandler = new GestureHandler(handler);
@@ -465,7 +465,7 @@
static class GestureDetectorCompatImplJellybeanMr2 implements GestureDetectorCompatImpl {
private final GestureDetector mDetector;
- public GestureDetectorCompatImplJellybeanMr2(Context context, OnGestureListener listener,
+ GestureDetectorCompatImplJellybeanMr2(Context context, OnGestureListener listener,
Handler handler) {
mDetector = new GestureDetector(context, listener, handler);
}
diff --git a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
index fe26b6e..0822d01 100644
--- a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
+++ b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
@@ -50,7 +50,7 @@
private MatchFilter mMatchFilterStartWithDot = new MatchFilter() {
@Override
- public final boolean acceptMatch(final CharSequence s, final int start, final int end) {
+ public boolean acceptMatch(final CharSequence s, final int start, final int end) {
if (start == 0) {
return true;
}
@@ -65,7 +65,7 @@
private TransformFilter mTransformFilterUpperChar = new TransformFilter() {
@Override
- public final String transformUrl(final Matcher match, String url) {
+ public String transformUrl(final Matcher match, String url) {
StringBuilder buffer = new StringBuilder();
String matchingRegion = match.group();
diff --git a/compat/tests/java/android/support/v4/widget/TextViewCompatTest.java b/compat/tests/java/android/support/v4/widget/TextViewCompatTest.java
index cf2b52f..42cf80e 100644
--- a/compat/tests/java/android/support/v4/widget/TextViewCompatTest.java
+++ b/compat/tests/java/android/support/v4/widget/TextViewCompatTest.java
@@ -78,7 +78,7 @@
private int mWidth;
private int mHeight;
- public TestDrawable(@ColorInt int color, int width, int height) {
+ TestDrawable(@ColorInt int color, int width, int height) {
super(color);
mWidth = width;
mHeight = height;
diff --git a/core-ui/api/current.txt b/core-ui/api/current.txt
index 77e805d..cdc1830 100644
--- a/core-ui/api/current.txt
+++ b/core-ui/api/current.txt
@@ -379,10 +379,10 @@
public class ContentLoadingProgressBar extends android.widget.ProgressBar {
ctor public ContentLoadingProgressBar(android.content.Context);
ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet);
- method public void hide();
+ method public synchronized void hide();
method public void onAttachedToWindow();
method public void onDetachedFromWindow();
- method public void show();
+ method public synchronized void show();
}
public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
diff --git a/core-ui/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java b/core-ui/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java
index c234177..98769e6 100644
--- a/core-ui/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java
+++ b/core-ui/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java
@@ -27,7 +27,7 @@
private final float[] mValues;
private final float mStepSize;
- public LookupTableInterpolator(float[] values) {
+ protected LookupTableInterpolator(float[] values) {
mValues = values;
mStepSize = 1f / (mValues.length - 1);
}
diff --git a/core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java b/core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
index ca04e46..5e10f51 100644
--- a/core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -418,12 +418,7 @@
private void startScaleUpAnimation(AnimationListener listener) {
mCircleView.setVisibility(View.VISIBLE);
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- // Pre API 11, alpha is used in place of scale up to show the
- // progress circle appearing.
- // Don't adjust the alpha during appearance otherwise.
- mProgress.setAlpha(MAX_ALPHA);
- }
+ mProgress.setAlpha(MAX_ALPHA);
mScaleAnimation = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
diff --git a/core-ui/tests/java/android/support/v4/view/ViewPagerActions.java b/core-ui/tests/java/android/support/v4/view/ViewPagerActions.java
index 7e175dd..4c42d72 100644
--- a/core-ui/tests/java/android/support/v4/view/ViewPagerActions.java
+++ b/core-ui/tests/java/android/support/v4/view/ViewPagerActions.java
@@ -109,7 +109,7 @@
}
@Override
- public final void perform(UiController uiController, View view) {
+ public void perform(UiController uiController, View view) {
final ViewPager viewPager = (ViewPager) view;
// Add a custom tracker listener
final CustomViewPagerListener customListener = new CustomViewPagerListener();
diff --git a/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTest.java b/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTest.java
index 83c1dc1..d78b49b 100644
--- a/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTest.java
+++ b/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTest.java
@@ -115,7 +115,7 @@
private static class ParentBoundsHelper extends ExploreByTouchHelper {
private final View mHost;
- public ParentBoundsHelper(View host) {
+ ParentBoundsHelper(View host) {
super(host);
mHost = host;
diff --git a/core-utils/java/android/support/v4/content/FileProvider.java b/core-utils/java/android/support/v4/content/FileProvider.java
index 16164be..ca22407 100644
--- a/core-utils/java/android/support/v4/content/FileProvider.java
+++ b/core-utils/java/android/support/v4/content/FileProvider.java
@@ -669,12 +669,12 @@
/**
* Return a {@link Uri} that represents the given {@link File}.
*/
- public Uri getUriForFile(File file);
+ Uri getUriForFile(File file);
/**
* Return a {@link File} that represents the given {@link Uri}.
*/
- public File getFileForUri(Uri uri);
+ File getFileForUri(Uri uri);
}
/**
@@ -691,7 +691,7 @@
private final String mAuthority;
private final HashMap<String, File> mRoots = new HashMap<String, File>();
- public SimplePathStrategy(String authority) {
+ SimplePathStrategy(String authority) {
mAuthority = authority;
}
@@ -699,7 +699,7 @@
* Add a mapping from a name to a filesystem root. The provider only offers
* access to files that live under configured roots.
*/
- public void addRoot(String name, File root) {
+ void addRoot(String name, File root) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("Name must not be empty");
}
diff --git a/development/checkstyle/config/support-lib.xml b/development/checkstyle/config/support-lib.xml
index 43bbb82..e664be3 100644
--- a/development/checkstyle/config/support-lib.xml
+++ b/development/checkstyle/config/support-lib.xml
@@ -28,6 +28,8 @@
&defaultJavadocChecks;
&defaultTreewalkerChecks;
+ <module name="RedundantModifierCheck" />
+
<!-- Custom support library check for @RestrictTo / @hide. -->
<module name="com.android.support.checkstyle.MismatchedAnnotationCheck">
<property name="severity" value="error" />
diff --git a/fragment/api/current.txt b/fragment/api/current.txt
index c3fc2ea..e052a0b 100644
--- a/fragment/api/current.txt
+++ b/fragment/api/current.txt
@@ -178,7 +178,7 @@
public class FragmentController {
method public void attachHost(android.support.v4.app.Fragment);
- method public static final android.support.v4.app.FragmentController createController(android.support.v4.app.FragmentHostCallback<?>);
+ method public static android.support.v4.app.FragmentController createController(android.support.v4.app.FragmentHostCallback<?>);
method public void dispatchActivityCreated();
method public void dispatchConfigurationChanged(android.content.res.Configuration);
method public boolean dispatchContextItemSelected(android.view.MenuItem);
diff --git a/fragment/src/androidTest/java/android/support/v4/app/FragmentAnimationTest.java b/fragment/src/androidTest/java/android/support/v4/app/FragmentAnimationTest.java
index 8c3d6ed..4966316 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/FragmentAnimationTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/FragmentAnimationTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertTrue;
import android.app.Instrumentation;
+import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.AnimRes;
import android.support.fragment.test.R;
@@ -32,8 +33,11 @@
import android.support.v4.app.test.FragmentTestActivity;
import android.support.v4.view.ViewCompat;
import android.util.Pair;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
import android.view.animation.TranslateAnimation;
import org.junit.Before;
@@ -41,6 +45,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
@MediumTest
@RunWith(AndroidJUnit4.class)
public class FragmentAnimationTest {
@@ -442,6 +449,54 @@
});
}
+ // When a view is animated out, is parent should be null after the animation completes
+ @Test
+ public void parentNullAfterAnimation() throws Throwable {
+ final FragmentManager fm = mActivityRule.getActivity().getSupportFragmentManager();
+
+ final EndAnimationListenerFragment fragment1 = new EndAnimationListenerFragment();
+ fm.beginTransaction()
+ .add(R.id.fragmentContainer, fragment1)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ final EndAnimationListenerFragment fragment2 = new EndAnimationListenerFragment();
+
+ fm.beginTransaction()
+ .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out,
+ android.R.anim.fade_in, android.R.anim.fade_out)
+ .replace(R.id.fragmentContainer, fragment2)
+ .addToBackStack(null)
+ .commit();
+
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ assertTrue(fragment1.exitLatch.await(1, TimeUnit.SECONDS));
+ assertTrue(fragment2.enterLatch.await(1, TimeUnit.SECONDS));
+
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertNotNull(fragment1.view);
+ assertNotNull(fragment2.view);
+ assertNull(fragment1.view.getParent());
+ }
+ });
+
+ // Now pop the transaction
+ FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+ assertTrue(fragment2.exitLatch.await(1, TimeUnit.SECONDS));
+ assertTrue(fragment1.enterLatch.await(1, TimeUnit.SECONDS));
+
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertNull(fragment2.view.getParent());
+ }
+ });
+ }
+
private void assertEnterPopExit(AnimatorFragment fragment) throws Throwable {
assertFragmentAnimation(fragment, 1, true, ENTER);
@@ -516,4 +571,50 @@
return this.animation;
}
}
+
+ public static class EndAnimationListenerFragment extends StrictViewFragment {
+ public View view;
+ public final CountDownLatch enterLatch = new CountDownLatch(1);
+ public final CountDownLatch exitLatch = new CountDownLatch(1);
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ if (view != null) {
+ return view;
+ }
+ view = super.onCreateView(inflater, container, savedInstanceState);
+ return view;
+ }
+
+ @Override
+ public Animation onCreateAnimation(int transit, final boolean enter, int nextAnim) {
+ if (nextAnim == 0) {
+ return null;
+ }
+ Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);
+ if (anim != null) {
+ anim.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (enter) {
+ enterLatch.countDown();
+ } else {
+ exitLatch.countDown();
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+
+ }
+ });
+ }
+ return anim;
+ }
+ }
}
diff --git a/fragment/src/main/java/android/support/v4/app/FragmentController.java b/fragment/src/main/java/android/support/v4/app/FragmentController.java
index 48b3602..2dfb6b0 100644
--- a/fragment/src/main/java/android/support/v4/app/FragmentController.java
+++ b/fragment/src/main/java/android/support/v4/app/FragmentController.java
@@ -43,7 +43,7 @@
/**
* Returns a {@link FragmentController}.
*/
- public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
+ public static FragmentController createController(FragmentHostCallback<?> callbacks) {
return new FragmentController(callbacks);
}
diff --git a/fragment/src/main/java/android/support/v4/app/FragmentManager.java b/fragment/src/main/java/android/support/v4/app/FragmentManager.java
index 16103f8..56040b2 100644
--- a/fragment/src/main/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/src/main/java/android/support/v4/app/FragmentManager.java
@@ -61,6 +61,7 @@
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.ScaleAnimation;
+import android.view.animation.Transformation;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1504,8 +1505,8 @@
dispatchOnFragmentViewDestroyed(f, false);
if (f.mView != null && f.mContainer != null) {
// Stop any current animations:
- f.mView.clearAnimation();
f.mContainer.endViewTransition(f.mView);
+ f.mView.clearAnimation();
AnimationOrAnimator anim = null;
if (mCurState > Fragment.INITIALIZING && !mDestroyed
&& f.mView.getVisibility() == View.VISIBLE
@@ -1598,21 +1599,21 @@
container.startViewTransition(viewToAnimate);
fragment.setStateAfterAnimating(newState);
if (anim.animation != null) {
- Animation animation = anim.animation;
+ Animation animation =
+ new EndViewTransitionAnimator(anim.animation, container, viewToAnimate);
fragment.setAnimatingAway(fragment.mView);
AnimationListener listener = getAnimationListener(animation);
animation.setAnimationListener(new AnimationListenerWrapper(listener) {
@Override
public void onAnimationEnd(Animation animation) {
super.onAnimationEnd(animation);
+
// onAnimationEnd() comes during draw(), so there can still be some
// draw events happening after this call. We don't want to detach
// the view until after the onAnimationEnd()
container.post(new Runnable() {
@Override
public void run() {
- container.endViewTransition(viewToAnimate);
-
if (fragment.getAnimatingAway() != null) {
fragment.setAnimatingAway(null);
moveToState(fragment, fragment.getStateAfterAnimating(), 0, 0,
@@ -4003,4 +4004,58 @@
animation.removeListener(this);
}
}
+
+ /**
+ * We must call endViewTransition() before the animation ends or else the parent doesn't
+ * get nulled out. We use both startViewTransition() and startAnimation() to solve a problem
+ * with Views remaining in the hierarchy as disappearing children after the view has been
+ * removed in some edge cases.
+ */
+ private static class EndViewTransitionAnimator extends AnimationSet implements Runnable {
+ private final ViewGroup mParent;
+ private final View mChild;
+ private boolean mEnded;
+ private boolean mTransitionEnded;
+
+ EndViewTransitionAnimator(@NonNull Animation animation,
+ @NonNull ViewGroup parent, @NonNull View child) {
+ super(false);
+ mParent = parent;
+ mChild = child;
+ addAnimation(animation);
+ }
+
+ @Override
+ public boolean getTransformation(long currentTime, Transformation t) {
+ if (mEnded) {
+ return !mTransitionEnded;
+ }
+ boolean more = super.getTransformation(currentTime, t);
+ if (!more) {
+ mEnded = true;
+ mParent.post(this);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean getTransformation(long currentTime, Transformation outTransformation,
+ float scale) {
+ if (mEnded) {
+ return !mTransitionEnded;
+ }
+ boolean more = super.getTransformation(currentTime, outTransformation, scale);
+ if (!more) {
+ mEnded = true;
+ mParent.post(this);
+ }
+ return true;
+ }
+
+ @Override
+ public void run() {
+ mParent.endViewTransition(mChild);
+ mTransitionEnded = true;
+ }
+ }
}
diff --git a/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java
index 943f1aa..a47cf59 100644
--- a/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -651,11 +651,7 @@
case 15:
return Mode.SCREEN;
case 16:
- if (Build.VERSION.SDK_INT >= 11) {
- return Mode.ADD;
- } else {
- return defaultMode;
- }
+ return Mode.ADD;
default:
return defaultMode;
}
diff --git a/leanback/api/current.txt b/leanback/api/current.txt
index b045d8f..56a8f1a 100644
--- a/leanback/api/current.txt
+++ b/leanback/api/current.txt
@@ -1895,7 +1895,7 @@
ctor public GuidedActionDiffCallback();
method public boolean areContentsTheSame(android.support.v17.leanback.widget.GuidedAction, android.support.v17.leanback.widget.GuidedAction);
method public boolean areItemsTheSame(android.support.v17.leanback.widget.GuidedAction, android.support.v17.leanback.widget.GuidedAction);
- method public static final android.support.v17.leanback.widget.GuidedActionDiffCallback getInstance();
+ method public static android.support.v17.leanback.widget.GuidedActionDiffCallback getInstance();
}
public class GuidedActionEditText extends android.widget.EditText implements android.support.v17.leanback.widget.ImeKeyMonitor {
diff --git a/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java b/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
index 9be350d..1c52946 100644
--- a/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
+++ b/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
@@ -1199,7 +1199,7 @@
return EXTRA_BUTTON_ACTION_PREFIX + action.getId();
}
- final static boolean isSaveEnabled(GuidedAction action) {
+ static boolean isSaveEnabled(GuidedAction action) {
return action.isAutoSaveRestoreEnabled() && action.getId() != GuidedAction.NO_ID;
}
diff --git a/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java b/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
index e276d07..ce48b3c 100644
--- a/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
+++ b/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
@@ -1194,7 +1194,7 @@
return EXTRA_BUTTON_ACTION_PREFIX + action.getId();
}
- final static boolean isSaveEnabled(GuidedAction action) {
+ static boolean isSaveEnabled(GuidedAction action) {
return action.isAutoSaveRestoreEnabled() && action.getId() != GuidedAction.NO_ID;
}
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedAction.java b/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
index 8898d48..a0c198d 100644
--- a/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
+++ b/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
@@ -938,7 +938,7 @@
}
}
- final static boolean isPasswordVariant(int inputType) {
+ static boolean isPasswordVariant(int inputType) {
final int variation = inputType & InputType.TYPE_MASK_VARIATION;
return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
|| variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedActionDiffCallback.java b/leanback/src/android/support/v17/leanback/widget/GuidedActionDiffCallback.java
index d4d4d77..0894720 100644
--- a/leanback/src/android/support/v17/leanback/widget/GuidedActionDiffCallback.java
+++ b/leanback/src/android/support/v17/leanback/widget/GuidedActionDiffCallback.java
@@ -30,7 +30,7 @@
* Returns the singleton GuidedActionDiffCallback.
* @return The singleton GuidedActionDiffCallback.
*/
- public static final GuidedActionDiffCallback getInstance() {
+ public static GuidedActionDiffCallback getInstance() {
return sInstance;
}
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java b/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
index 75769f5..4d4a1eb 100644
--- a/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
+++ b/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
@@ -43,7 +43,7 @@
import android.support.v17.leanback.widget.ListRowPresenter;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowHeaderPresenter;
+import android.support.v17.leanback.widget.RowPresenter;
import android.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
@@ -115,6 +115,7 @@
public void testTouchMode() throws Throwable {
Intent intent = new Intent();
intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
+ intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY , 0L);
mActivity = activityTestRule.launchActivity(intent);
waitForEntranceTransitionFinished();
@@ -134,7 +135,7 @@
@Test
public void testTwoBackKeysWithBackStack() throws Throwable {
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
Intent intent = new Intent();
intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
@@ -150,7 +151,7 @@
@Test
public void testTwoBackKeysWithoutBackStack() throws Throwable {
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
Intent intent = new Intent();
intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
@@ -207,13 +208,18 @@
@Test
public void testPressCenterBeforeMainFragmentCreated() throws Throwable {
Intent intent = new Intent();
- intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, 0);
+ intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, 0L);
mActivity = activityTestRule.launchActivity(intent);
final BrowseFragment fragment = mActivity.getBrowseTestFragment();
fragment.getMainFragmentRegistry().registerFragment(MyRow.class, new MyFragmentFactory());
- final ArrayObjectAdapter adapter = new ArrayObjectAdapter(new RowHeaderPresenter());
+ final ArrayObjectAdapter adapter = new ArrayObjectAdapter(new RowPresenter() {
+ protected ViewHolder createRowViewHolder(ViewGroup parent) {
+ View view = new FrameLayout(parent.getContext());
+ return new RowPresenter.ViewHolder(view);
+ }
+ });
adapter.add(new MyRow());
activityTestRule.runOnUiThread(new Runnable() {
@Override
@@ -238,7 +244,7 @@
final int selectRow = 10;
final int selectItem = 20;
Intent intent = new Intent();
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
mActivity = activityTestRule.launchActivity(intent);
@@ -275,7 +281,7 @@
@Test
public void activityRecreate_notCrash() throws Throwable {
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
Intent intent = new Intent();
intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
@@ -296,7 +302,7 @@
@Test
public void lateLoadingHeaderDisabled() throws Throwable {
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
Intent intent = new Intent();
intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseFragmentTestActivity.EXTRA_HEADERS_STATE,
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java b/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
index de94551..2011b8e 100644
--- a/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
+++ b/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
@@ -40,7 +40,7 @@
import android.support.v17.leanback.widget.ListRowPresenter;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowHeaderPresenter;
+import android.support.v17.leanback.widget.RowPresenter;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
@@ -112,6 +112,7 @@
public void testTouchMode() throws Throwable {
Intent intent = new Intent();
intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
+ intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY , 0L);
mActivity = activityTestRule.launchActivity(intent);
waitForEntranceTransitionFinished();
@@ -131,7 +132,7 @@
@Test
public void testTwoBackKeysWithBackStack() throws Throwable {
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
Intent intent = new Intent();
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
@@ -147,7 +148,7 @@
@Test
public void testTwoBackKeysWithoutBackStack() throws Throwable {
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
Intent intent = new Intent();
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
@@ -204,13 +205,18 @@
@Test
public void testPressCenterBeforeMainFragmentCreated() throws Throwable {
Intent intent = new Intent();
- intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, 0);
+ intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, 0L);
mActivity = activityTestRule.launchActivity(intent);
final BrowseSupportFragment fragment = mActivity.getBrowseTestSupportFragment();
fragment.getMainFragmentRegistry().registerFragment(MyRow.class, new MyFragmentFactory());
- final ArrayObjectAdapter adapter = new ArrayObjectAdapter(new RowHeaderPresenter());
+ final ArrayObjectAdapter adapter = new ArrayObjectAdapter(new RowPresenter() {
+ protected ViewHolder createRowViewHolder(ViewGroup parent) {
+ View view = new FrameLayout(parent.getContext());
+ return new RowPresenter.ViewHolder(view);
+ }
+ });
adapter.add(new MyRow());
activityTestRule.runOnUiThread(new Runnable() {
@Override
@@ -235,7 +241,7 @@
final int selectRow = 10;
final int selectItem = 20;
Intent intent = new Intent();
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
mActivity = activityTestRule.launchActivity(intent);
@@ -272,7 +278,7 @@
@Test
public void activityRecreate_notCrash() throws Throwable {
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
Intent intent = new Intent();
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
@@ -293,7 +299,7 @@
@Test
public void lateLoadingHeaderDisabled() throws Throwable {
- final long dataLoadingDelay = 1000;
+ final long dataLoadingDelay = 0L;
Intent intent = new Intent();
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, dataLoadingDelay);
intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_HEADERS_STATE,
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java b/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
index 6a34c53..74fe87a 100644
--- a/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
+++ b/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
@@ -95,9 +95,7 @@
@Override
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
- Log.i(TAG, "onItemSelected: " + item + " row " + row.getHeaderItem().getName()
- + " " + rowViewHolder
- + " " + ((ListRowPresenter.ViewHolder) rowViewHolder).getGridView());
+ Log.i(TAG, "onItemSelected: " + item + " row " + row);
}
});
if (TEST_ENTRANCE_TRANSITION) {
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java b/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
index 373d7a3..0986f0d 100644
--- a/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
+++ b/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
@@ -92,9 +92,7 @@
@Override
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
- Log.i(TAG, "onItemSelected: " + item + " row " + row.getHeaderItem().getName()
- + " " + rowViewHolder
- + " " + ((ListRowPresenter.ViewHolder) rowViewHolder).getGridView());
+ Log.i(TAG, "onItemSelected: " + item + " row " + row);
}
});
if (TEST_ENTRANCE_TRANSITION) {
diff --git a/lifecycle/common/src/test/java/android/arch/lifecycle/ReflectiveGenericLifecycleObserverTest.java b/lifecycle/common/src/test/java/android/arch/lifecycle/ReflectiveGenericLifecycleObserverTest.java
index 68f04e8..23aed28 100644
--- a/lifecycle/common/src/test/java/android/arch/lifecycle/ReflectiveGenericLifecycleObserverTest.java
+++ b/lifecycle/common/src/test/java/android/arch/lifecycle/ReflectiveGenericLifecycleObserverTest.java
@@ -30,6 +30,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -185,6 +186,7 @@
ReflectiveGenericLifecycleObserver observer = new ReflectiveGenericLifecycleObserver(obj);
try {
observer.onStateChanged(mOwner, ON_START);
+ fail();
} catch (Exception e) {
assertThat("exception cause is wrong",
e.getCause() instanceof UnprecedentedError);
@@ -247,13 +249,14 @@
new ReflectiveGenericLifecycleObserver(observer);
}
- class BaseClass1 implements LifecycleObserver {
+ static class BaseClass1 implements LifecycleObserver {
@OnLifecycleEvent(ON_START)
void foo(LifecycleOwner owner) {
}
}
- class DerivedClass1 extends BaseClass1 {
+ static class DerivedClass1 extends BaseClass1 {
+ @Override
@OnLifecycleEvent(ON_STOP)
void foo(LifecycleOwner owner) {
}
@@ -264,13 +267,13 @@
new ReflectiveGenericLifecycleObserver(new DerivedClass1());
}
- class BaseClass2 implements LifecycleObserver {
+ static class BaseClass2 implements LifecycleObserver {
@OnLifecycleEvent(ON_START)
void foo(LifecycleOwner owner) {
}
}
- class DerivedClass2 extends BaseClass1 {
+ static class DerivedClass2 extends BaseClass1 {
@OnLifecycleEvent(ON_STOP)
void foo() {
}
@@ -289,7 +292,7 @@
verify(obj, never()).foo(Matchers.<LifecycleOwner>any());
}
- class BaseClass3 implements LifecycleObserver {
+ static class BaseClass3 implements LifecycleObserver {
@OnLifecycleEvent(ON_START)
void foo(LifecycleOwner owner) {
}
@@ -300,7 +303,7 @@
void foo(LifecycleOwner owner);
}
- class DerivedClass3 extends BaseClass3 implements Interface3 {
+ static class DerivedClass3 extends BaseClass3 implements Interface3 {
@Override
public void foo(LifecycleOwner owner) {
}
@@ -311,7 +314,7 @@
new ReflectiveGenericLifecycleObserver(new DerivedClass3());
}
- class BaseClass4 implements LifecycleObserver {
+ static class BaseClass4 implements LifecycleObserver {
@OnLifecycleEvent(ON_START)
void foo(LifecycleOwner owner) {
}
@@ -322,7 +325,7 @@
void foo(LifecycleOwner owner);
}
- class DerivedClass4 extends BaseClass4 implements Interface4 {
+ static class DerivedClass4 extends BaseClass4 implements Interface4 {
@Override
@OnLifecycleEvent(ON_START)
public void foo(LifecycleOwner owner) {
@@ -352,7 +355,7 @@
void foo(LifecycleOwner owner);
}
- class DerivedClass5 implements InterfaceStart, InterfaceStop {
+ static class DerivedClass5 implements InterfaceStart, InterfaceStop {
@Override
public void foo(LifecycleOwner owner) {
}
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
index 675c0fc..ca44a9a 100644
--- a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
+++ b/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
@@ -37,13 +37,13 @@
@RunWith(AndroidJUnit4.class)
public class AudioAttributesCompatTest {
// some macros for conciseness
- static final AudioAttributesCompat.Builder mkBuilder(
+ static AudioAttributesCompat.Builder mkBuilder(
@AudioAttributesCompat.AttributeContentType int type,
@AudioAttributesCompat.AttributeUsage int usage) {
return new AudioAttributesCompat.Builder().setContentType(type).setUsage(usage);
}
- static final AudioAttributesCompat.Builder mkBuilder(int legacyStream) {
+ static AudioAttributesCompat.Builder mkBuilder(int legacyStream) {
return new AudioAttributesCompat.Builder().setLegacyStreamType(legacyStream);
}
diff --git a/recyclerview-selection/src/main/java/androidx/widget/recyclerview/selection/FocusDelegate.java b/recyclerview-selection/src/main/java/androidx/widget/recyclerview/selection/FocusDelegate.java
index 1ecfcc4..c1b5fa0 100644
--- a/recyclerview-selection/src/main/java/androidx/widget/recyclerview/selection/FocusDelegate.java
+++ b/recyclerview-selection/src/main/java/androidx/widget/recyclerview/selection/FocusDelegate.java
@@ -29,7 +29,7 @@
*/
public abstract class FocusDelegate<K> {
- static final <K> FocusDelegate<K> dummy() {
+ static <K> FocusDelegate<K> dummy() {
return new FocusDelegate<K>() {
@Override
public void focusItem(@NonNull ItemDetails<K> item) {
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/media/LocalPlayer.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/media/LocalPlayer.java
index 03f3318..133f4ea 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/media/LocalPlayer.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/media/LocalPlayer.java
@@ -375,7 +375,7 @@
}
private static final class ICSMediaPlayer {
- public static final void setSurface(MediaPlayer player, Surface surface) {
+ public static void setSurface(MediaPlayer player, Surface surface) {
player.setSurface(surface);
}
}
diff --git a/samples/SupportCarDemos/src/main/java/com/example/androidx/car/SeekbarListItemActivity.java b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/SeekbarListItemActivity.java
index 198f092..6975d61 100644
--- a/samples/SupportCarDemos/src/main/java/com/example/androidx/car/SeekbarListItemActivity.java
+++ b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/SeekbarListItemActivity.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.content.Context;
-import android.graphics.Color;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.Toast;
@@ -40,17 +39,12 @@
PagedListView mPagedListView;
- private static int pixelToDip(Context context, int pixels) {
- return (int) (pixels / context.getResources().getDisplayMetrics().density);
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_paged_list_view);
mPagedListView = findViewById(R.id.paged_list_view);
- mPagedListView.setBackgroundColor(Color.BLUE);
ListItemAdapter adapter = new ListItemAdapter(this,
new SampleProvider(this), ListItemAdapter.BackgroundStyle.PANEL);
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 23da45e..a265ce2 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
@@ -25,6 +25,7 @@
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.os.Handler;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.text.SpannableString;
@@ -48,8 +49,11 @@
"com.example.androidx.slice.action.TOAST";
public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE";
+ public static final int LOADING_DELAY_MS = 4000;
+
public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle",
- "toggle2", "contact", "gallery", "weather", "reservation"};
+ "toggle2", "contact", "gallery", "weather", "reservation", "loadlist", "loadlist2",
+ "loadgrid", "loadgrid2"};
/**
* @return Uri with the provided path
@@ -97,6 +101,14 @@
return createWeather(sliceUri);
case "/reservation":
return createReservationSlice(sliceUri);
+ case "/loadlist":
+ return createLoadingSlice(sliceUri, false /* loadAll */, true /* isList */);
+ case "/loadlist2":
+ return createLoadingSlice(sliceUri, true /* loadAll */, true /* isList */);
+ case "/loadgrid":
+ return createLoadingSlice(sliceUri, false /* loadAll */, false /* isList */);
+ case "/loadgrid2":
+ return createLoadingSlice(sliceUri, true /* loadAll */, false /* isList */);
}
throw new IllegalArgumentException("Unknown uri " + sliceUri);
}
@@ -246,15 +258,13 @@
return new ListBuilder(getContext(), sliceUri)
.setColor(0xff0F9D58)
.addRow(b -> b
- .setContentIntent(getBroadcastIntent(ACTION_TOAST, "work"))
.setTitle("Work")
.setSubtitle(workSubtitle)
.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work),
getBroadcastIntent(ACTION_TOAST, "work")))
.addRow(b -> b
- .setContentIntent(getBroadcastIntent(ACTION_TOAST, "home"))
.setTitle("Home")
- .setSubtitle(homeSubtitle)
+ .setSubtitle("2 hours 33 min via 101")
.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_home),
getBroadcastIntent(ACTION_TOAST, "home")))
.build();
@@ -320,6 +330,86 @@
.build();
}
+ private Handler mHandler = new Handler();
+ private Runnable mLoader;
+ private boolean mLoaded = false;
+
+ private Slice createLoadingSlice(Uri sliceUri, boolean loadAll, boolean isList) {
+ if (!mLoaded || mLoader != null) {
+ // Need to load content or we're still loading so just return partial
+ if (!mLoaded) {
+ mLoader = () -> {
+ // Note that we've loaded things
+ mLoader = null;
+ mLoaded = true;
+ // Notify to update the slice
+ getContext().getContentResolver().notifyChange(sliceUri, null);
+ };
+ mHandler.postDelayed(mLoader, LOADING_DELAY_MS);
+ }
+ if (loadAll) {
+ return isList
+ ? new ListBuilder(getContext(), sliceUri).build()
+ : new GridBuilder(getContext(), sliceUri).build();
+ }
+ return createPartialSlice(sliceUri, true, isList);
+ } else {
+ mLoaded = false;
+ return createPartialSlice(sliceUri, false, isList);
+ }
+ }
+
+ private Slice createPartialSlice(Uri sliceUri, boolean isPartial, boolean isList) {
+ Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_star_on);
+ PendingIntent intent = getBroadcastIntent(ACTION_TOAST, "star tapped");
+ PendingIntent intent2 = getBroadcastIntent(ACTION_TOAST, "toggle tapped");
+ if (isPartial) {
+ if (isList) {
+ return new ListBuilder(getContext(), sliceUri)
+ .addRow(b -> createRow(b, "Slice that has content to load",
+ "Temporary subtitle", icon, intent, true))
+ .addRow(b -> createRow(b, null, null, null, intent, true))
+ .addRow(b -> b.setTitle("My title").addToggle(intent2, false, true))
+ .build();
+ } else {
+ return new GridBuilder(getContext(), sliceUri)
+ .addCell(b -> createCell(b, null, null, null, true))
+ .addCell(b -> createCell(b, "Two stars", null, icon, true))
+ .addCell(b -> createCell(b, null, null, null, true))
+ .build();
+ }
+ } else {
+ if (isList) {
+ return new ListBuilder(getContext(), sliceUri)
+ .addRow(b -> createRow(b, "Slice that has content to load",
+ "Subtitle loaded", icon, intent, false))
+ .addRow(b -> createRow(b, "Loaded row", "Loaded subtitle",
+ icon, intent, false))
+ .addRow(b -> b.setTitle("My title").addToggle(intent2, false))
+ .build();
+ } else {
+ return new GridBuilder(getContext(), sliceUri)
+ .addCell(b -> createCell(b, "One star", "meh", icon, false))
+ .addCell(b -> createCell(b, "Two stars", "good", icon, false))
+ .addCell(b -> createCell(b, "Three stars", "best", icon, false))
+ .build();
+ }
+ }
+ }
+
+ private ListBuilder.RowBuilder createRow(ListBuilder.RowBuilder rb, String title,
+ String subtitle, Icon icon, PendingIntent content, boolean isLoading) {
+ return rb.setTitle(title, isLoading)
+ .setSubtitle(subtitle, isLoading)
+ .addEndItem(icon, isLoading)
+ .setContentIntent(content);
+ }
+
+ private GridBuilder.CellBuilder createCell(GridBuilder.CellBuilder cb, String text1,
+ String text2, Icon icon, boolean isLoading) {
+ return cb.addText(text1, isLoading).addText(text2, isLoading).addImage(icon, isLoading);
+ }
+
private PendingIntent getIntent(String action) {
Intent intent = new Intent(action);
PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBroadcastReceiver.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBroadcastReceiver.java
index 05f0820..24b2b77 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBroadcastReceiver.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBroadcastReceiver.java
@@ -16,6 +16,8 @@
package com.example.androidx.slice.demos;
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+
import static com.example.androidx.slice.demos.SampleSliceProvider.getUri;
import android.content.BroadcastReceiver;
@@ -25,8 +27,6 @@
import android.os.Handler;
import android.widget.Toast;
-import androidx.app.slice.core.SliceHints;
-
/**
* Responds to actions performed on slices and notifies slices of updates in state changes.
*/
@@ -38,8 +38,7 @@
switch (action) {
case SampleSliceProvider.ACTION_WIFI_CHANGED:
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- boolean newState = i.getBooleanExtra(SliceHints.EXTRA_TOGGLE_STATE,
- wm.isWifiEnabled());
+ boolean newState = i.getBooleanExtra(EXTRA_TOGGLE_STATE, wm.isWifiEnabled());
wm.setWifiEnabled(newState);
// Wait a bit for wifi to update (TODO: is there a better way to do this?)
Handler h = new Handler();
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
index 3769f34..7015743 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
@@ -66,6 +66,7 @@
private static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
private static final boolean TEST_INTENT = false;
+ private static final boolean TEST_THEMES = false;
private ArrayList<Uri> mSliceUris = new ArrayList<Uri>();
private int mSelectedMode;
@@ -122,8 +123,8 @@
});
mSelectedMode = (savedInstanceState != null)
- ? savedInstanceState.getInt("SELECTED_MODE", SliceView.MODE_SHORTCUT)
- : SliceView.MODE_SHORTCUT;
+ ? savedInstanceState.getInt("SELECTED_MODE", SliceView.MODE_LARGE)
+ : SliceView.MODE_LARGE;
if (savedInstanceState != null) {
mSearchView.setQuery(savedInstanceState.getString("SELECTED_QUERY"), true);
}
@@ -139,7 +140,7 @@
@Override
public boolean onCreateOptionsMenu(Menu menu) {
mTypeMenu = menu.addSubMenu("Type");
- mTypeMenu.setIcon(R.drawable.ic_shortcut);
+ mTypeMenu.setIcon(R.drawable.ic_large);
mTypeMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
mTypeMenu.add("Shortcut");
mTypeMenu.add("Small");
@@ -220,7 +221,9 @@
}
private void addSlice(Intent intent) {
- SliceView v = new SliceView(getApplicationContext());
+ SliceView v = TEST_THEMES
+ ? (SliceView) getLayoutInflater().inflate(R.layout.slice_view, mContainer, false)
+ : new SliceView(getApplicationContext());
v.setOnSliceActionListener(this);
v.setTag(intent);
if (mSliceLiveData != null) {
@@ -235,7 +238,10 @@
private void addSlice(Uri uri) {
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
- SliceView v = new SliceView(getApplicationContext());
+ SliceView v = TEST_THEMES
+ ? (SliceView) getLayoutInflater().inflate(
+ R.layout.slice_view, mContainer, false)
+ : new SliceView(getApplicationContext());
v.setOnSliceActionListener(this);
v.setTag(uri);
if (mSliceLiveData != null) {
diff --git a/samples/SupportSliceDemos/src/main/res/layout/slice_view.xml b/samples/SupportSliceDemos/src/main/res/layout/slice_view.xml
new file mode 100644
index 0000000..8d5eb61
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/layout/slice_view.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2018 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.
+ -->
+
+<androidx.app.slice.widget.SliceView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/CustomSliceView"/>
\ No newline at end of file
diff --git a/samples/SupportSliceDemos/src/main/res/values/styles.xml b/samples/SupportSliceDemos/src/main/res/values/styles.xml
index afb6bad..a01e0aa 100644
--- a/samples/SupportSliceDemos/src/main/res/values/styles.xml
+++ b/samples/SupportSliceDemos/src/main/res/values/styles.xml
@@ -24,6 +24,7 @@
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
+
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
@@ -31,4 +32,14 @@
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
+ <style name="CustomSliceView" parent="Widget.SliceView">
+ <item name="titleColor">@color/colorAccent</item>
+ <item name="tintColor">@color/colorAccent</item>
+ <item name="headerTitleSize">20sp</item>
+ <item name="headerSubtitleSize">16sp</item>
+ <item name="android:paddingLeft">14dp</item>
+ <item name="android:paddingTop">8dp</item>
+ <item name="android:paddingRight">20dp</item>
+ <item name="android:paddingBottom">8dp</item>
+ </style>
</resources>
diff --git a/slices/builders/api/current.txt b/slices/builders/api/current.txt
index eeb0d2f..513a054 100644
--- a/slices/builders/api/current.txt
+++ b/slices/builders/api/current.txt
@@ -11,9 +11,13 @@
ctor public GridBuilder.CellBuilder(androidx.app.slice.builders.GridBuilder);
ctor public GridBuilder.CellBuilder(androidx.app.slice.builders.GridBuilder, android.net.Uri);
method public androidx.app.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon);
+ method public androidx.app.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, boolean);
method public androidx.app.slice.builders.GridBuilder.CellBuilder addLargeImage(android.graphics.drawable.Icon);
+ method public androidx.app.slice.builders.GridBuilder.CellBuilder addLargeImage(android.graphics.drawable.Icon, boolean);
method public androidx.app.slice.builders.GridBuilder.CellBuilder addText(java.lang.CharSequence);
+ method public androidx.app.slice.builders.GridBuilder.CellBuilder addText(java.lang.CharSequence, boolean);
method public androidx.app.slice.builders.GridBuilder.CellBuilder addTitleText(java.lang.CharSequence);
+ method public androidx.app.slice.builders.GridBuilder.CellBuilder addTitleText(java.lang.CharSequence, boolean);
method public androidx.app.slice.builders.GridBuilder.CellBuilder setContentIntent(android.app.PendingIntent);
}
@@ -49,15 +53,23 @@
ctor public ListBuilder.RowBuilder(android.content.Context, android.net.Uri);
method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(long);
method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon);
+ method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, boolean);
method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, android.app.PendingIntent);
+ method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, android.app.PendingIntent, boolean);
method public androidx.app.slice.builders.ListBuilder.RowBuilder addToggle(android.app.PendingIntent, boolean);
+ method public androidx.app.slice.builders.ListBuilder.RowBuilder addToggle(android.app.PendingIntent, boolean, boolean);
method public androidx.app.slice.builders.ListBuilder.RowBuilder addToggle(android.app.PendingIntent, boolean, android.graphics.drawable.Icon);
+ method public androidx.app.slice.builders.ListBuilder.RowBuilder addToggle(android.app.PendingIntent, boolean, android.graphics.drawable.Icon, boolean);
method public androidx.app.slice.builders.ListBuilder.RowBuilder setContentIntent(android.app.PendingIntent);
method public androidx.app.slice.builders.ListBuilder.RowBuilder setSubtitle(java.lang.CharSequence);
+ method public androidx.app.slice.builders.ListBuilder.RowBuilder setSubtitle(java.lang.CharSequence, boolean);
method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitle(java.lang.CharSequence);
+ method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitle(java.lang.CharSequence, boolean);
method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(long);
method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon);
+ method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, boolean);
method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, android.app.PendingIntent);
+ method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, android.app.PendingIntent, boolean);
}
public abstract class TemplateSliceBuilder {
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java
index 01db779..6f967cb 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java
@@ -24,6 +24,7 @@
import android.net.Uri;
import android.os.Build;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.RestrictTo;
@@ -162,7 +163,22 @@
*/
@NonNull
public CellBuilder addText(@NonNull CharSequence text) {
- mImpl.addText(text);
+ return addText(text, false /* isLoading */);
+ }
+
+ /**
+ * Adds text to the cell. There can be at most two text items, the first two added
+ * will be used, others will be ignored.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public CellBuilder addText(@Nullable CharSequence text, boolean isLoading) {
+ mImpl.addText(text, isLoading);
return this;
}
@@ -173,7 +189,23 @@
*/
@NonNull
public CellBuilder addTitleText(@NonNull CharSequence text) {
- mImpl.addTitleText(text);
+ return addTitleText(text, false /* isLoading */);
+ }
+
+ /**
+ * Adds text to the cell. Text added with this method will be styled as a title.
+ * There can be at most two text items, the first two added will be used, others
+ * will be ignored.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public CellBuilder addTitleText(@Nullable CharSequence text, boolean isLoading) {
+ mImpl.addTitleText(text, isLoading);
return this;
}
@@ -185,7 +217,22 @@
*/
@NonNull
public CellBuilder addLargeImage(@NonNull Icon image) {
- mImpl.addLargeImage(image);
+ return addLargeImage(image, false /* isLoading */);
+ }
+
+ /**
+ * Adds an image to the cell that should be displayed as large as the cell allows.
+ * There can be at most one image, the first one added will be used, others will be ignored.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public CellBuilder addLargeImage(@Nullable Icon image, boolean isLoading) {
+ mImpl.addLargeImage(image, isLoading);
return this;
}
@@ -197,7 +244,22 @@
*/
@NonNull
public CellBuilder addImage(@NonNull Icon image) {
- mImpl.addImage(image);
+ return addImage(image, false /* isLoading */);
+ }
+
+ /**
+ * Adds an image to the cell. There can be at most one image, the first one added
+ * will be used, others will be ignored.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public CellBuilder addImage(@Nullable Icon image, boolean isLoading) {
+ mImpl.addImage(image, isLoading);
return this;
}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java
index 722543c..78f7c03 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java
@@ -273,10 +273,8 @@
}
/**
- * Sets the title item to be the provided icon.
- * <p>
- * There can only be one title item, this will replace any other title
- * items that may have been set.
+ * Sets the title item to be the provided icon. There can only be one title item, this
+ * will replace any other title items that may have been set.
*/
@NonNull
public RowBuilder setTitleItem(@NonNull Icon icon) {
@@ -285,14 +283,44 @@
}
/**
- * Sets the title item to be a tappable icon.
+ * Sets the title item to be the provided icon. There can only be one title item, this
+ * will replace any other title items that may have been set.
* <p>
- * There can only be one title item, this will replace any other title
- * items that may have been set.
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public RowBuilder setTitleItem(@Nullable Icon icon, boolean isLoading) {
+ mImpl.setTitleItem(icon, isLoading);
+ return this;
+ }
+
+ /**
+ * Sets the title item to be a tappable icon. There can only be one title item, this will
+ * replace any other title items that may have been set.
*/
@NonNull
public RowBuilder setTitleItem(@NonNull Icon icon, @NonNull PendingIntent action) {
- mImpl.setTitleItem(icon, action);
+ return setTitleItem(icon, action, false /* isLoading */);
+ }
+
+ /**
+ * Sets the title item to be a tappable icon. There can only be one title item, this will
+ * replace any other title items that may have been set.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public RowBuilder setTitleItem(@NonNull Icon icon, @NonNull PendingIntent action,
+ boolean isLoading) {
+ mImpl.setTitleItem(icon, action, isLoading);
return this;
}
@@ -309,17 +337,46 @@
* Sets the title text.
*/
@NonNull
- public RowBuilder setTitle(CharSequence title) {
+ public RowBuilder setTitle(@NonNull CharSequence title) {
mImpl.setTitle(title);
return this;
}
/**
+ * Sets the title text.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public RowBuilder setTitle(@Nullable CharSequence title, boolean isLoading) {
+ mImpl.setTitle(title, isLoading);
+ return this;
+ }
+
+ /**
* Sets the subtitle text.
*/
@NonNull
- public RowBuilder setSubtitle(CharSequence subtitle) {
- mImpl.setSubtitle(subtitle);
+ public RowBuilder setSubtitle(@NonNull CharSequence subtitle) {
+ return setSubtitle(subtitle, false /* isLoading */);
+ }
+
+ /**
+ * Sets the subtitle text.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public RowBuilder setSubtitle(@Nullable CharSequence subtitle, boolean isLoading) {
+ mImpl.setSubtitle(subtitle, isLoading);
return this;
}
@@ -345,12 +402,28 @@
*/
@NonNull
public RowBuilder addEndItem(@NonNull Icon icon) {
+ return addEndItem(icon, false /* isLoading */);
+ }
+
+ /**
+ * Adds an icon to be displayed at the end of the row. A mixture of icons and tappable
+ * icons is not permitted. If an action has already been added this will throw
+ * {@link IllegalArgumentException}.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public RowBuilder addEndItem(@NonNull Icon icon, boolean isLoading) {
if (mHasEndActionOrToggle) {
throw new IllegalArgumentException("Trying to add an icon to end items when an"
+ "action has already been added. End items cannot have a mixture of "
+ "tappable icons and icons.");
}
- mImpl.addEndItem(icon);
+ mImpl.addEndItem(icon, isLoading);
mHasEndImage = true;
return this;
}
@@ -362,13 +435,24 @@
*/
@NonNull
public RowBuilder addEndItem(@NonNull Icon icon, @NonNull PendingIntent action) {
- if (mHasEndImage) {
- throw new IllegalArgumentException("Trying to add an action to end items when an"
- + "icon has already been added. End items cannot have a mixture of "
- + "tappable icons and icons.");
- }
- mImpl.addEndItem(icon, action);
- mHasEndActionOrToggle = true;
+ return addEndItem(icon, action, false /* isLoading */);
+ }
+
+ /**
+ * Adds a tappable icon to be displayed at the end of the row. A mixture of icons and
+ * tappable icons is not permitted. If an icon has already been added, this will throw
+ * {@link IllegalArgumentException}.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public RowBuilder addEndItem(@Nullable Icon icon, @Nullable PendingIntent action,
+ boolean isLoading) {
+ mImpl.addEndItem(icon, action, isLoading);
return this;
}
@@ -379,7 +463,24 @@
*/
@NonNull
public RowBuilder addToggle(@NonNull PendingIntent action, boolean isChecked) {
- return addToggleInternal(action, isChecked, null);
+ return addToggle(action, isChecked, null, false /* isLoading */);
+ }
+
+ /**
+ * Adds a toggle action to be displayed at the end of the row. A mixture of icons and
+ * tappable icons is not permitted. If an icon has already been added, this will throw an
+ * {@link IllegalArgumentException}.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public RowBuilder addToggle(@NonNull PendingIntent action, boolean isChecked,
+ boolean isLoading) {
+ return addToggleInternal(action, isChecked, null, isLoading);
}
/**
@@ -391,11 +492,29 @@
@NonNull
public RowBuilder addToggle(@NonNull PendingIntent action, boolean isChecked,
@NonNull Icon icon) {
- return addToggleInternal(action, isChecked, icon);
+ return addToggle(action, isChecked, icon, false /* isLoading */);
+ }
+
+ /**
+ * Adds a toggle action to be displayed with custom icons to represent checked and
+ * unchecked state at the end of the row. A mixture of icons and tappable icons is not
+ * permitted. If an icon has already been added, this will throw an
+ * {@link IllegalArgumentException}.
+ * <p>
+ * Use this method to specify content that will appear in the template once it's been
+ * loaded.
+ * </p>
+ * @param isLoading indicates whether the app is doing work to load the added content in the
+ * background or not.
+ */
+ @NonNull
+ public RowBuilder addToggle(@NonNull PendingIntent action, boolean isChecked,
+ @NonNull Icon icon, boolean isLoading) {
+ return addToggleInternal(action, isChecked, icon, isLoading);
}
private RowBuilder addToggleInternal(@NonNull PendingIntent action, boolean isChecked,
- @Nullable Icon icon) {
+ @Nullable Icon icon, boolean isLoading) {
if (mHasEndImage) {
throw new IllegalStateException("Trying to add a toggle to end items when an "
+ "icon has already been added. End items cannot have a mixture of "
@@ -406,7 +525,7 @@
+ "in a single row. If you would like to include multiple toggles "
+ "in a row, set a custom icon for each toggle.");
}
- mImpl.addToggle(action, isChecked, icon);
+ mImpl.addToggle(action, isChecked, icon, isLoading);
mHasDefaultToggle = icon == null;
mHasEndActionOrToggle = true;
return this;
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilder.java
index 28134be..91266a4 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilder.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilder.java
@@ -22,6 +22,7 @@
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import androidx.app.slice.Slice;
@@ -62,6 +63,17 @@
void addText(@NonNull CharSequence text);
/**
+ * Adds text to the cell. There can be at most two text items, the first two added
+ * will be used, others will be ignored.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ @NonNull
+ void addText(@Nullable CharSequence text, boolean isLoading);
+
+ /**
* Adds text to the cell. Text added with this method will be styled as a title.
* There can be at most two text items, the first two added will be used, others
* will be ignored.
@@ -70,6 +82,18 @@
void addTitleText(@NonNull CharSequence text);
/**
+ * Adds text to the cell. Text added with this method will be styled as a title.
+ * There can be at most two text items, the first two added will be used, others
+ * will be ignored.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ @NonNull
+ void addTitleText(@Nullable CharSequence text, boolean isLoading);
+
+ /**
* Adds an image to the cell that should be displayed as large as the cell allows.
* There can be at most one image, the first one added will be used, others will be ignored.
*
@@ -79,6 +103,17 @@
void addLargeImage(@NonNull Icon image);
/**
+ * Adds an image to the cell that should be displayed as large as the cell allows.
+ * There can be at most one image, the first one added will be used, others will be ignored.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ @NonNull
+ void addLargeImage(@Nullable Icon image, boolean isLoading);
+
+ /**
* Adds an image to the cell. There can be at most one image, the first one added
* will be used, others will be ignored.
*
@@ -88,6 +123,17 @@
void addImage(@NonNull Icon image);
/**
+ * Adds an image to the cell. There can be at most one image, the first one added
+ * will be used, others will be ignored.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.l.
+ */
+ @NonNull
+ void addImage(@NonNull Icon image, boolean isLoading);
+
+ /**
* Sets the action to be invoked if the user taps on this cell in the row.
*/
@NonNull
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderBasicImpl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderBasicImpl.java
index 8205013..63f7506 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderBasicImpl.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderBasicImpl.java
@@ -22,6 +22,7 @@
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import androidx.app.slice.Slice;
@@ -102,6 +103,12 @@
/**
*/
+ @Override
+ public void addText(@Nullable CharSequence text, boolean isLoading) {
+ }
+
+ /**
+ */
@NonNull
@Override
public void addTitleText(@NonNull CharSequence text) {
@@ -111,6 +118,13 @@
*/
@NonNull
@Override
+ public void addTitleText(@Nullable CharSequence text, boolean isLoading) {
+ }
+
+ /**
+ */
+ @NonNull
+ @Override
public void addLargeImage(@NonNull Icon image) {
}
@@ -118,6 +132,13 @@
*/
@NonNull
@Override
+ public void addLargeImage(@Nullable Icon image, boolean isLoading) {
+ }
+
+ /**
+ */
+ @NonNull
+ @Override
public void addImage(@NonNull Icon image) {
}
@@ -125,6 +146,13 @@
*/
@NonNull
@Override
+ public void addImage(@Nullable Icon image, boolean isLoading) {
+ }
+
+ /**
+ */
+ @NonNull
+ @Override
public void setContentIntent(@NonNull PendingIntent intent) {
}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderListV1Impl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderListV1Impl.java
index d1a9e12..140bd9b 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderListV1Impl.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderListV1Impl.java
@@ -19,12 +19,14 @@
import static android.app.slice.Slice.HINT_HORIZONTAL;
import static android.app.slice.Slice.HINT_LARGE;
import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_PARTIAL;
import static android.support.annotation.RestrictTo.Scope.LIBRARY;
import android.app.PendingIntent;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import androidx.app.slice.Slice;
@@ -103,7 +105,17 @@
@NonNull
@Override
public void addText(@NonNull CharSequence text) {
- getBuilder().addText(text, null);
+ addText(text, false /* isLoading */);
+ }
+
+ /**
+ */
+ @Override
+ public void addText(@Nullable CharSequence text, boolean isLoading) {
+ @Slice.SliceHint String[] hints = isLoading
+ ? new String[] {HINT_PARTIAL}
+ : new String[0];
+ getBuilder().addText(text, null, hints);
}
/**
@@ -111,7 +123,18 @@
@NonNull
@Override
public void addTitleText(@NonNull CharSequence text) {
- getBuilder().addText(text, null, HINT_LARGE);
+ addTitleText(text, false /* isLoading */);
+ }
+
+ /**
+ */
+ @NonNull
+ @Override
+ public void addTitleText(@Nullable CharSequence text, boolean isLoading) {
+ @Slice.SliceHint String[] hints = isLoading
+ ? new String[] {HINT_PARTIAL, HINT_LARGE}
+ : new String[] {HINT_LARGE};
+ getBuilder().addText(text, null, hints);
}
/**
@@ -119,7 +142,18 @@
@NonNull
@Override
public void addLargeImage(@NonNull Icon image) {
- getBuilder().addIcon(image, null, HINT_LARGE);
+ addLargeImage(image, false /* isLoading */);
+ }
+
+ /**
+ */
+ @NonNull
+ @Override
+ public void addLargeImage(@Nullable Icon image, boolean isLoading) {
+ @Slice.SliceHint String[] hints = isLoading
+ ? new String[] {HINT_PARTIAL, HINT_LARGE}
+ : new String[] {HINT_LARGE};
+ getBuilder().addIcon(image, null, hints);
}
/**
@@ -127,7 +161,18 @@
@NonNull
@Override
public void addImage(@NonNull Icon image) {
- getBuilder().addIcon(image, null);
+ addImage(image, false /* isLoading */);
+ }
+
+ /**
+ */
+ @NonNull
+ @Override
+ public void addImage(@Nullable Icon image, boolean isLoading) {
+ @Slice.SliceHint String[] hints = isLoading
+ ? new String[] {HINT_PARTIAL}
+ : new String[0];
+ getBuilder().addIcon(image, null, hints);
}
/**
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilder.java
index 4aca4ee..9c2fd72 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilder.java
@@ -100,22 +100,38 @@
void setTitleItem(long timeStamp);
/**
- * Sets the title item to be the provided icon.
- * <p>
- * There can only be one title item, this will replace any other title
- * items that may have been set.
+ * Sets the title item to be the provided icon. There can only be one title item, this
+ * will replace any other title items that may have been set.
*/
void setTitleItem(Icon icon);
/**
- * Sets the title item to be a tappable icon.
+ * Sets the title item to be the provided icon. There can only be one title item, this
+ * will replace any other title items that may have been set.
* <p>
- * There can only be one title item, this will replace any other title
- * items that may have been set.
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ void setTitleItem(Icon icon, boolean isLoading);
+
+ /**
+ * Sets the title item to be a tappable icon. There can only be one title item, this will
+ * replace any other title items that may have been set.
*/
void setTitleItem(Icon icon, PendingIntent action);
/**
+ * Sets the title item to be a tappable icon. There can only be one title item, this will
+ * replace any other title items that may have been set.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ void setTitleItem(Icon icon, PendingIntent action, boolean isLoading);
+
+ /**
* Sets the action to be invoked if the user taps on the main content of the template.
*/
void setContentIntent(PendingIntent action);
@@ -126,11 +142,29 @@
void setTitle(CharSequence title);
/**
+ * Sets the title text.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ void setTitle(CharSequence title, boolean isLoading);
+
+ /**
* Sets the subtitle text.
*/
void setSubtitle(CharSequence subtitle);
/**
+ * Sets the subtitle text.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ void setSubtitle(CharSequence subtitle, boolean isLoading);
+
+ /**
* Adds a timestamp to be displayed at the end of the row.
*/
void addEndItem(long timeStamp);
@@ -141,15 +175,43 @@
void addEndItem(Icon icon);
/**
+ * Adds an icon to be displayed at the end of the row.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ void addEndItem(Icon icon, boolean isLoading);
+
+ /**
* Adds a tappable icon to be displayed at the end of the row.
*/
void addEndItem(Icon icon, PendingIntent action);
/**
+ * Adds a tappable icon to be displayed at the end of the row.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ void addEndItem(Icon icon, PendingIntent action, boolean isLoading);
+
+ /**
* Adds a toggle action to the template with custom icons to represent checked and unchecked
* state.
*/
void addToggle(PendingIntent action, boolean isChecked, Icon icon);
+
+ /**
+ * Adds a toggle action to the template with custom icons to represent checked and unchecked
+ * state.
+ * <p>
+ * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+ * to load this content in the background, in this case the template displays a placeholder
+ * until updated.
+ */
+ void addToggle(PendingIntent action, boolean isChecked, Icon icon, boolean isLoading);
}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderBasicImpl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderBasicImpl.java
index 6987adb..6520a16 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderBasicImpl.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderBasicImpl.java
@@ -153,6 +153,13 @@
/**
*/
@Override
+ public void addEndItem(Icon icon, boolean isLoading) {
+
+ }
+
+ /**
+ */
+ @Override
public void addEndItem(Icon icon, PendingIntent action) {
}
@@ -160,6 +167,13 @@
/**
*/
@Override
+ public void addEndItem(Icon icon, PendingIntent action, boolean isLoading) {
+
+ }
+
+ /**
+ */
+ @Override
public void addToggle(PendingIntent action, boolean isChecked, Icon icon) {
}
@@ -167,6 +181,14 @@
/**
*/
@Override
+ public void addToggle(PendingIntent action, boolean isChecked, Icon icon,
+ boolean isLoading) {
+
+ }
+
+ /**
+ */
+ @Override
public void setTitleItem(long timeStamp) {
}
@@ -181,6 +203,13 @@
/**
*/
@Override
+ public void setTitleItem(Icon icon, boolean isLoading) {
+
+ }
+
+ /**
+ */
+ @Override
public void setTitleItem(Icon icon, PendingIntent action) {
mIcon = icon;
}
@@ -188,6 +217,13 @@
/**
*/
@Override
+ public void setTitleItem(Icon icon, PendingIntent action, boolean isLoading) {
+
+ }
+
+ /**
+ */
+ @Override
public void setContentIntent(PendingIntent action) {
}
@@ -202,6 +238,13 @@
/**
*/
@Override
+ public void setTitle(CharSequence title, boolean isLoading) {
+
+ }
+
+ /**
+ */
+ @Override
public void setSubtitle(CharSequence subtitle) {
mSubtitle = subtitle;
}
@@ -209,6 +252,13 @@
/**
*/
@Override
+ public void setSubtitle(CharSequence subtitle, boolean isLoading) {
+
+ }
+
+ /**
+ */
+ @Override
public void addEndItem(long timeStamp) {
}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderV1Impl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderV1Impl.java
index 38d7fc3..9d7fba4 100644
--- a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderV1Impl.java
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderV1Impl.java
@@ -20,23 +20,25 @@
import static android.app.slice.Slice.HINT_LARGE;
import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_PARTIAL;
import static android.app.slice.Slice.HINT_SELECTED;
+import static android.app.slice.Slice.HINT_SUMMARY;
import static android.app.slice.Slice.HINT_TITLE;
import static android.app.slice.Slice.SUBTYPE_COLOR;
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 android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static android.support.annotation.RestrictTo.Scope.LIBRARY;
-import static androidx.app.slice.core.SliceHints.SUBTYPE_TOGGLE;
-
import android.app.PendingIntent;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import java.util.ArrayList;
@@ -44,7 +46,6 @@
import androidx.app.slice.Slice;
import androidx.app.slice.SliceItem;
import androidx.app.slice.SliceSpec;
-import androidx.app.slice.core.SliceHints;
/**
* @hide
@@ -197,7 +198,17 @@
@NonNull
@Override
public void setTitleItem(@NonNull Icon icon) {
+ setTitleItem(icon, false /* isLoading */);
+ }
+
+ /**
+ */
+ @Override
+ public void setTitleItem(@Nullable Icon icon, boolean isLoading) {
mStartItem = new SliceItem(icon, FORMAT_IMAGE, null, new String[0]);
+ if (isLoading) {
+ mStartItem.addHint(HINT_PARTIAL);
+ }
}
/**
@@ -205,8 +216,18 @@
@NonNull
@Override
public void setTitleItem(@NonNull Icon icon, @NonNull PendingIntent action) {
+ setTitleItem(icon, action, false /* isLoading */);
+ }
+
+ /**
+ */
+ @Override
+ public void setTitleItem(Icon icon, PendingIntent action, boolean isLoading) {
Slice actionSlice = new Slice.Builder(getBuilder()).addIcon(icon, null).build();
mStartItem = new SliceItem(action, actionSlice, FORMAT_ACTION, null, new String[0]);
+ if (isLoading) {
+ mStartItem.addHint(HINT_PARTIAL);
+ }
}
/**
@@ -222,7 +243,17 @@
@NonNull
@Override
public void setTitle(CharSequence title) {
- mTitleItem = new SliceItem(title, FORMAT_TEXT, null, new String[]{HINT_TITLE});
+ setTitle(title, false /* isLoading */);
+ }
+
+ /**
+ */
+ @Override
+ public void setTitle(CharSequence title, boolean isLoading) {
+ mTitleItem = new SliceItem(title, FORMAT_TEXT, null, new String[] {HINT_TITLE});
+ if (isLoading) {
+ mTitleItem.addHint(HINT_PARTIAL);
+ }
}
/**
@@ -230,7 +261,17 @@
@NonNull
@Override
public void setSubtitle(CharSequence subtitle) {
+ setSubtitle(subtitle, false /* isLoading */);
+ }
+
+ /**
+ */
+ @Override
+ public void setSubtitle(CharSequence subtitle, boolean isLoading) {
mSubtitleItem = new SliceItem(subtitle, FORMAT_TEXT, null, new String[0]);
+ if (isLoading) {
+ mSubtitleItem.addHint(HINT_PARTIAL);
+ }
}
/**
@@ -246,8 +287,19 @@
@NonNull
@Override
public void addEndItem(@NonNull Icon icon) {
- mEndItems.add(new SliceItem(icon, FORMAT_IMAGE, null,
- new String[]{HINT_NO_TINT, HINT_LARGE}));
+ addEndItem(icon, false /* isLoading */);
+ }
+
+ /**
+ */
+ @Override
+ public void addEndItem(Icon icon, boolean isLoading) {
+ SliceItem item = new SliceItem(icon, FORMAT_IMAGE, null,
+ new String[] {HINT_NO_TINT, HINT_LARGE});
+ if (isLoading) {
+ item.addHint(HINT_PARTIAL);
+ }
+ mEndItems.add(item);
}
/**
@@ -255,8 +307,20 @@
@NonNull
@Override
public void addEndItem(@NonNull Icon icon, @NonNull PendingIntent action) {
+ addEndItem(icon, action, false /* isLoading */);
+ }
+
+ /**
+ */
+ @Override
+ public void addEndItem(Icon icon, PendingIntent action, boolean isLoading) {
Slice actionSlice = new Slice.Builder(getBuilder()).addIcon(icon, null).build();
- mEndItems.add(new SliceItem(action, actionSlice, FORMAT_ACTION, null, new String[0]));
+ SliceItem item = new SliceItem(action, actionSlice, FORMAT_ACTION, null,
+ new String[0]);
+ if (isLoading) {
+ item.addHint(HINT_PARTIAL);
+ }
+ mEndItems.add(item);
}
/**
@@ -265,15 +329,26 @@
@Override
public void addToggle(@NonNull PendingIntent action, boolean isChecked,
@NonNull Icon icon) {
+ addToggle(action, isChecked, icon, false /* isLoading */);
+ }
+
+ @Override
+ public void addToggle(PendingIntent action, boolean isChecked, Icon icon,
+ boolean isLoading) {
@Slice.SliceHint String[] hints = isChecked
- ? new String[] {SUBTYPE_TOGGLE, HINT_SELECTED}
- : new String[] {SUBTYPE_TOGGLE};
+ ? new String[] {HINT_SELECTED}
+ : new String[0];
Slice.Builder actionSliceBuilder = new Slice.Builder(getBuilder()).addHints(hints);
if (icon != null) {
actionSliceBuilder.addIcon(icon, null);
}
Slice actionSlice = actionSliceBuilder.build();
- mEndItems.add(new SliceItem(action, actionSlice, FORMAT_ACTION, null, hints));
+ SliceItem item = new SliceItem(action, actionSlice, FORMAT_ACTION, SUBTYPE_TOGGLE,
+ hints);
+ if (isLoading) {
+ item.addHint(HINT_PARTIAL);
+ }
+ mEndItems.add(item);
}
/**
@@ -341,7 +416,7 @@
b.addText(mSubtitle, null /* subtype */);
}
if (mSummarySubtitle != null) {
- b.addText(mSummarySubtitle, null /* subtype */, SliceHints.HINT_SUMMARY);
+ b.addText(mSummarySubtitle, null /* subtype */, HINT_SUMMARY);
}
if (mContentIntent != null) {
wrapped.addAction(mContentIntent, b.build(), null /* subtype */);
diff --git a/slices/core/src/main/java/androidx/app/slice/Slice.java b/slices/core/src/main/java/androidx/app/slice/Slice.java
index 4681b2d..153a34f 100644
--- a/slices/core/src/main/java/androidx/app/slice/Slice.java
+++ b/slices/core/src/main/java/androidx/app/slice/Slice.java
@@ -24,6 +24,7 @@
import static android.app.slice.Slice.HINT_NO_TINT;
import static android.app.slice.Slice.HINT_PARTIAL;
import static android.app.slice.Slice.HINT_SELECTED;
+import static android.app.slice.Slice.HINT_SUMMARY;
import static android.app.slice.Slice.HINT_TITLE;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
@@ -57,7 +58,6 @@
import java.util.List;
import androidx.app.slice.compat.SliceProviderCompat;
-import androidx.app.slice.core.SliceHints;
/**
* A slice is a piece of app content and actions that can be surfaced outside of the app.
@@ -80,8 +80,7 @@
*/
@RestrictTo(Scope.LIBRARY)
@StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
- HINT_HORIZONTAL, HINT_NO_TINT, HINT_PARTIAL,
- SliceHints.HINT_SUMMARY, SliceHints.SUBTYPE_TOGGLE})
+ HINT_HORIZONTAL, HINT_NO_TINT, HINT_PARTIAL, HINT_SUMMARY})
public @interface SliceHint{ }
private final SliceItem[] mItems;
diff --git a/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
index c98f1d2..cb913e2 100644
--- a/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
+++ b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
@@ -18,7 +18,6 @@
import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-import android.app.slice.Slice;
import android.support.annotation.RestrictTo;
/**
@@ -28,14 +27,6 @@
@RestrictTo(LIBRARY_GROUP)
public class SliceHints {
/**
- * Subtype to indicate that this content has a toggle action associated with it. To indicate
- * that the toggle is on, use {@link Slice#HINT_SELECTED}. When the toggle state changes, the
- * intent associated with it will be sent along with an extra {@link #EXTRA_TOGGLE_STATE}
- * which can be retrieved to see the new state of the toggle.
- */
- public static final String SUBTYPE_TOGGLE = "toggle";
-
- /**
* Subtype indicating that this content is the maximum value for a slider or progress.
*/
public static final String SUBTYPE_MAX = "max";
@@ -46,19 +37,7 @@
public static final String SUBTYPE_PROGRESS = "progress";
/**
- * Key to retrieve an extra added to an intent when a control is changed.
- */
- public static final String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
-
- /**
* Key to retrieve an extra added to an intent when the value of a slider has changed.
*/
public static final String EXTRA_SLIDER_VALUE = "android.app.slice.extra.SLIDER_VALUE";
-
- /**
- * Hint indicating this content should be shown instead of the normal content when the slice
- * is in small format
- */
- public static final String HINT_SUMMARY = "summary";
-
}
diff --git a/slices/view/api/current.txt b/slices/view/api/current.txt
index 251742a..d158818 100644
--- a/slices/view/api/current.txt
+++ b/slices/view/api/current.txt
@@ -16,8 +16,12 @@
}
public class SliceUtils {
+ method public static int getLoadingState(androidx.app.slice.Slice);
method public static androidx.app.slice.Slice parseSlice(java.io.InputStream, java.lang.String) throws java.io.IOException;
method public static void serializeSlice(androidx.app.slice.Slice, android.content.Context, java.io.OutputStream, java.lang.String, androidx.app.slice.SliceUtils.SerializeOptions) throws java.io.IOException;
+ field public static final int LOADING_ALL = 0; // 0x0
+ field public static final int LOADING_COMPLETE = 2; // 0x2
+ field public static final int LOADING_PARTIAL = 1; // 0x1
}
public static class SliceUtils.SerializeOptions {
@@ -76,6 +80,7 @@
method public void setOnSliceActionListener(androidx.app.slice.widget.SliceView.OnSliceActionListener);
method public void setScrollable(boolean);
method public void setSlice(androidx.app.slice.Slice);
+ method public void setTint(int);
field public static final int MODE_LARGE = 2; // 0x2
field public static final int MODE_SHORTCUT = 3; // 0x3
field public static final int MODE_SMALL = 1; // 0x1
diff --git a/slices/view/build.gradle b/slices/view/build.gradle
index 92e117e..93e9fc5 100644
--- a/slices/view/build.gradle
+++ b/slices/view/build.gradle
@@ -29,6 +29,7 @@
api(ARCH_LIFECYCLE_EXTENSIONS, libs.exclude_annotations_transitive)
androidTestImplementation(TEST_RUNNER)
+ androidTestImplementation(ESPRESSO_CORE)
androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy)
androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy)
}
diff --git a/slices/view/src/androidTest/AndroidManifest.xml b/slices/view/src/androidTest/AndroidManifest.xml
index 5a7abb6..6800706 100644
--- a/slices/view/src/androidTest/AndroidManifest.xml
+++ b/slices/view/src/androidTest/AndroidManifest.xml
@@ -16,9 +16,22 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="androidx.app.slice.view.test">
+ <uses-sdk android:targetSdkVersion="21" />
+
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<application>
<provider android:name="androidx.app.slice.SliceManagerTest$TestSliceProvider"
android:authorities="androidx.app.slice.view.test"
android:exported="true"/>
+
+ <activity android:name="androidx.app.slice.render.SliceRenderActivity"
+ android:theme="@style/AppTheme.NoActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/RenderTest.java b/slices/view/src/androidTest/java/androidx/app/slice/render/RenderTest.java
new file mode 100644
index 0000000..6cf6182
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/RenderTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 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 androidx.app.slice.render;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RenderTest {
+
+ private final Context mContext = InstrumentationRegistry.getContext();
+
+ @Test
+ public void testRender() throws InterruptedException {
+ final CountDownLatch latch = new CountDownLatch(1);
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ latch.countDown();
+ }
+ };
+ mContext.registerReceiver(receiver,
+ new IntentFilter(SliceRenderActivity.ACTION_RENDER_DONE));
+ mContext.startActivity(new Intent(mContext, SliceRenderActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+
+ latch.await(30000, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceCreator.java b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceCreator.java
new file mode 100644
index 0000000..114d0e1
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceCreator.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2018 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 androidx.app.slice.render;
+
+import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
+
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.text.SpannableString;
+import android.text.format.DateUtils;
+import android.text.style.ForegroundColorSpan;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.builders.GridBuilder;
+import androidx.app.slice.builders.ListBuilder;
+import androidx.app.slice.builders.MessagingSliceBuilder;
+import androidx.app.slice.view.test.R;
+
+/**
+ * Examples of using slice template builders.
+ */
+public class SliceCreator {
+
+ public static final String ACTION_WIFI_CHANGED =
+ "com.example.androidx.slice.action.WIFI_CHANGED";
+ public static final String ACTION_TOAST =
+ "com.example.androidx.slice.action.TOAST";
+ public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE";
+
+ public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle",
+ "toggle2", "contact", "gallery", "weather"};
+
+ private final Context mContext;
+
+ public SliceCreator(Context context) {
+ mContext = context;
+ }
+
+ private Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * @return Uri with the provided path
+ */
+ public static Uri getUri(String path, Context context) {
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority("androidx.app.slice.view.test")
+ .appendPath(path)
+ .build();
+ }
+
+ public Slice onBindSlice(Uri sliceUri) {
+ String path = sliceUri.getPath();
+ switch (path) {
+ case "/message":
+ return createMessagingSlice(sliceUri);
+ case "/wifi":
+ return createWifiSlice(sliceUri);
+ case "/note":
+ return createNoteSlice(sliceUri);
+ case "/ride":
+ return createRideSlice(sliceUri);
+ case "/toggle":
+ return createCustomToggleSlice(sliceUri);
+ case "/toggle2":
+ return createTwoCustomToggleSlices(sliceUri);
+ case "/contact":
+ return createContact(sliceUri);
+ case "/gallery":
+ return createGallery(sliceUri);
+ case "/weather":
+ return createWeather(sliceUri);
+ }
+ throw new IllegalArgumentException("Unknown uri " + sliceUri);
+ }
+
+ private Slice createWeather(Uri sliceUri) {
+ GridBuilder b = new GridBuilder(getContext(), sliceUri);
+ return b.addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+ .addText("MON")
+ .addTitleText("69\u00B0"))
+ .addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_2))
+ .addText("TUE")
+ .addTitleText("71\u00B0"))
+ .addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_3))
+ .addText("WED")
+ .addTitleText("76\u00B0"))
+ .addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_4))
+ .addText("THU")
+ .addTitleText("72\u00B0"))
+ .addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+ .addText("FRI")
+ .addTitleText("68\u00B0"))
+ .build();
+ }
+
+ private Slice createGallery(Uri sliceUri) {
+ GridBuilder b = new GridBuilder(getContext(), sliceUri);
+ return b.addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_1)))
+ .addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_2)))
+ .addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_3)))
+ .addCell(new GridBuilder.CellBuilder(b)
+ .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_4)))
+ .build();
+ }
+
+ private Slice createContact(Uri sliceUri) {
+ ListBuilder b = new ListBuilder(getContext(), sliceUri);
+ ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(b);
+ 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)))
+ .addGrid(gb
+ .addCell(new GridBuilder.CellBuilder(gb)
+ .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call))
+ .addText("Call")
+ .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
+ .addCell(new GridBuilder.CellBuilder(gb)
+ .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text))
+ .addText("Text")
+ .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
+ .addCell(new GridBuilder.CellBuilder(gb)
+ .addImage(Icon.createWithResource(getContext(), R.drawable.ic_video))
+ .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
+ .addText("Video"))
+ .addCell(new GridBuilder.CellBuilder(gb)
+ .addImage(Icon.createWithResource(getContext(), R.drawable.ic_email))
+ .addText("Email")
+ .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
+ .build();
+ }
+
+ private Slice createMessagingSlice(Uri sliceUri) {
+ // TODO: Remote input.
+ MessagingSliceBuilder mb = new MessagingSliceBuilder(getContext(), sliceUri);
+ return mb
+ .add(new MessagingSliceBuilder.MessageBuilder(mb)
+ .addText("yo home \uD83C\uDF55, I emailed you the info")
+ .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS)
+ .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+ .add(new MessagingSliceBuilder.MessageBuilder(mb)
+ .addText("just bought my tickets")
+ .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS))
+ .add(new MessagingSliceBuilder.MessageBuilder(mb)
+ .addText("yay! can't wait for getContext() weekend!\n"
+ + "\uD83D\uDE00")
+ .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS)
+ .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+ .build();
+
+ }
+
+ private Slice createNoteSlice(Uri sliceUri) {
+ // TODO: Remote input.
+ ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+ return lb.setColor(0xfff4b400)
+ .addRow(new ListBuilder.RowBuilder(lb)
+ .setTitle("Create new note")
+ .setSubtitle("with this note taking app")
+ .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_create),
+ getBroadcastIntent(ACTION_TOAST, "create note"))
+ .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_voice),
+ getBroadcastIntent(ACTION_TOAST, "voice note"))
+ .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_camera),
+ getIntent("android.media.action.IMAGE_CAPTURE")))
+ .build();
+ }
+
+ private Slice createRideSlice(Uri sliceUri) {
+ final ForegroundColorSpan colorSpan = new ForegroundColorSpan(0xff0F9D58);
+ SpannableString headerSubtitle = new SpannableString("Ride in 4 min");
+ headerSubtitle.setSpan(colorSpan, 8, headerSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+ SpannableString homeSubtitle = new SpannableString("12 miles | 12 min | $9.00");
+ homeSubtitle.setSpan(colorSpan, 20, homeSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+ SpannableString workSubtitle = new SpannableString("44 miles | 1 hour 45 min | $31.41");
+ workSubtitle.setSpan(colorSpan, 27, workSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ ListBuilder b = new ListBuilder(getContext(), sliceUri);
+ return b.setColor(0xff0F9D58)
+ .addRow(new ListBuilder.RowBuilder(b)
+ .setContentIntent(getBroadcastIntent(ACTION_TOAST, "work"))
+ .setTitle("Work")
+ .setSubtitle(workSubtitle)
+ .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work),
+ getBroadcastIntent(ACTION_TOAST, "work")))
+ .addRow(new ListBuilder.RowBuilder(b)
+ .setContentIntent(getBroadcastIntent(ACTION_TOAST, "home"))
+ .setTitle("Home")
+ .setSubtitle(homeSubtitle)
+ .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_home),
+ getBroadcastIntent(ACTION_TOAST, "home")))
+ .build();
+ }
+
+ private Slice createCustomToggleSlice(Uri sliceUri) {
+ ListBuilder b = new ListBuilder(getContext(), sliceUri);
+ return b.setColor(0xffff4081)
+ .addRow(new ListBuilder.RowBuilder(b)
+ .setTitle("Custom toggle")
+ .setSubtitle("It can support two states")
+ .addToggle(getBroadcastIntent(ACTION_TOAST, "star toggled"),
+ true /* isChecked */,
+ Icon.createWithResource(getContext(), R.drawable.toggle_star)))
+ .build();
+ }
+
+ private Slice createTwoCustomToggleSlices(Uri sliceUri) {
+ ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+ return lb.setColor(0xffff4081)
+ .addRow(new ListBuilder.RowBuilder(lb)
+ .setTitle("2 toggles")
+ .setSubtitle("each supports two states")
+ .addToggle(getBroadcastIntent(ACTION_TOAST, "first star toggled"),
+ true /* isChecked */,
+ Icon.createWithResource(getContext(), R.drawable.toggle_star))
+ .addToggle(getBroadcastIntent(ACTION_TOAST, "second star toggled"),
+ false /* isChecked */,
+ Icon.createWithResource(getContext(), R.drawable.toggle_star)))
+ .build();
+ }
+
+ private Slice createWifiSlice(Uri sliceUri) {
+ // Get wifi state
+ WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+ int wifiState = wifiManager.getWifiState();
+ boolean wifiEnabled = false;
+ String state;
+ switch (wifiState) {
+ case WifiManager.WIFI_STATE_DISABLED:
+ case WifiManager.WIFI_STATE_DISABLING:
+ state = "disconnected";
+ break;
+ case WifiManager.WIFI_STATE_ENABLED:
+ case WifiManager.WIFI_STATE_ENABLING:
+ state = wifiManager.getConnectionInfo().getSSID();
+ wifiEnabled = true;
+ break;
+ case WifiManager.WIFI_STATE_UNKNOWN:
+ default:
+ state = ""; // just don't show anything?
+ break;
+ }
+ boolean finalWifiEnabled = wifiEnabled;
+ ListBuilder b = new ListBuilder(getContext(), sliceUri);
+ return b.setColor(0xff4285f4)
+ .addRow(new ListBuilder.RowBuilder(b)
+ .setTitle("Wi-fi")
+ .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi))
+ .setSubtitle(state)
+ .addToggle(getBroadcastIntent(ACTION_WIFI_CHANGED, null), finalWifiEnabled)
+ .setContentIntent(getIntent(Settings.ACTION_WIFI_SETTINGS)))
+ .build();
+ }
+
+ private PendingIntent getIntent(String action) {
+ Intent intent = new Intent(action);
+ intent.setClassName(getContext().getPackageName(), SliceRenderActivity.class.getName());
+ PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
+ return pi;
+ }
+
+ private PendingIntent getBroadcastIntent(String action, String message) {
+ Intent intent = new Intent(action);
+ intent.setClassName(getContext().getPackageName(), SliceRenderActivity.class.getName());
+ // Ensure a new PendingIntent is created for each message.
+ int requestCode = 0;
+ if (message != null) {
+ intent.putExtra(EXTRA_TOAST_MESSAGE, message);
+ requestCode = message.hashCode();
+ }
+ return PendingIntent.getBroadcast(getContext(), requestCode, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+}
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderActivity.java b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderActivity.java
new file mode 100644
index 0000000..debb280
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 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 androidx.app.slice.render;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+public class SliceRenderActivity extends Activity {
+ public static final String ACTION_RENDER_DONE = "androidx.app.slice.render.RENDER_DONE";
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ new SliceRenderer(this).renderAll(new Runnable() {
+
+ @Override
+ public void run() {
+ sendBroadcast(new Intent(ACTION_RENDER_DONE));
+ finish();
+ }
+ });
+ }
+}
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
new file mode 100644
index 0000000..d2b8619
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2018 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 androidx.app.slice.render;
+
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.os.Handler;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.util.concurrent.CountDownLatch;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
+import androidx.app.slice.view.test.R;
+import androidx.app.slice.widget.SliceLiveData;
+import androidx.app.slice.widget.SliceView;
+
+public class SliceRenderer {
+
+ private static final String TAG = "SliceRenderer";
+ private static final String SCREENSHOT_DIR = "slice-screenshots";
+ private static File sScreenshotDirectory;
+
+ private final Activity mContext;
+ private final View mLayout;
+ private final SliceView mSV1;
+ private final SliceView mSV2;
+ private final SliceView mSV3;
+ private final ViewGroup mParent;
+ private final Handler mHandler;
+ private final SliceCreator mSliceCreator;
+ private CountDownLatch mDoneLatch;
+
+ public SliceRenderer(Activity context) {
+ mContext = context;
+ mParent = new ViewGroup(mContext) {
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 900,
+ mContext.getResources().getDisplayMetrics());
+ int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200,
+ mContext.getResources().getDisplayMetrics());
+ mLayout.measure(makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+ makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+ mLayout.layout(0, 0, width, height);
+ }
+
+ @Override
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ return false;
+ }
+ };
+ mLayout = LayoutInflater.from(context).inflate(R.layout.render_layout, null);
+ mSV1 = mLayout.findViewById(R.id.sv1);
+ mSV1.setMode(SliceView.MODE_SHORTCUT);
+ mSV2 = mLayout.findViewById(R.id.sv2);
+ mSV2.setMode(SliceView.MODE_SMALL);
+ mSV3 = mLayout.findViewById(R.id.sv3);
+ mSV3.setMode(SliceView.MODE_LARGE);
+ disableAnims(mLayout);
+ mHandler = new Handler();
+ ((ViewGroup) mContext.getWindow().getDecorView()).addView(mParent);
+ mParent.addView(mLayout);
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ mSliceCreator = new SliceCreator(mContext);
+ }
+
+ private void disableAnims(View view) {
+ if (view instanceof RecyclerView) {
+ ((RecyclerView) view).setItemAnimator(null);
+ }
+ if (view instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ disableAnims(viewGroup.getChildAt(i));
+ }
+ }
+ }
+
+
+ private static File getScreenshotDirectory() {
+ if (sScreenshotDirectory == null) {
+ File storage = Environment.getExternalStorageDirectory();
+ sScreenshotDirectory = new File(storage, SCREENSHOT_DIR);
+ if (!sScreenshotDirectory.exists()) {
+ if (!sScreenshotDirectory.mkdirs()) {
+ throw new RuntimeException(
+ "Failed to create a screenshot directory.");
+ }
+ }
+ }
+ return sScreenshotDirectory;
+ }
+
+
+ private void doRender() {
+ File output = getScreenshotDirectory();
+ if (!output.exists()) {
+ output.mkdir();
+ }
+ mDoneLatch = new CountDownLatch(SliceCreator.URI_PATHS.length);
+ for (String slice : SliceCreator.URI_PATHS) {
+ doRender(slice, new File(output, String.format("%s.png", slice)));
+ }
+ Log.d(TAG, "Wrote render to " + output.getAbsolutePath());
+ mContext.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ((ViewGroup) mParent.getParent()).removeView(mParent);
+ }
+ });
+ try {
+ mDoneLatch.await();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ private void doRender(final String slice, final File file) {
+ Log.d(TAG, "Rendering " + slice + " to " + file.getAbsolutePath());
+
+ final Slice s = mSliceCreator.onBindSlice(SliceCreator.getUri(slice, mContext));
+
+ final CountDownLatch l = new CountDownLatch(1);
+ mContext.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mSV1.setSlice(s);
+ mSV2.setSlice(s);
+ mSV3.setSlice(s);
+ mSV1.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ mSV1.removeOnLayoutChangeListener(this);
+ mSV1.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ Log.d(TAG, "Drawing " + slice);
+ Bitmap b = Bitmap.createBitmap(mLayout.getMeasuredWidth(),
+ mLayout.getMeasuredHeight(),
+ Bitmap.Config.ARGB_8888);
+
+ mLayout.draw(new Canvas(b));
+ try {
+ doCompress(slice, b, new FileOutputStream(file));
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ l.countDown();
+ }
+ }, 10);
+ }
+ });
+ }
+ });
+ try {
+ l.await();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ private void doCompress(final String slice, final Bitmap b, final FileOutputStream s) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ Log.d(TAG, "Compressing " + slice);
+ if (!b.compress(Bitmap.CompressFormat.PNG, 100, s)) {
+ throw new RuntimeException("Unable to compress");
+ }
+
+ b.recycle();
+ Log.d(TAG, "Done " + slice);
+ mDoneLatch.countDown();
+ }
+ });
+ }
+
+ public void renderAll(final Runnable runnable) {
+ final ProgressDialog dialog = ProgressDialog.show(mContext, null, "Rendering...");
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ doRender();
+ mContext.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ dialog.dismiss();
+ runnable.run();
+ }
+ });
+ }
+ }).start();
+ }
+}
diff --git a/slices/view/src/androidTest/res/drawable/ic_call.xml b/slices/view/src/androidTest/res/drawable/ic_call.xml
new file mode 100644
index 0000000..ebf9de6
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_call.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M6.62,10.79c1.44,2.83 3.76,5.14 6.59,6.59l2.2,-2.2c0.27,-0.27 0.67,-0.36 1.02,-0.24 1.12,0.37 2.33,0.57 3.57,0.57 0.55,0 1,0.45 1,1V20c0,0.55 -0.45,1 -1,1 -9.39,0 -17,-7.61 -17,-17 0,-0.55 0.45,-1 1,-1h3.5c0.55,0 1,0.45 1,1 0,1.25 0.2,2.45 0.57,3.57 0.11,0.35 0.03,0.74 -0.25,1.02l-2.2,2.2z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_camera.xml b/slices/view/src/androidTest/res/drawable/ic_camera.xml
new file mode 100644
index 0000000..74b6bf9
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_camera.xml
@@ -0,0 +1,32 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M 12 8.8 C 13.7673111995 8.8 15.2 10.2326888005 15.2 12 C 15.2 13.7673111995 13.7673111995 15.2 12 15.2 C 10.2326888005 15.2 8.8 13.7673111995 8.8 12 C 8.8 10.2326888005 10.2326888005 8.8 12 8.8 Z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1 0 2-.9
+2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5
+5-2.24 5-5 5z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/ic_car.xml b/slices/view/src/androidTest/res/drawable/ic_car.xml
new file mode 100644
index 0000000..6bab660
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_car.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M18.92 6.01C18.72 5.42 18.16 5 17.5 5h-11c-.66 0-1.21 .42 -1.42 1.01L3 12v8c0
+.55 .45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55 .45 1 1 1h1c.55 0 1-.45
+1-1v-8l-2.08-5.99zM6.5 16c-.83 0-1.5-.67-1.5-1.5S5.67 13 6.5 13s1.5 .67 1.5
+1.5S7.33 16 6.5 16zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5 .67 1.5
+1.5-.67 1.5-1.5 1.5zM5 11l1.5-4.5h11L19 11H5z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/ic_create.xml b/slices/view/src/androidTest/res/drawable/ic_create.xml
new file mode 100644
index 0000000..d1666a8
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_create.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_email.xml b/slices/view/src/androidTest/res/drawable/ic_email.xml
new file mode 100644
index 0000000..ce97ab8
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_email.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_home.xml b/slices/view/src/androidTest/res/drawable/ic_home.xml
new file mode 100644
index 0000000..b278230
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_home.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/ic_large.xml b/slices/view/src/androidTest/res/drawable/ic_large.xml
new file mode 100644
index 0000000..79ac590
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_large.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48.0dp"
+ android:height="48.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M34.0,2.02L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/>
+ <path
+ android:strokeColor="#FF000000"
+ android:strokeWidth="2"
+ android:pathData="M16,18 l16,0 l0,10 l-16,0z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_shortcut.xml b/slices/view/src/androidTest/res/drawable/ic_shortcut.xml
new file mode 100644
index 0000000..bf9572a
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_shortcut.xml
@@ -0,0 +1,34 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="48.0dp"
+ android:viewportHeight="48.0"
+ android:viewportWidth="48.0"
+ android:width="48.0dp">
+ <path
+ android:fillColor="#e2e2e2"
+ android:pathData="M24.0,24.0m-19.0,0.0a19.0,19.0 0.0,1.0 1.0,38.0 0.0a19.0,19.0 0.0,1.0 1.0,-38.0 0.0"/>
+ <group
+ android:scaleX=".7"
+ android:scaleY=".7"
+ android:translateX="7.2"
+ android:translateY="7.2">
+
+ <path
+ android:fillColor="#ff000000"
+ android:pathData="M12.0,36.0c0.0,1.0 0.9,2.0 2.0,2.0l2.0,0.0l0.0,7.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0l0.0,-7.0l4.0,0.0l0.0,7.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0l0.0,-7.0l2.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L36.0,16.0L12.0,16.0l0.0,20.0zM7.0,16.0c-1.66,0.0 -3.0,1.34 -3.0,3.0l0.0,14.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0L10.0,19.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0zm34.0,0.0c-1.66,0.0 -3.0,1.34 -3.0,3.0l0.0,14.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0L44.0,19.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0zM31.06,4.32l2.61,-2.61c0.39,-0.3 0.39,-1.02 0.0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0.0L29.3,3.25C27.7,2.46 25.91,2.0 24.0,2.0c-1.92,0.0 -3.7,0.46 -5.33,1.26L15.0,0.29c-0.39,-0.39 -1.02,-0.39 -1.41,0.0 -0.3,0.39 -0.39,1.02 0.0,1.41l2.62,2.62C13.94,6.51 12.0,10.03 12.0,14.0l24.0,0.0c0.0,-3.98 -1.95,-7.5 -4.94,-9.68zM20.0,10.0l-2.0,0.0L18.0,8.0l2.0,0.0l0.0,2.0zm10.0,0.0l-2.0,0.0L28.0,8.0l2.0,0.0l0.0,2.0z"/>
+ </group>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_small.xml b/slices/view/src/androidTest/res/drawable/ic_small.xml
new file mode 100644
index 0000000..8fd43df
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_small.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48.0dp"
+ android:height="48.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M34.0,2.02L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16,18 l16,0 l0,4 l-16,0z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_star_off.xml b/slices/view/src/androidTest/res/drawable/ic_star_off.xml
new file mode 100644
index 0000000..7f023b3
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_star_off.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_star_on.xml b/slices/view/src/androidTest/res/drawable/ic_star_on.xml
new file mode 100644
index 0000000..f3ca086
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_star_on.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_text.xml b/slices/view/src/androidTest/res/drawable/ic_text.xml
new file mode 100644
index 0000000..d2876bf
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_text.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_video.xml b/slices/view/src/androidTest/res/drawable/ic_video.xml
new file mode 100644
index 0000000..e23eac8
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_video.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_voice.xml b/slices/view/src/androidTest/res/drawable/ic_voice.xml
new file mode 100644
index 0000000..8f465bb
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_voice.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM17.3,12c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12L5,12c0,3.42 2.72,6.23 6,6.72L11,22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_wifi.xml b/slices/view/src/androidTest/res/drawable/ic_wifi.xml
new file mode 100644
index 0000000..4fbfd60
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_wifi.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+ android:fillAlpha=".3"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_work.xml b/slices/view/src/androidTest/res/drawable/ic_work.xml
new file mode 100644
index 0000000..6806402
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_work.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright 2017 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M0 0h24v24H0z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99 .89 -1.99 2L2
+19c0 1.11 .89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z" />
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/mady.jpg b/slices/view/src/androidTest/res/drawable/mady.jpg
new file mode 100644
index 0000000..8b61f1b
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/mady.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/slices_1.jpg b/slices/view/src/androidTest/res/drawable/slices_1.jpg
new file mode 100644
index 0000000..31cc065
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/slices_1.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/slices_2.jpg b/slices/view/src/androidTest/res/drawable/slices_2.jpg
new file mode 100644
index 0000000..adbe1d3
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/slices_2.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/slices_3.jpg b/slices/view/src/androidTest/res/drawable/slices_3.jpg
new file mode 100644
index 0000000..6617019
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/slices_3.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/slices_4.jpg b/slices/view/src/androidTest/res/drawable/slices_4.jpg
new file mode 100644
index 0000000..d00a8b3
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/slices_4.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/toggle_star.xml b/slices/view/src/androidTest/res/drawable/toggle_star.xml
new file mode 100644
index 0000000..e964925
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/toggle_star.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/on"
+ android:state_checked="true"
+ android:drawable="@drawable/ic_star_on" />
+ <item
+ android:id="@+id/off"
+ android:drawable="@drawable/ic_star_off" />
+</selector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/weather_1.png b/slices/view/src/androidTest/res/drawable/weather_1.png
new file mode 100644
index 0000000..7c4034e
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/weather_1.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/weather_2.png b/slices/view/src/androidTest/res/drawable/weather_2.png
new file mode 100644
index 0000000..f1b6672
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/weather_2.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/weather_3.png b/slices/view/src/androidTest/res/drawable/weather_3.png
new file mode 100644
index 0000000..a5db683
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/weather_3.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/weather_4.png b/slices/view/src/androidTest/res/drawable/weather_4.png
new file mode 100644
index 0000000..0b7f3b0
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/weather_4.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/layout/activity_demo.xml b/slices/view/src/androidTest/res/layout/activity_demo.xml
new file mode 100644
index 0000000..f557f40
--- /dev/null
+++ b/slices/view/src/androidTest/res/layout/activity_demo.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.android.support.content.demos.ContentPagerDemoActivity">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ android:theme="@style/AppTheme.AppBarOverlay"
+ app:popupTheme="@style/AppTheme.PopupOverlay"/>
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+</LinearLayout>
diff --git a/slices/view/src/androidTest/res/layout/render_layout.xml b/slices/view/src/androidTest/res/layout/render_layout.xml
new file mode 100644
index 0000000..a8ed779
--- /dev/null
+++ b/slices/view/src/androidTest/res/layout/render_layout.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2018 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="1200dp"
+ android:layout_height="400dp"
+ android:background="@android:color/black"
+ android:orientation="horizontal"
+ android:padding="20dp">
+
+
+ <FrameLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <androidx.app.slice.widget.SliceView
+ android:id="@+id/sv1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+
+ <FrameLayout android:layout_width="400dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="20dp">
+ <androidx.app.slice.widget.SliceView
+ android:id="@+id/sv2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@android:color/white"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"/>
+ </FrameLayout>
+
+ <FrameLayout android:layout_width="400dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="20dp">
+ <androidx.app.slice.widget.SliceView
+ android:id="@+id/sv3"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@android:color/white"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"/>
+ </FrameLayout>
+
+
+</LinearLayout>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/values/colors.xml b/slices/view/src/androidTest/res/values/colors.xml
new file mode 100644
index 0000000..86b4304
--- /dev/null
+++ b/slices/view/src/androidTest/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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.
+ -->
+
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/slices/view/src/androidTest/res/values/strings.xml b/slices/view/src/androidTest/res/values/strings.xml
new file mode 100644
index 0000000..89583bd
--- /dev/null
+++ b/slices/view/src/androidTest/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name">Slice Browser</string>
+</resources>
diff --git a/slices/view/src/androidTest/res/values/styles.xml b/slices/view/src/androidTest/res/values/styles.xml
new file mode 100644
index 0000000..afb6bad
--- /dev/null
+++ b/slices/view/src/androidTest/res/values/styles.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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.
+ -->
+
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+ <style name="AppTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+ <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
+ <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
+
+</resources>
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceUtils.java b/slices/view/src/main/java/androidx/app/slice/SliceUtils.java
index ededbfd..6a6ab14 100644
--- a/slices/view/src/main/java/androidx/app/slice/SliceUtils.java
+++ b/slices/view/src/main/java/androidx/app/slice/SliceUtils.java
@@ -16,6 +16,7 @@
package androidx.app.slice;
+import static android.app.slice.Slice.HINT_PARTIAL;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
@@ -29,6 +30,8 @@
import java.io.InputStream;
import java.io.OutputStream;
+import androidx.app.slice.core.SliceQuery;
+
/**
* Utilities for dealing with slices.
*/
@@ -155,4 +158,49 @@
return this;
}
}
+
+ /**
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @IntDef({
+ LOADING_ALL, LOADING_PARTIAL, LOADING_COMPLETE
+ })
+ public @interface SliceLoadingState{}
+
+ /**
+ * Indicates this slice is empty and waiting for content to be loaded.
+ */
+ public static final int LOADING_ALL = 0;
+ /**
+ * Indicates this slice has some content but is waiting for other content to be loaded.
+ */
+ public static final int LOADING_PARTIAL = 1;
+ /**
+ * Indicates this slice has fully loaded and is not waiting for other content.
+ */
+ public static final int LOADING_COMPLETE = 2;
+
+ /**
+ * @return the current loading state of the provided {@link Slice}.
+ *
+ * @see #LOADING_ALL
+ * @see #LOADING_PARTIAL
+ * @see #LOADING_COMPLETE
+ */
+ public static int getLoadingState(Slice slice) {
+ // Check loading state
+ boolean hasHintPartial =
+ SliceQuery.find(slice, null, HINT_PARTIAL, null) != null;
+ if (hasHintPartial && slice.getItems().size() == 0) {
+ // Empty slice
+ return LOADING_ALL;
+ } else if (hasHintPartial) {
+ // Slice with specific content to load
+ return LOADING_PARTIAL;
+ } else {
+ // Full slice
+ return LOADING_COMPLETE;
+ }
+ }
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
index 8d01c64..a5959d3 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
@@ -288,6 +288,8 @@
boolean title = SliceQuery.hasAnyHints(item, HINT_LARGE, HINT_TITLE);
TextView tv = (TextView) LayoutInflater.from(getContext()).inflate(title
? TITLE_TEXT_LAYOUT : TEXT_LAYOUT, null);
+ tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, title ? mTitleSize : mSubtitleSize);
+ tv.setTextColor(title ? mTitleColor : mSubtitleColor);
CharSequence text = FORMAT_TIMESTAMP.equals(format)
? SliceViewUtil.getRelativeTimeString(item.getTimestamp())
: item.getText();
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
index fa8397e..d015893 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
@@ -54,6 +54,12 @@
}
@Override
+ public void setTint(int tint) {
+ super.setTint(tint);
+ populate();
+ }
+
+ @Override
public @SliceView.SliceMode int getMode() {
return SliceView.MODE_LARGE;
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java b/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
index 86e9409..5b29ab2 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
@@ -19,6 +19,7 @@
import static android.app.slice.Slice.HINT_ACTIONS;
import static android.app.slice.Slice.HINT_LIST;
import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_SUMMARY;
import static android.app.slice.Slice.SUBTYPE_COLOR;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_INT;
@@ -33,7 +34,6 @@
import androidx.app.slice.Slice;
import androidx.app.slice.SliceItem;
-import androidx.app.slice.core.SliceHints;
import androidx.app.slice.core.SliceQuery;
/**
@@ -76,7 +76,7 @@
for (int i = 0; i < children.size(); i++) {
final SliceItem child = children.get(i);
final String format = child.getFormat();
- if (!child.hasAnyHints(SliceHints.HINT_SUMMARY, HINT_ACTIONS)
+ if (!child.hasAnyHints(HINT_SUMMARY, HINT_ACTIONS)
&& (FORMAT_ACTION.equals(format) || FORMAT_SLICE.equals(format))) {
if (!mHasHeader && !child.hasHint(HINT_LIST_ITEM)) {
mHasHeader = true;
@@ -125,7 +125,7 @@
private static SliceItem getSummaryItem(@NonNull Slice slice) {
List<SliceItem> items = slice.getItems();
// See if a summary is specified
- SliceItem summary = SliceQuery.find(slice, FORMAT_SLICE, SliceHints.HINT_SUMMARY, null);
+ SliceItem summary = SliceQuery.find(slice, FORMAT_SLICE, HINT_SUMMARY, null);
if (summary != null) {
return summary;
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
index 0e730a5..352983d 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
@@ -34,7 +34,6 @@
import java.util.List;
import androidx.app.slice.SliceItem;
-import androidx.app.slice.core.SliceHints;
import androidx.app.slice.core.SliceQuery;
/**
@@ -238,8 +237,7 @@
*/
private static boolean isStartType(SliceItem item) {
final String type = item.getFormat();
- return (!item.hasHint(SliceHints.SUBTYPE_TOGGLE)
- && (FORMAT_ACTION.equals(type) && (SliceQuery.find(item, FORMAT_IMAGE) != null)))
+ return (FORMAT_ACTION.equals(type) && (SliceQuery.find(item, FORMAT_IMAGE) != null))
|| FORMAT_IMAGE.equals(type)
|| FORMAT_TIMESTAMP.equals(type);
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
index 47a8045..a81c55b 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
@@ -16,18 +16,18 @@
package androidx.app.slice.widget;
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
import static android.app.slice.Slice.HINT_NO_TINT;
import static android.app.slice.Slice.HINT_SELECTED;
+import static android.app.slice.Slice.SUBTYPE_TOGGLE;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_INT;
import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static androidx.app.slice.core.SliceHints.EXTRA_SLIDER_VALUE;
-import static androidx.app.slice.core.SliceHints.EXTRA_TOGGLE_STATE;
import static androidx.app.slice.core.SliceHints.SUBTYPE_MAX;
import static androidx.app.slice.core.SliceHints.SUBTYPE_PROGRESS;
-import static androidx.app.slice.core.SliceHints.SUBTYPE_TOGGLE;
import static androidx.app.slice.widget.SliceView.MODE_LARGE;
import static androidx.app.slice.widget.SliceView.MODE_SMALL;
@@ -40,6 +40,7 @@
import android.support.annotation.ColorInt;
import android.support.annotation.RestrictTo;
import android.util.Log;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
@@ -168,12 +169,20 @@
if (titleItem != null) {
mPrimaryText.setText(titleItem.getText());
}
+ mPrimaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mIsHeader
+ ? mHeaderTitleSize
+ : mTitleSize);
+ mPrimaryText.setTextColor(mTitleColor);
mPrimaryText.setVisibility(titleItem != null ? View.VISIBLE : View.GONE);
final SliceItem subTitle = mRowContent.getSubtitleItem();
if (subTitle != null) {
mSecondaryText.setText(subTitle.getText());
}
+ mSecondaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mIsHeader
+ ? mHeaderSubtitleSize
+ : mSubtitleSize);
+ mSecondaryText.setTextColor(mSubtitleColor);
mSecondaryText.setVisibility(subTitle != null ? View.VISIBLE : View.GONE);
final SliceItem slider = mRowContent.getSlider();
@@ -343,7 +352,7 @@
SliceItem timeStamp = null;
ViewGroup container = isStart ? mStartContainer : mEndContainer;
if (FORMAT_ACTION.equals(sliceItem.getFormat())) {
- if (SliceQuery.hasHints(sliceItem.getSlice(), SUBTYPE_TOGGLE)) {
+ if (SUBTYPE_TOGGLE.equals(sliceItem.getSubType())) {
addToggle(sliceItem, color, container);
return true;
}
@@ -371,6 +380,8 @@
} else if (timeStamp != null) {
TextView tv = new TextView(getContext());
tv.setText(SliceViewUtil.getRelativeTimeString(sliceItem.getTimestamp()));
+ tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSubtitleSize);
+ tv.setTextColor(mSubtitleColor);
container.addView(tv);
addedView = tv;
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
index f731c96..a9faf86 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
@@ -17,6 +17,7 @@
package androidx.app.slice.widget;
import android.content.Context;
+import android.content.res.TypedArray;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
@@ -26,6 +27,7 @@
import androidx.app.slice.Slice;
import androidx.app.slice.SliceItem;
+import androidx.app.slice.view.R;
/**
* Base class for children views of {@link SliceView}.
@@ -35,7 +37,15 @@
public abstract class SliceChildView extends FrameLayout {
protected SliceView.OnSliceActionListener mObserver;
- protected int mTintColor;
+ protected int mTintColor = -1;
+ protected int mTitleColor;
+ protected int mSubtitleColor;
+ protected int mHeaderTitleSize;
+ protected int mHeaderSubtitleSize;
+ protected int mTitleSize;
+ protected int mSubtitleSize;
+ protected int mGridTitleSize;
+ protected int mGridSubtitleSize;
public SliceChildView(@NonNull Context context) {
super(context);
@@ -85,7 +95,26 @@
* Populates style information for this view.
*/
public void setStyle(AttributeSet attrs) {
- // TODO
+ TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.SliceView,
+ R.attr.sliceViewStyle, R.style.Widget_SliceView);
+ try {
+ int themeColor = a.getColor(R.styleable.SliceView_tintColor, -1);
+ mTintColor = themeColor != -1 ? themeColor : mTintColor;
+ mTitleColor = a.getColor(R.styleable.SliceView_titleColor, 0);
+ mSubtitleColor = a.getColor(R.styleable.SliceView_subtitleColor, 0);
+ mHeaderTitleSize = (int) a.getDimension(
+ R.styleable.SliceView_headerTitleSize, 0);
+ mHeaderSubtitleSize = (int) a.getDimension(
+ R.styleable.SliceView_headerSubtitleSize, 0);
+ mTitleSize = (int) a.getDimension(R.styleable.SliceView_titleSize, 0);
+ mSubtitleSize = (int) a.getDimension(
+ R.styleable.SliceView_subtitleSize, 0);
+ mGridTitleSize = (int) a.getDimension(R.styleable.SliceView_gridTitleSize, 0);
+ mGridSubtitleSize = (int) a.getDimension(
+ R.styleable.SliceView_gridSubtitleSize, 0);
+ } finally {
+ a.recycle();
+ }
}
/**
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
index dbf1d67..b974814 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
@@ -24,6 +24,7 @@
import android.arch.lifecycle.Observer;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.drawable.ColorDrawable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
@@ -119,6 +120,7 @@
* that selection.
*/
private static final int MODE_AUTO = 0;
+
private int mMode = MODE_AUTO;
private SliceChildView mCurrentView;
private Slice mCurrentSlice;
@@ -129,24 +131,31 @@
private boolean mShowActions = true;
private boolean mIsScrollable = true;
- private int mThemeTintColor = -1;
private AttributeSet mAttrs;
+ private int mThemeTintColor;
public SliceView(Context context) {
this(context, null);
}
public SliceView(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, R.attr.sliceViewStyle);
}
public SliceView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
+ this(context, attrs, defStyleAttr, R.style.Widget_SliceView);
}
public SliceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mAttrs = attrs;
+ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SliceView,
+ defStyleAttr, defStyleRes);
+ try {
+ mThemeTintColor = a.getColor(R.styleable.SliceView_tintColor, -1);
+ } finally {
+ a.recycle();
+ }
mActions = new ActionRow(getContext(), true);
mActions.setBackground(new ColorDrawable(0xffeeeeee));
mCurrentView = new LargeTemplateView(getContext());
@@ -247,6 +256,18 @@
}
/**
+ * Contents of a slice such as icons, text, and controls (e.g. toggle) can be tinted. Normally
+ * a color for tinting will be provided by the slice. Using this method will override
+ * this color information and instead tint elements with the provided color.
+ *
+ * @param tintColor the color to use for tinting contents of this view.
+ */
+ public void setTint(int tintColor) {
+ mThemeTintColor = tintColor;
+ mCurrentView.setTint(tintColor);
+ }
+
+ /**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@@ -318,6 +339,7 @@
}
// Styles
mCurrentView.setStyle(mAttrs);
+ mCurrentView.setTint(getTintColor());
// Set the slice
SliceItem actionRow = SliceQuery.find(mCurrentSlice, FORMAT_SLICE,
HINT_ACTIONS,
diff --git a/slices/view/src/main/res-public/values/public_attrs.xml b/slices/view/src/main/res-public/values/public_attrs.xml
new file mode 100644
index 0000000..ad909ea
--- /dev/null
+++ b/slices/view/src/main/res-public/values/public_attrs.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2017 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.
+ -->
+
+<!-- Definitions of attributes to be exposed to the public -->
+<resources>
+ <public type="attr" name="titleColor" />
+ <public type="attr" name="subtitleColor" />
+ <public type="attr" name="tintColor" />
+ <public type="attr" name="headerTitleSize" />
+ <public type="attr" name="headerSubtitleSize" />
+ <public type="attr" name="titleSize" />
+ <public type="attr" name="subtitleSize" />
+ <public type="attr" name="gridTitleSize" />
+ <public type="attr" name="gridSubtitleSize" />
+ <public type="attr" name="sliceViewStyle" />
+</resources>
\ No newline at end of file
diff --git a/slices/view/src/main/res-public/values/public_styles.xml b/slices/view/src/main/res-public/values/public_styles.xml
new file mode 100644
index 0000000..36f3e26
--- /dev/null
+++ b/slices/view/src/main/res-public/values/public_styles.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2018 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.
+ -->
+
+<!-- Definitions of styles to be exposed to the public -->
+<resources>
+ <public type="style" name="Widget.SliceView"/>
+</resources>
\ No newline at end of file
diff --git a/slices/view/src/main/res/layout/abc_slice_small_template.xml b/slices/view/src/main/res/layout/abc_slice_small_template.xml
index 706ded6..2d5e913 100644
--- a/slices/view/src/main/res/layout/abc_slice_small_template.xml
+++ b/slices/view/src/main/res/layout/abc_slice_small_template.xml
@@ -43,16 +43,12 @@
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceListItem"
- android:textColor="?android:attr/textColorPrimary"
android:maxLines="2"/>
<TextView android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@android:id/title"
- android:textAppearance="?attr/textAppearanceListItemSecondary"
- android:textColor="?android:attr/textColorSecondary"
android:maxLines="10" />
<SeekBar
diff --git a/slices/view/src/main/res/values/attrs.xml b/slices/view/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..5779d31
--- /dev/null
+++ b/slices/view/src/main/res/values/attrs.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2018 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.
+ -->
+
+<resources>
+ <declare-styleable name="SliceView">
+ <!-- Colors -->
+ <attr name="titleColor" format="color" />
+ <attr name="subtitleColor" format="color" />
+ <attr name="tintColor" format="color" />
+
+ <!-- Text sizes -->
+ <attr name="headerTitleSize" format="dimension" />
+ <attr name="headerSubtitleSize" format="dimension"/>
+ <attr name="titleSize" format="dimension" />
+ <attr name="subtitleSize" format="dimension" />
+ <attr name="gridTitleSize" format="dimension" />
+ <attr name="gridSubtitleSize" format="dimension" />
+ </declare-styleable>
+
+ <attr name="sliceViewStyle" format="reference"/>
+</resources>
\ No newline at end of file
diff --git a/slices/view/src/main/res/values/styles.xml b/slices/view/src/main/res/values/styles.xml
new file mode 100644
index 0000000..4b27820
--- /dev/null
+++ b/slices/view/src/main/res/values/styles.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2018 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.
+ -->
+
+<resources>
+ <style name="Widget.SliceView" parent="">
+ <item name="tintColor">@null</item>
+ <!-- Colors -->
+ <item name="titleColor">?android:attr/textColorPrimary</item>
+ <item name="subtitleColor">?android:attr/textColorSecondary</item>
+
+ <!-- Text sizes -->
+ <item name="headerTitleSize">16sp</item>
+ <item name="headerSubtitleSize">14sp</item>
+ <item name="titleSize">14sp</item>
+ <item name="subtitleSize">14sp</item>
+ <item name="gridTitleSize">12sp</item>
+ <item name="gridSubtitleSize">12sp</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/ActivityChooserView.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActivityChooserView.java
index ddcb9fc..9979363 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/ActivityChooserView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/ActivityChooserView.java
@@ -44,6 +44,7 @@
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
@@ -857,7 +858,7 @@
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
- public static class InnerLayout extends LinearLayoutCompat {
+ public static class InnerLayout extends LinearLayout {
private static final int[] TINT_ATTRS = {
android.R.attr.background
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/ScrollingTabContainerView.java b/v7/appcompat/src/main/java/android/support/v7/widget/ScrollingTabContainerView.java
index 345e318..1244508f 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/ScrollingTabContainerView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/ScrollingTabContainerView.java
@@ -42,6 +42,7 @@
import android.widget.BaseAdapter;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
@@ -375,7 +376,7 @@
// no-op
}
- private class TabView extends LinearLayoutCompat {
+ private class TabView extends LinearLayout {
private final int[] BG_ATTRS = {
android.R.attr.background
};
diff --git a/v7/preference/res/layout-v11/preference.xml b/v7/preference/res/layout-v11/preference.xml
deleted file mode 100644
index 981288f..0000000
--- a/v7/preference/res/layout-v11/preference.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2015 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
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingEnd="?android:attr/scrollbarSize"
- android:background="?android:attr/selectableItemBackground"
- android:focusable="true" >
-
- <FrameLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <android.support.v7.internal.widget.PreferenceImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:maxWidth="48dp"
- app:maxHeight="48dp" />
- </FrameLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="15dip"
- android:layout_marginEnd="6dip"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="6dip"
- android:layout_weight="1">
-
- <TextView android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textColor="?android:attr/textColorPrimary"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
-
- <TextView android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/title"
- android:layout_alignStart="@android:id/title"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="4" />
-
- </RelativeLayout>
-
- <!-- Preference should place its actual preference widget here. -->
- <LinearLayout android:id="@android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical" />
-
-</LinearLayout>
diff --git a/v7/preference/res/layout-v11/preference_dropdown.xml b/v7/preference/res/layout-v11/preference_dropdown.xml
deleted file mode 100644
index 0e5b35dc..0000000
--- a/v7/preference/res/layout-v11/preference_dropdown.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2016 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
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingEnd="?android:attr/scrollbarSize"
- android:background="?android:attr/selectableItemBackground"
- android:focusable="true" >
-
- <Spinner
- android:id="@+id/spinner"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:visibility="invisible" />
-
- <FrameLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <android.support.v7.internal.widget.PreferenceImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:maxWidth="48dp"
- app:maxHeight="48dp" />
- </FrameLayout>
-
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="15dip"
- android:layout_marginEnd="6dip"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="6dip"
- android:layout_weight="1">
-
- <TextView android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textColor="?android:attr/textColorPrimary"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
-
- <TextView android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/title"
- android:layout_alignStart="@android:id/title"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="4" />
-
- </RelativeLayout>
-
- <!-- Preference should place its actual preference widget here. -->
- <LinearLayout android:id="@android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical" />
-
-</LinearLayout>
diff --git a/v7/preference/res/layout-v7/expand_button.xml b/v7/preference/res/layout/expand_button.xml
similarity index 100%
rename from v7/preference/res/layout-v7/expand_button.xml
rename to v7/preference/res/layout/expand_button.xml
diff --git a/v7/preference/res/layout/preference.xml b/v7/preference/res/layout/preference.xml
index f75bc68..981288f 100644
--- a/v7/preference/res/layout/preference.xml
+++ b/v7/preference/res/layout/preference.xml
@@ -16,24 +16,25 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingEnd="?android:attr/scrollbarSize"
- android:background="@android:drawable/list_selector_background"
+ android:background="?android:attr/selectableItemBackground"
android:focusable="true" >
<FrameLayout
android:id="@+id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <ImageView
+ <android.support.v7.internal.widget.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- />
+ app:maxWidth="48dp"
+ app:maxHeight="48dp" />
</FrameLayout>
<RelativeLayout
diff --git a/v7/preference/res/layout/preference_dropdown.xml b/v7/preference/res/layout/preference_dropdown.xml
index 1c51e09..0e5b35dc 100644
--- a/v7/preference/res/layout/preference_dropdown.xml
+++ b/v7/preference/res/layout/preference_dropdown.xml
@@ -16,12 +16,13 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingEnd="?android:attr/scrollbarSize"
- android:background="@android:drawable/list_selector_background"
+ android:background="?android:attr/selectableItemBackground"
android:focusable="true" >
<Spinner
@@ -34,12 +35,12 @@
android:id="@+id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <ImageView
+ <android.support.v7.internal.widget.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- />
+ app:maxWidth="48dp"
+ app:maxHeight="48dp" />
</FrameLayout>
<RelativeLayout
diff --git a/wear/res/drawable-v23/ws_action_item_background.xml b/wear/res/drawable/ws_action_item_background.xml
similarity index 100%
rename from wear/res/drawable-v23/ws_action_item_background.xml
rename to wear/res/drawable/ws_action_item_background.xml
diff --git a/wear/res/drawable-v23/ws_action_item_icon_background.xml b/wear/res/drawable/ws_action_item_icon_background.xml
similarity index 100%
rename from wear/res/drawable-v23/ws_action_item_icon_background.xml
rename to wear/res/drawable/ws_action_item_icon_background.xml
diff --git a/wear/res/drawable-v23/ws_ic_expand_less_white_22.xml b/wear/res/drawable/ws_ic_expand_less_white_22.xml
similarity index 100%
rename from wear/res/drawable-v23/ws_ic_expand_less_white_22.xml
rename to wear/res/drawable/ws_ic_expand_less_white_22.xml
diff --git a/wear/res/drawable-v23/ws_ic_expand_more_white_22.xml b/wear/res/drawable/ws_ic_expand_more_white_22.xml
similarity index 100%
rename from wear/res/drawable-v23/ws_ic_expand_more_white_22.xml
rename to wear/res/drawable/ws_ic_expand_more_white_22.xml
diff --git a/wear/res/drawable-v23/ws_ic_more_horiz_24dp_wht.xml b/wear/res/drawable/ws_ic_more_horiz_24dp_wht.xml
similarity index 100%
rename from wear/res/drawable-v23/ws_ic_more_horiz_24dp_wht.xml
rename to wear/res/drawable/ws_ic_more_horiz_24dp_wht.xml
diff --git a/wear/res/drawable-v23/ws_ic_more_vert_24dp_wht.xml b/wear/res/drawable/ws_ic_more_vert_24dp_wht.xml
similarity index 100%
rename from wear/res/drawable-v23/ws_ic_more_vert_24dp_wht.xml
rename to wear/res/drawable/ws_ic_more_vert_24dp_wht.xml
diff --git a/wear/res/drawable-v23/ws_switch_thumb_material_anim.xml b/wear/res/drawable/ws_switch_thumb_material_anim.xml
similarity index 100%
rename from wear/res/drawable-v23/ws_switch_thumb_material_anim.xml
rename to wear/res/drawable/ws_switch_thumb_material_anim.xml
diff --git a/wear/res/layout-v23/ws_action_drawer_item_view.xml b/wear/res/layout/ws_action_drawer_item_view.xml
similarity index 100%
rename from wear/res/layout-v23/ws_action_drawer_item_view.xml
rename to wear/res/layout/ws_action_drawer_item_view.xml
diff --git a/wear/res/layout-v23/ws_action_drawer_peek_view.xml b/wear/res/layout/ws_action_drawer_peek_view.xml
similarity index 100%
rename from wear/res/layout-v23/ws_action_drawer_peek_view.xml
rename to wear/res/layout/ws_action_drawer_peek_view.xml
diff --git a/wear/res/layout-v23/ws_action_drawer_title_view.xml b/wear/res/layout/ws_action_drawer_title_view.xml
similarity index 100%
rename from wear/res/layout-v23/ws_action_drawer_title_view.xml
rename to wear/res/layout/ws_action_drawer_title_view.xml
diff --git a/wear/res/layout-v23/ws_wearable_drawer_view.xml b/wear/res/layout/ws_wearable_drawer_view.xml
similarity index 100%
rename from wear/res/layout-v23/ws_wearable_drawer_view.xml
rename to wear/res/layout/ws_wearable_drawer_view.xml
diff --git a/wear/res/values-v23/styles.xml b/wear/res/values-v23/styles.xml
deleted file mode 100644
index 63ed2d8..0000000
--- a/wear/res/values-v23/styles.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<resources>
- <style name="WsPageIndicatorViewStyle">
- <item name="wsPageIndicatorDotSpacing">7.8dp</item>
- <item name="wsPageIndicatorDotRadius">2.1dp</item>
- <item name="wsPageIndicatorDotRadiusSelected">3.1dp</item>
- <item name="wsPageIndicatorDotColor">?android:attr/colorForeground</item>
- <item name="wsPageIndicatorDotColorSelected">?android:attr/colorForeground</item>
- <item name="wsPageIndicatorDotFadeOutDelay">1000</item>
- <item name="wsPageIndicatorDotFadeOutDuration">250</item>
- <item name="wsPageIndicatorDotFadeInDuration">100</item>
- <item name="wsPageIndicatorDotFadeWhenIdle">true</item>
- <item name="wsPageIndicatorDotShadowColor">#66000000</item>
- <item name="wsPageIndicatorDotShadowRadius">1dp</item>
- <item name="wsPageIndicatorDotShadowDx">0.5dp</item>
- <item name="wsPageIndicatorDotShadowDy">0.5dp</item>
- </style>
-
- <style name="WsWearableActionDrawerItemText">
- <item name="android:layout_gravity">center_vertical</item>
- <item name="android:ellipsize">end</item>
- <item name="android:fontFamily">sans-serif-condensed-light</item>
- <item name="android:maxLines">3</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:textSize">@dimen/ws_action_drawer_item_text_size</item>
- </style>
- <style name="WsWearableActionDrawerTitleText" parent="android:TextAppearance.Material.Subhead">
- <item name="android:alpha">0.7</item>
- </style>
-</resources>
diff --git a/wear/res/values/styles.xml b/wear/res/values/styles.xml
index 1908946..0a5127d 100644
--- a/wear/res/values/styles.xml
+++ b/wear/res/values/styles.xml
@@ -36,4 +36,31 @@
<item name="android:elevation">@dimen/ws_wearable_drawer_view_elevation</item>
<item name="android:background">?android:attr/colorBackgroundFloating</item>
</style>
+ <style name="WsPageIndicatorViewStyle">
+ <item name="wsPageIndicatorDotSpacing">7.8dp</item>
+ <item name="wsPageIndicatorDotRadius">2.1dp</item>
+ <item name="wsPageIndicatorDotRadiusSelected">3.1dp</item>
+ <item name="wsPageIndicatorDotColor">?android:attr/colorForeground</item>
+ <item name="wsPageIndicatorDotColorSelected">?android:attr/colorForeground</item>
+ <item name="wsPageIndicatorDotFadeOutDelay">1000</item>
+ <item name="wsPageIndicatorDotFadeOutDuration">250</item>
+ <item name="wsPageIndicatorDotFadeInDuration">100</item>
+ <item name="wsPageIndicatorDotFadeWhenIdle">true</item>
+ <item name="wsPageIndicatorDotShadowColor">#66000000</item>
+ <item name="wsPageIndicatorDotShadowRadius">1dp</item>
+ <item name="wsPageIndicatorDotShadowDx">0.5dp</item>
+ <item name="wsPageIndicatorDotShadowDy">0.5dp</item>
+ </style>
+
+ <style name="WsWearableActionDrawerItemText">
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:fontFamily">sans-serif-condensed-light</item>
+ <item name="android:maxLines">3</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">@dimen/ws_action_drawer_item_text_size</item>
+ </style>
+ <style name="WsWearableActionDrawerTitleText" parent="android:TextAppearance.Material.Subhead">
+ <item name="android:alpha">0.7</item>
+ </style>
</resources>