Remove all the extra accessor methods added by javac in support-vector-drawable.
am: 8fbfb9b792
Change-Id: I8985df2e8fff9b1163fdfa6ee074e792dacf0af3
diff --git a/annotations/src/android/support/annotation/RestrictTo.java b/annotations/src/android/support/annotation/RestrictTo.java
new file mode 100644
index 0000000..65c8ba0
--- /dev/null
+++ b/annotations/src/android/support/annotation/RestrictTo.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+package android.support.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+/**
+ * Denotes that the annotated element should only be accessed from within a
+ * specific scope (as defined by {@link Scope}).
+ * <p>
+ * Example of restricting usage within a library (based on gradle group ID):
+ * <pre><code>
+ * @RestrictTo(GROUP_ID)
+ * public void resetPaddingToInitialValues() { ...
+ * </code></pre>
+ * Example of restricting usage to tests:
+ * <pre><code>
+ * @RestrictScope(TESTS)
+ * public abstract int getUserId();
+ * </code></pre>
+ * Example of restricting usage to subclasses:
+ * <pre><code>
+ * @RestrictScope(SUBCLASSES)
+ * public void onDrawForeground(Canvas canvas) { ...
+ * </code></pre>
+ */
+@Retention(CLASS)
+@Target({ANNOTATION_TYPE,TYPE,METHOD,CONSTRUCTOR,FIELD,PACKAGE})
+public @interface RestrictTo {
+
+ /**
+ * The scope to which usage should be restricted.
+ */
+ Scope[] value();
+
+ enum Scope {
+ /**
+ * Restrict usage to code within the same group ID (based on gradle
+ * group ID).
+ */
+ GROUP_ID,
+
+ /**
+ * Restrict usage to tests.
+ */
+ TESTS,
+
+ /**
+ * Restrict usage to subclasses of the enclosing class.
+ * <p>
+ * <strong>Note:</strong> This scope should not be used to annotate
+ * packages.
+ */
+ SUBCLASSES,
+ }
+}
diff --git a/api/current.txt b/api/current.txt
index bd2ea01..b2101c7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -312,6 +312,26 @@
method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean);
}
+ public class BottomNavigationView extends android.widget.FrameLayout {
+ ctor public BottomNavigationView(android.content.Context);
+ ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet);
+ ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet, int);
+ method public int getItemBackgroundResource();
+ method public android.content.res.ColorStateList getItemIconTintList();
+ method public android.content.res.ColorStateList getItemTextColor();
+ method public int getMaxItemCount();
+ method public android.view.Menu getMenu();
+ method public void inflateMenu(int);
+ method public void setItemBackgroundResource(int);
+ method public void setItemIconTintList(android.content.res.ColorStateList);
+ method public void setItemTextColor(android.content.res.ColorStateList);
+ method public void setOnNavigationItemSelectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener);
+ }
+
+ public static abstract interface BottomNavigationView.OnNavigationItemSelectedListener {
+ method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
+ }
+
public class BottomSheetBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
ctor public BottomSheetBehavior();
ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
@@ -504,6 +524,7 @@
method public float getCompatElevation();
method public android.graphics.drawable.Drawable getContentBackground();
method public boolean getContentRect(android.graphics.Rect);
+ method public int getRippleColor();
method public int getSize();
method public boolean getUseCompatPadding();
method public void hide();
@@ -988,6 +1009,7 @@
package android.support.v13.app {
public class ActivityCompat extends android.support.v4.app.ActivityCompat {
+ ctor protected ActivityCompat();
method public static android.support.v13.view.DragAndDropPermissionsCompat requestDragAndDropPermissions(android.app.Activity, android.view.DragEvent);
}
@@ -1054,6 +1076,38 @@
}
+package android.support.v13.view.inputmethod {
+
+ public final class EditorInfoCompat {
+ ctor public EditorInfoCompat();
+ method public static java.lang.String[] getContentMimeTypes(android.view.inputmethod.EditorInfo);
+ method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, java.lang.String[]);
+ }
+
+ public final class InputConnectionCompat {
+ ctor public InputConnectionCompat();
+ method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, android.support.v13.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle);
+ method public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, android.support.v13.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+ field public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
+ }
+
+ public static abstract interface InputConnectionCompat.OnCommitContentListener {
+ method public abstract boolean onCommitContent(android.support.v13.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle);
+ }
+
+ public final class InputContentInfoCompat {
+ ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public java.lang.Object unwrap();
+ method public static android.support.v13.view.inputmethod.InputContentInfoCompat wrap(java.lang.Object);
+ }
+
+}
+
package android.support.v14.preference {
public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
@@ -3665,10 +3719,10 @@
}
public class ActivityCompat extends android.support.v4.content.ContextCompat {
- ctor public deprecated ActivityCompat();
+ ctor protected ActivityCompat();
method public static void finishAffinity(android.app.Activity);
method public static void finishAfterTransition(android.app.Activity);
- method public deprecated android.net.Uri getReferrer(android.app.Activity);
+ method public static android.net.Uri getReferrer(android.app.Activity);
method public static boolean invalidateOptionsMenu(android.app.Activity);
method public static void postponeEnterTransition(android.app.Activity);
method public static void requestPermissions(android.app.Activity, java.lang.String[], int);
@@ -4614,7 +4668,7 @@
}
public class ContextCompat {
- ctor public deprecated ContextCompat();
+ ctor protected ContextCompat();
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);
@@ -5489,7 +5543,11 @@
public final class ConnectivityManagerCompat {
method public static android.net.NetworkInfo getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+ method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
method public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+ field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+ field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+ field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
}
public final class TrafficStatsCompat {
@@ -6259,6 +6317,7 @@
method public static android.content.res.ColorStateList getBackgroundTintList(android.view.View);
method public static android.graphics.PorterDuff.Mode getBackgroundTintMode(android.view.View);
method public static android.graphics.Rect getClipBounds(android.view.View);
+ method public static android.view.Display getDisplay(android.view.View);
method public static float getElevation(android.view.View);
method public static boolean getFitsSystemWindows(android.view.View);
method public static int getImportantForAccessibility(android.view.View);
@@ -6322,6 +6381,7 @@
method public static void setAccessibilityLiveRegion(android.view.View, int);
method public static void setActivated(android.view.View, boolean);
method public static void setAlpha(android.view.View, float);
+ method public static void setBackground(android.view.View, android.graphics.drawable.Drawable);
method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList);
method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode);
method public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup, boolean);
@@ -6439,6 +6499,7 @@
method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
method public void setPageMarginDrawable(int);
method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
+ method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer, int);
field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
field public static final int SCROLL_STATE_IDLE = 0; // 0x0
field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
@@ -7377,6 +7438,8 @@
ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
method public boolean canChildScrollUp();
method public int getProgressCircleDiameter();
+ method public int getProgressViewEndOffset();
+ method public int getProgressViewStartOffset();
method public boolean isRefreshing();
method protected void onLayout(boolean, int, int, int, int);
method public void onMeasure(int, int);
@@ -7875,6 +7938,14 @@
ctor public NotificationCompat.Builder(android.content.Context);
}
+ public static class NotificationCompat.DecoratedCustomViewStyle extends android.support.v4.app.NotificationCompat.Style {
+ ctor public NotificationCompat.DecoratedCustomViewStyle();
+ }
+
+ public static class NotificationCompat.DecoratedMediaCustomViewStyle extends android.support.v7.app.NotificationCompat.MediaStyle {
+ ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+ }
+
public static class NotificationCompat.MediaStyle extends android.support.v4.app.NotificationCompat.Style {
ctor public NotificationCompat.MediaStyle();
ctor public NotificationCompat.MediaStyle(android.support.v4.app.NotificationCompat.Builder);
@@ -9076,6 +9147,14 @@
method public void runPendingAnimations();
}
+ public class DividerItemDecoration extends android.support.v7.widget.RecyclerView.ItemDecoration {
+ ctor public DividerItemDecoration(android.content.Context, int);
+ method public void setDrawable(android.graphics.drawable.Drawable);
+ method public void setOrientation(int);
+ field public static final int HORIZONTAL = 0; // 0x0
+ field public static final int VERTICAL = 1; // 0x1
+ }
+
public class GridLayout extends android.view.ViewGroup {
ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
ctor public GridLayout(android.content.Context, android.util.AttributeSet);
@@ -9434,6 +9513,7 @@
method public deprecated int getChildPosition(android.view.View);
method public android.support.v7.widget.RecyclerView.ViewHolder getChildViewHolder(android.view.View);
method public android.support.v7.widget.RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate();
+ method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
method public android.support.v7.widget.RecyclerView.ItemAnimator getItemAnimator();
method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
method public int getMaxFlingVelocity();
@@ -9680,6 +9760,7 @@
method public boolean isAttachedToWindow();
method public boolean isAutoMeasureEnabled();
method public boolean isFocused();
+ method public final boolean isItemPrefetchEnabled();
method public boolean isLayoutHierarchical(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
method public boolean isMeasurementCacheEnabled();
method public boolean isSmoothScrolling();
@@ -9733,6 +9814,7 @@
method public void scrollToPosition(int);
method public int scrollVerticallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
method public void setAutoMeasureEnabled(boolean);
+ method public final void setItemPrefetchEnabled(boolean);
method public void setMeasuredDimension(android.graphics.Rect, int, int);
method public void setMeasuredDimension(int, int);
method public void setMeasurementCacheEnabled(boolean);
diff --git a/api/removed.txt b/api/removed.txt
index 7dadbb7..401cf00 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,12 +1,3 @@
-package android.support.v4.content {
-
- public class ContextCompat {
- method public static deprecated android.content.Context createDeviceEncryptedStorageContext(android.content.Context);
- method public static deprecated boolean isDeviceEncryptedStorage(android.content.Context);
- }
-
-}
-
package android.support.v4.os {
public class UserManagerCompat {
diff --git a/build.gradle b/build.gradle
index 4cc4f89..8768f56 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,8 +30,8 @@
doclava project(':doclava')
}
-ext.supportVersion = '24.2.1'
-ext.extraVersion = 37
+ext.supportVersion = '25.0.0-SNAPSHOT'
+ext.extraVersion = 36
ext.supportRepoOut = ''
ext.buildToolsVersion = '23.0.2'
ext.buildNumber = Integer.toString(ext.extraVersion)
@@ -224,8 +224,16 @@
def sourceSet = subProject.sourceSets.create(name)
sourceSet.java.srcDirs = [folder]
- def configName = sourceSet.getCompileConfigurationName()
+ // The Android gradle plugin doesn't touch Java sub-tasks, so we need to
+ // manually set the Java task's boot classpath to the correct Android SDK.
+ def compileJavaTaskName = sourceSet.getCompileJavaTaskName();
+ def compileJavaOptions = subProject.tasks."${compileJavaTaskName}".options
+ compileJavaOptions.bootClasspath = getAndroidPrebuilt(apiLevel)
+ // Useful for cleaning up compiler warnings...
+ //compileJavaOptions.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
+
+ def configName = sourceSet.getCompileConfigurationName()
subProject.getDependencies().add(configName, getAndroidPrebuilt(apiLevel))
if (previousSource != null) {
setupDependencies(subProject, configName, previousSource)
diff --git a/buildSrc/studioCompat.gradle b/buildSrc/studioCompat.gradle
index 123eec1..1712bda 100644
--- a/buildSrc/studioCompat.gradle
+++ b/buildSrc/studioCompat.gradle
@@ -106,7 +106,8 @@
new ApiModule("ics", 14),
new ApiModule("ics-mr1", 15),
new ApiModule("api23", 23),
- new ApiModule("api24", ApiModule.CURRENT)
+ new ApiModule("api24", 24),
+ new ApiModule("api25", ApiModule.CURRENT)
],
dependencies : [":support-v4"],
folder : "v13",
diff --git a/compat/api21/android/support/v4/app/ActivityCompat21.java b/compat/api21/android/support/v4/app/ActivityCompatApi21.java
similarity index 99%
rename from compat/api21/android/support/v4/app/ActivityCompat21.java
rename to compat/api21/android/support/v4/app/ActivityCompatApi21.java
index 2e6de1e..51888d4 100644
--- a/compat/api21/android/support/v4/app/ActivityCompat21.java
+++ b/compat/api21/android/support/v4/app/ActivityCompatApi21.java
@@ -30,7 +30,7 @@
import java.util.List;
import java.util.Map;
-class ActivityCompat21 {
+class ActivityCompatApi21 {
public static void setMediaController(Activity activity, Object mediaControllerObj) {
activity.setMediaController((MediaController) mediaControllerObj);
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/compat/api22/android/support/v4/app/ActivityCompatApi22.java
similarity index 96%
rename from compat/api22/android/support/v4/app/ActivityCompat22.java
rename to compat/api22/android/support/v4/app/ActivityCompatApi22.java
index 3946f1d..c56d490 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/compat/api22/android/support/v4/app/ActivityCompatApi22.java
@@ -19,7 +19,7 @@
import android.app.Activity;
import android.net.Uri;
-class ActivityCompat22 {
+class ActivityCompatApi22 {
public static Uri getReferrer(Activity activity) {
return activity.getReferrer();
}
diff --git a/compat/api23/android/support/v4/app/ActivityCompatApi23.java b/compat/api23/android/support/v4/app/ActivityCompatApi23.java
index 5ed84df..ab46058 100644
--- a/compat/api23/android/support/v4/app/ActivityCompatApi23.java
+++ b/compat/api23/android/support/v4/app/ActivityCompatApi23.java
@@ -69,7 +69,7 @@
}
public abstract static class SharedElementCallback23
- extends ActivityCompat21.SharedElementCallback21 {
+ extends ActivityCompatApi21.SharedElementCallback21 {
public abstract void onSharedElementsArrived(List<String> sharedElementNames,
List<View> sharedElements, OnSharedElementsReadyListenerBridge listener);
}
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java
similarity index 60%
copy from compat/api22/android/support/v4/app/ActivityCompat22.java
copy to compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java
index 3946f1d..5e0edf9 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/compat/api24/android/support/v4/net/ConnectivityManagerCompatApi24.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package android.support.v4.app;
+package android.support.v4.net;
-import android.app.Activity;
-import android.net.Uri;
+import android.net.ConnectivityManager;
-class ActivityCompat22 {
- public static Uri getReferrer(Activity activity) {
- return activity.getReferrer();
+/**
+ * Implementation of ConnectivityManagerCompat that can use API 24 APIs.
+ */
+class ConnectivityManagerCompatApi24 {
+ public static int getRestrictBackgroundStatus(ConnectivityManager cm) {
+ return cm.getRestrictBackgroundStatus();
}
}
diff --git a/compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorBase.java b/compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorBase.java
new file mode 100644
index 0000000..afac122
--- /dev/null
+++ b/compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorBase.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.os;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+class ParcelableCompatCreatorBase<T> implements Parcelable.Creator<T> {
+ final ParcelableCompatCreatorCallbacks<T> mCallbacks;
+
+ public ParcelableCompatCreatorBase(ParcelableCompatCreatorCallbacks<T> callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public T createFromParcel(Parcel source) {
+ return mCallbacks.createFromParcel(source, null);
+ }
+
+ @Override
+ public T[] newArray(int size) {
+ return mCallbacks.newArray(size);
+ }
+}
diff --git a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorCallbacks.java b/compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
similarity index 100%
rename from compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
rename to compat/gingerbread/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
diff --git a/compat/gingerbread/android/support/v4/view/ViewCompatBase.java b/compat/gingerbread/android/support/v4/view/ViewCompatBase.java
index f4e113e..e7882bd 100644
--- a/compat/gingerbread/android/support/v4/view/ViewCompatBase.java
+++ b/compat/gingerbread/android/support/v4/view/ViewCompatBase.java
@@ -16,10 +16,13 @@
package android.support.v4.view;
+import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
+import android.view.Display;
import android.view.View;
import android.view.ViewParent;
+import android.view.WindowManager;
import java.lang.reflect.Field;
@@ -149,4 +152,14 @@
}
}
}
+
+ static Display getDisplay(View view) {
+ if (isAttachedToWindow(view)) {
+ final WindowManager wm = (WindowManager) view.getContext().getSystemService(
+ Context.WINDOW_SERVICE);
+ return wm.getDefaultDisplay();
+ }
+ return null;
+ }
+
}
diff --git a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorHoneycombMR2.java b/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorHoneycombMR2.java
new file mode 100644
index 0000000..61a5924
--- /dev/null
+++ b/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatCreatorHoneycombMR2.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.os;
+
+import android.os.Parcel;
+
+class ParcelableCompatCreatorHoneycombMR2<T> extends ParcelableCompatCreatorBase<T> {
+
+ public ParcelableCompatCreatorHoneycombMR2(ParcelableCompatCreatorCallbacks<T> callbacks) {
+ super(callbacks);
+ }
+
+ public T createFromParcel(Parcel in, ClassLoader loader) {
+ return mCallbacks.createFromParcel(in, loader);
+ }
+}
diff --git a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java b/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java
deleted file mode 100644
index 08acb55..0000000
--- a/compat/honeycomb_mr2/android/support/v4/os/ParcelableCompatHoneycombMR2.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.os;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-class ParcelableCompatCreatorHoneycombMR2Stub {
- static <T> Parcelable.Creator<T> instantiate(ParcelableCompatCreatorCallbacks<T> callbacks) {
- return new ParcelableCompatCreatorHoneycombMR2<T>(callbacks);
- }
-}
-
-class ParcelableCompatCreatorHoneycombMR2<T> implements Parcelable.ClassLoaderCreator<T> {
- private final ParcelableCompatCreatorCallbacks<T> mCallbacks;
-
- public ParcelableCompatCreatorHoneycombMR2(ParcelableCompatCreatorCallbacks<T> callbacks) {
- mCallbacks = callbacks;
- }
-
- public T createFromParcel(Parcel in) {
- return mCallbacks.createFromParcel(in, null);
- }
-
- public T createFromParcel(Parcel in, ClassLoader loader) {
- return mCallbacks.createFromParcel(in, loader);
- }
-
- public T[] newArray(int size) {
- return mCallbacks.newArray(size);
- }
-}
diff --git a/compat/java/android/support/v4/app/ActivityCompat.java b/compat/java/android/support/v4/app/ActivityCompat.java
index 478a153..b97d101 100644
--- a/compat/java/android/support/v4/app/ActivityCompat.java
+++ b/compat/java/android/support/v4/app/ActivityCompat.java
@@ -72,11 +72,12 @@
}
/**
- * @deprecated Do not use this constructor. It will be removed and replaced
- * with a protected constructor in a future release.
+ * This class should not be instantiated, but the constructor must be
+ * visible for the class to be extended (ex. in support-v13).
*/
- @Deprecated
- public ActivityCompat() {}
+ protected ActivityCompat() {
+ // Not publicly instantiable, but may be extended.
+ }
/**
* Invalidate the activity's options menu, if able.
@@ -236,24 +237,32 @@
*/
public static void finishAfterTransition(Activity activity) {
if (Build.VERSION.SDK_INT >= 21) {
- ActivityCompat21.finishAfterTransition(activity);
+ ActivityCompatApi21.finishAfterTransition(activity);
} else {
activity.finish();
}
}
/**
- * Backwards compatible implementation of {@link android.app.Activity#getReferrer()
- * Activity.getReferrer}. Uses the platform's implementation if available, otherwise
- * only falls back to digging any explicitly specified referrer from the activity's intent.
+ * Return information about who launched this activity. If the launching Intent
+ * contains an {@link Intent#EXTRA_REFERRER Intent.EXTRA_REFERRER},
+ * that will be returned as-is; otherwise, if known, an
+ * {@link Intent#URI_ANDROID_APP_SCHEME android-app:} referrer URI containing the
+ * package name that started the Intent will be returned. This may return null if no
+ * referrer can be identified -- it is neither explicitly specified, nor is it known which
+ * application package was involved.
*
- * @deprecated Do not call this method. It will be removed and replaced
- * with a static method in a future release.
+ * <p>If called while inside the handling of {@link Activity#onNewIntent}, this function will
+ * return the referrer that submitted that new intent to the activity. Otherwise, it
+ * always returns the referrer of the original Intent.</p>
+ *
+ * <p>Note that this is <em>not</em> a security feature -- you can not trust the
+ * referrer information, applications can spoof it.</p>
*/
- @Deprecated
- public Uri getReferrer(Activity activity) {
+ @Nullable
+ public static Uri getReferrer(Activity activity) {
if (Build.VERSION.SDK_INT >= 22) {
- return ActivityCompat22.getReferrer(activity);
+ return ActivityCompatApi22.getReferrer(activity);
}
Intent intent = activity.getIntent();
Uri referrer = intent.getParcelableExtra("android.intent.extra.REFERRER");
@@ -280,7 +289,7 @@
if (Build.VERSION.SDK_INT >= 23) {
ActivityCompatApi23.setEnterSharedElementCallback(activity, createCallback23(callback));
} else if (Build.VERSION.SDK_INT >= 21) {
- ActivityCompat21.setEnterSharedElementCallback(activity, createCallback(callback));
+ ActivityCompatApi21.setEnterSharedElementCallback(activity, createCallback(callback));
}
}
@@ -298,19 +307,19 @@
if (Build.VERSION.SDK_INT >= 23) {
ActivityCompatApi23.setExitSharedElementCallback(activity, createCallback23(callback));
} else if (Build.VERSION.SDK_INT >= 21) {
- ActivityCompat21.setExitSharedElementCallback(activity, createCallback(callback));
+ ActivityCompatApi21.setExitSharedElementCallback(activity, createCallback(callback));
}
}
public static void postponeEnterTransition(Activity activity) {
if (Build.VERSION.SDK_INT >= 21) {
- ActivityCompat21.postponeEnterTransition(activity);
+ ActivityCompatApi21.postponeEnterTransition(activity);
}
}
public static void startPostponedEnterTransition(Activity activity) {
if (Build.VERSION.SDK_INT >= 21) {
- ActivityCompat21.startPostponedEnterTransition(activity);
+ ActivityCompatApi21.startPostponedEnterTransition(activity);
}
}
@@ -424,9 +433,9 @@
return false;
}
- private static ActivityCompat21.SharedElementCallback21 createCallback(
+ private static ActivityCompatApi21.SharedElementCallback21 createCallback(
SharedElementCallback callback) {
- ActivityCompat21.SharedElementCallback21 newCallback = null;
+ ActivityCompatApi21.SharedElementCallback21 newCallback = null;
if (callback != null) {
newCallback = new ActivityCompat.SharedElementCallback21Impl(callback);
}
@@ -443,7 +452,7 @@
}
private static class SharedElementCallback21Impl
- extends ActivityCompat21.SharedElementCallback21 {
+ extends ActivityCompatApi21.SharedElementCallback21 {
private SharedElementCallback mCallback;
diff --git a/compat/java/android/support/v4/app/NotificationCompat.java b/compat/java/android/support/v4/app/NotificationCompat.java
index 62c1a7b..cb02f41 100644
--- a/compat/java/android/support/v4/app/NotificationCompat.java
+++ b/compat/java/android/support/v4/app/NotificationCompat.java
@@ -512,7 +512,11 @@
*/
protected static class BuilderExtender {
public Notification build(Builder b, NotificationBuilderWithBuilderAccessor builder) {
- return builder.build();
+ Notification n = builder.build();
+ if (b.mContentView != null) {
+ n.contentView = b.mContentView;
+ }
+ return n;
}
}
@@ -521,7 +525,7 @@
public Notification build(Builder b, BuilderExtender extender) {
Notification result = b.mNotification;
result = NotificationCompatBase.add(result, b.mContext,
- b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent);
+ b.resolveTitle(), b.resolveText(), b.mContentIntent, b.mFullScreenIntent);
// translate high priority requests into legacy flag
if (b.mPriority > PRIORITY_DEFAULT) {
result.flags |= FLAG_HIGH_PRIORITY;
@@ -600,7 +604,7 @@
@Override
public Notification build(Builder b, BuilderExtender extender) {
Notification notification = NotificationCompatHoneycomb.add(b.mContext, b.mNotification,
- b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView,
+ b.resolveTitle(), b.resolveText(), b.mContentInfo, b.mTickerView,
b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon);
if (b.mContentView != null) {
notification.contentView = b.mContentView;
@@ -613,15 +617,11 @@
@Override
public Notification build(Builder b, BuilderExtender extender) {
NotificationCompatIceCreamSandwich.Builder builder =
- new NotificationCompatIceCreamSandwich.Builder(
- b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
- b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
+ new NotificationCompatIceCreamSandwich.Builder(b.mContext, b.mNotification,
+ b.resolveTitle(), b.resolveText(), b.mContentInfo, b.mTickerView,
+ b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
b.mProgressMax, b.mProgress, b.mProgressIndeterminate);
- Notification notification = extender.build(b, builder);
- if (b.mContentView != null) {
- notification.contentView = b.mContentView;
- }
- return notification;
+ return extender.build(b, builder);
}
}
@@ -629,7 +629,7 @@
@Override
public Notification build(Builder b, BuilderExtender extender) {
NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder(
- b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+ b.mContext, b.mNotification, b.resolveTitle(), b.resolveText(), b.mContentInfo,
b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mExtras,
@@ -638,7 +638,10 @@
addStyleToBuilderJellybean(builder, b.mStyle);
Notification notification = extender.build(b, builder);
if (b.mStyle != null) {
- b.mStyle.addCompatExtras(getExtras(notification));
+ Bundle extras = getExtras(notification);
+ if (extras != null) {
+ b.mStyle.addCompatExtras(extras);
+ }
}
return notification;
}
@@ -697,7 +700,7 @@
@Override
public Notification build(Builder b, BuilderExtender extender) {
NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder(
- b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+ b.mContext, b.mNotification, b.resolveTitle(), b.resolveText(), b.mContentInfo,
b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly,
@@ -749,7 +752,7 @@
@Override
public Notification build(Builder b, BuilderExtender extender) {
NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder(
- b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+ b.mContext, b.mNotification, b.resolveTitle(), b.resolveText(), b.mContentInfo,
b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras,
@@ -807,7 +810,7 @@
@Override
public Notification build(Builder b, BuilderExtender extender) {
NotificationCompatApi21.Builder builder = new NotificationCompatApi21.Builder(
- b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
+ b.mContext, b.mNotification, b.resolveTitle(), b.resolveText(), b.mContentInfo,
b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
@@ -897,8 +900,6 @@
bigPictureStyle.mPicture,
bigPictureStyle.mBigLargeIcon,
bigPictureStyle.mBigLargeIconSet);
- } else if (style instanceof MessagingStyle) {
- // TODO implement BigText fallback
}
}
}
@@ -1740,6 +1741,73 @@
}
return cs;
}
+
+ /**
+ * @hide
+ */
+ public RemoteViews getContentView() {
+ return mContentView;
+ }
+
+ /**
+ * @hide
+ */
+ public RemoteViews getBigContentView() {
+ return mBigContentView;
+ }
+
+ /**
+ * @hide
+ */
+ public RemoteViews getHeadsUpContentView() {
+ return mHeadsUpContentView;
+ }
+
+ /**
+ * return when if it is showing or 0 otherwise
+ *
+ * @hide
+ */
+ public long getWhenIfShowing() {
+ return mShowWhen ? mNotification.when : 0;
+ }
+
+ /**
+ * @return the priority set on the notification
+ *
+ * @hide
+ */
+ public int getPriority() {
+ return mPriority;
+ }
+
+ /**
+ * @return the color of the notification
+ *
+ * @hide
+ */
+ public int getColor() {
+ return mColor;
+ }
+
+
+ /**
+ * @return the text of the notification
+ *
+ * @hide
+ */
+ protected CharSequence resolveText() {
+ return mContentText;
+ }
+
+ /**
+ * @return the title of the notification
+ *
+ * @hide
+ */
+ protected CharSequence resolveTitle() {
+ return mContentTitle;
+ }
}
/**
@@ -1919,8 +1987,9 @@
* messages of varying types between any number of people.
*
* <br>
- * If the platform does not provide large-format notifications, this method has no effect. The
- * user will always see the normal notification view.
+ * In order to get a backwards compatible behavior, the app needs to use the v7 version of the
+ * notification builder together with this style, otherwise the user will see the normal
+ * notification view.
* <br>
* This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like
* so:
diff --git a/compat/java/android/support/v4/content/ContextCompat.java b/compat/java/android/support/v4/content/ContextCompat.java
index 6ffcd54..05486c2 100644
--- a/compat/java/android/support/v4/content/ContextCompat.java
+++ b/compat/java/android/support/v4/content/ContextCompat.java
@@ -51,11 +51,12 @@
private static TypedValue sTempValue;
/**
- * @deprecated Do not use this constructor. It will be removed and replaced
- * with a protected constructor in a future release.
+ * This class should not be instantiated, but the constructor must be
+ * visible for the class to be extended (ex. in ActivityCompat).
*/
- @Deprecated
- public ContextCompat() {}
+ protected ContextCompat() {
+ // Not publicly instantiable, but may be extended.
+ }
/**
* Start a set of activities as a synthesized task stack, if able.
@@ -528,17 +529,6 @@
}
/**
- * @removed
- * @deprecated This method will be removed in a future release. Use
- * {@link #createDeviceProtectedStorageContext(Context)}
- * instead.
- */
- @Deprecated
- public static Context createDeviceEncryptedStorageContext(Context context) {
- return createDeviceProtectedStorageContext(context);
- }
-
- /**
* Indicates if the storage APIs of this Context are backed by
* device-encrypted storage.
*
@@ -551,14 +541,4 @@
return false;
}
}
-
- /**
- * @removed
- * @deprecated This method will be removed in a future release. Use
- * {@link #isDeviceProtectedStorage(Context)} instead.
- */
- @Deprecated
- public static boolean isDeviceEncryptedStorage(Context context) {
- return isDeviceProtectedStorage(context);
- }
}
diff --git a/compat/java/android/support/v4/content/IntentCompat.java b/compat/java/android/support/v4/content/IntentCompat.java
index eaf7b1f..179824e 100644
--- a/compat/java/android/support/v4/content/IntentCompat.java
+++ b/compat/java/android/support/v4/content/IntentCompat.java
@@ -247,8 +247,6 @@
* selector.
* @return Returns a newly created Intent that can be used to launch the
* activity as a main application entry.
- *
- * @see #setSelector(Intent)
*/
public static Intent makeMainSelectorActivity(String selectorAction,
String selectorCategory) {
diff --git a/compat/java/android/support/v4/net/ConnectivityManagerCompat.java b/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
index 9137d4a..90479c1 100644
--- a/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
+++ b/compat/java/android/support/v4/net/ConnectivityManagerCompat.java
@@ -20,6 +20,10 @@
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
@@ -37,8 +41,44 @@
interface ConnectivityManagerCompatImpl {
boolean isActiveNetworkMetered(ConnectivityManager cm);
+
+ @RestrictBackgroundStatus
+ int getRestrictBackgroundStatus(ConnectivityManager cm);
}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false, value = {
+ RESTRICT_BACKGROUND_STATUS_DISABLED,
+ RESTRICT_BACKGROUND_STATUS_WHITELISTED,
+ RESTRICT_BACKGROUND_STATUS_ENABLED,
+ })
+ public @interface RestrictBackgroundStatus {
+ }
+
+ /**
+ * Device is not restricting metered network activity while application is running on
+ * background.
+ */
+ public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1;
+
+ /**
+ * Device is restricting metered network activity while application is running on background,
+ * but application is allowed to bypass it.
+ * <p>
+ * In this state, application should take action to mitigate metered network access.
+ * For example, a music streaming application should switch to a low-bandwidth bitrate.
+ */
+ public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2;
+
+ /**
+ * Device is restricting metered network activity while application is running on background.
+ * <p>
+ * In this state, application should not try to use the network while running on background,
+ * because it would be denied.
+ */
+ public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3;
+
static class BaseConnectivityManagerCompatImpl implements ConnectivityManagerCompatImpl {
@Override
public boolean isActiveNetworkMetered(ConnectivityManager cm) {
@@ -64,27 +104,44 @@
return true;
}
}
+
+ @Override
+ public int getRestrictBackgroundStatus(ConnectivityManager cm) {
+ return RESTRICT_BACKGROUND_STATUS_ENABLED;
+ }
}
static class HoneycombMR2ConnectivityManagerCompatImpl
- implements ConnectivityManagerCompatImpl {
+ extends BaseConnectivityManagerCompatImpl {
@Override
public boolean isActiveNetworkMetered(ConnectivityManager cm) {
return ConnectivityManagerCompatHoneycombMR2.isActiveNetworkMetered(cm);
}
}
- static class JellyBeanConnectivityManagerCompatImpl implements ConnectivityManagerCompatImpl {
+ static class JellyBeanConnectivityManagerCompatImpl
+ extends HoneycombMR2ConnectivityManagerCompatImpl {
@Override
public boolean isActiveNetworkMetered(ConnectivityManager cm) {
return ConnectivityManagerCompatJellyBean.isActiveNetworkMetered(cm);
}
}
+ static class Api24ConnectivityManagerCompatImpl
+ extends JellyBeanConnectivityManagerCompatImpl {
+ @Override
+ public int getRestrictBackgroundStatus(ConnectivityManager cm) {
+ //noinspection ResourceType
+ return ConnectivityManagerCompatApi24.getRestrictBackgroundStatus(cm);
+ }
+ }
+
private static final ConnectivityManagerCompatImpl IMPL;
static {
- if (Build.VERSION.SDK_INT >= 16) {
+ if (Build.VERSION.SDK_INT >= 24) {
+ IMPL = new Api24ConnectivityManagerCompatImpl();
+ } else if (Build.VERSION.SDK_INT >= 16) {
IMPL = new JellyBeanConnectivityManagerCompatImpl();
} else if (Build.VERSION.SDK_INT >= 13) {
IMPL = new HoneycombMR2ConnectivityManagerCompatImpl();
@@ -96,9 +153,15 @@
/**
* Returns if the currently active data network is metered. A network is
* classified as metered when the user is sensitive to heavy data usage on
- * that connection. You should check this before doing large data transfers,
- * and warn the user or delay the operation until another network is
- * available.
+ * that connection due to monetary costs, data limitations or
+ * battery/performance issues. You should check this before doing large
+ * data transfers, and warn the user or delay the operation until another
+ * network is available.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @return {@code true} if large transfers should be avoided, otherwise
+ * {@code false}.
*/
public static boolean isActiveNetworkMetered(ConnectivityManager cm) {
return IMPL.isActiveNetworkMetered(cm);
@@ -120,5 +183,18 @@
}
}
+ /**
+ * Determines if the calling application is subject to metered network restrictions while
+ * running on background.
+ *
+ * @return {@link #RESTRICT_BACKGROUND_STATUS_DISABLED},
+ * {@link #RESTRICT_BACKGROUND_STATUS_ENABLED},
+ * or {@link #RESTRICT_BACKGROUND_STATUS_WHITELISTED}
+ */
+ @RestrictBackgroundStatus
+ public static int getRestrictBackgroundStatus(ConnectivityManager cm) {
+ return IMPL.getRestrictBackgroundStatus(cm);
+ }
+
private ConnectivityManagerCompat() {}
}
diff --git a/compat/java/android/support/v4/os/ParcelableCompat.java b/compat/java/android/support/v4/os/ParcelableCompat.java
index 10c03b5..6c8820c 100644
--- a/compat/java/android/support/v4/os/ParcelableCompat.java
+++ b/compat/java/android/support/v4/os/ParcelableCompat.java
@@ -16,7 +16,6 @@
package android.support.v4.os;
-import android.os.Parcel;
import android.os.Parcelable;
/**
@@ -24,7 +23,6 @@
* introduced after API level 4 in a backwards compatible fashion.
*/
public final class ParcelableCompat {
-
/**
* Factory method for {@link Parcelable.Creator}.
*
@@ -34,27 +32,9 @@
public static <T> Parcelable.Creator<T> newCreator(
ParcelableCompatCreatorCallbacks<T> callbacks) {
if (android.os.Build.VERSION.SDK_INT >= 13) {
- return ParcelableCompatCreatorHoneycombMR2Stub.instantiate(callbacks);
+ return new ParcelableCompatCreatorHoneycombMR2<T>(callbacks);
}
- return new CompatCreator<T>(callbacks);
- }
-
- static class CompatCreator<T> implements Parcelable.Creator<T> {
- final ParcelableCompatCreatorCallbacks<T> mCallbacks;
-
- public CompatCreator(ParcelableCompatCreatorCallbacks<T> callbacks) {
- mCallbacks = callbacks;
- }
-
- @Override
- public T createFromParcel(Parcel source) {
- return mCallbacks.createFromParcel(source, null);
- }
-
- @Override
- public T[] newArray(int size) {
- return mCallbacks.newArray(size);
- }
+ return new ParcelableCompatCreatorBase<T>(callbacks);
}
private ParcelableCompat() {}
diff --git a/compat/java/android/support/v4/util/Pair.java b/compat/java/android/support/v4/util/Pair.java
index 7f9e61e..46ea5cd 100644
--- a/compat/java/android/support/v4/util/Pair.java
+++ b/compat/java/android/support/v4/util/Pair.java
@@ -67,6 +67,11 @@
return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
}
+ @Override
+ public String toString() {
+ return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
+ }
+
/**
* Convenience method for creating an appropriately typed pair.
* @param a the first object in the Pair
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
index 4e14ec0..d9d3cfb 100644
--- a/compat/java/android/support/v4/view/ViewCompat.java
+++ b/compat/java/android/support/v4/view/ViewCompat.java
@@ -21,6 +21,7 @@
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.FloatRange;
import android.support.annotation.IdRes;
@@ -31,6 +32,7 @@
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
import android.util.Log;
+import android.view.Display;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -455,6 +457,7 @@
void setSaveFromParentEnabled(View view, boolean enabled);
void setActivated(View view, boolean activated);
boolean isPaddingRelative(View view);
+ void setBackground(View view, Drawable background);
ColorStateList getBackgroundTintList(View view);
void setBackgroundTintList(View view, ColorStateList tintList);
PorterDuff.Mode getBackgroundTintMode(View view);
@@ -484,6 +487,7 @@
void offsetTopAndBottom(View view, int offset);
void offsetLeftAndRight(View view, int offset);
void setPointerIcon(View view, PointerIconCompat pointerIcon);
+ Display getDisplay(View view);
}
static class BaseViewCompatImpl implements ViewCompatImpl {
@@ -974,6 +978,11 @@
}
@Override
+ public void setBackground(View view, Drawable background) {
+ view.setBackgroundDrawable(background);
+ }
+
+ @Override
public ColorStateList getBackgroundTintList(View view) {
return ViewCompatBase.getBackgroundTintList(view);
}
@@ -1147,6 +1156,11 @@
public void setPointerIcon(View view, PointerIconCompat pointerIcon) {
// no-op
}
+
+ @Override
+ public Display getDisplay(View view) {
+ return ViewCompatBase.getDisplay(view);
+ }
}
static class HCViewCompatImpl extends BaseViewCompatImpl {
@@ -1486,6 +1500,11 @@
public boolean hasOverlappingRendering(View view) {
return ViewCompatJB.hasOverlappingRendering(view);
}
+
+ @Override
+ public void setBackground(View view, Drawable background) {
+ ViewCompatJB.setBackground(view, background);
+ }
}
static class JbMr1ViewCompatImpl extends JBViewCompatImpl {
@@ -1539,6 +1558,11 @@
public boolean isPaddingRelative(View view) {
return ViewCompatJellybeanMr1.isPaddingRelative(view);
}
+
+ @Override
+ public Display getDisplay(View view) {
+ return ViewCompatJellybeanMr1.getDisplay(view);
+ }
}
static class JbMr2ViewCompatImpl extends JbMr1ViewCompatImpl {
@@ -3082,6 +3106,16 @@
}
/**
+ * Set the background of the {@code view} to a given Drawable, or remove the background. If the
+ * background has padding, {@code view}'s padding is set to the background's padding. However,
+ * when a background is removed, this View's padding isn't touched. If setting the padding is
+ * desired, please use{@code setPadding(int, int, int, int)}.
+ */
+ public static void setBackground(View view, Drawable background) {
+ IMPL.setBackground(view, background);
+ }
+
+ /**
* Return the tint applied to the background drawable, if specified.
* <p>
* Only returns meaningful info when running on API v21 or newer, or if {@code view}
@@ -3342,7 +3376,7 @@
* <p>
* Compatibility:
* <ul>
- * <li>API < 18: Always returns {@code false}</li>
+ * <li>API < 18: Always returns {@code false}</li>
* </ul>
*
* @return whether the view hierarchy is currently undergoing a layout pass
@@ -3364,7 +3398,7 @@
* <p>
* Compatibility:
* <ul>
- * <li>API < 19: Always returns {@code false}</li>
+ * <li>API < 19: Always returns {@code false}</li>
* </ul>
*
* @return true if layout direction has been resolved.
@@ -3391,7 +3425,7 @@
* <p>
* Compatibility:
* <ul>
- * <li>API < 21: No-op
+ * <li>API < 21: No-op
* </ul>
*
* @param z The visual z position of this view, in pixels.
@@ -3532,5 +3566,19 @@
IMPL.setPointerIcon(view, pointerIcon);
}
+ /**
+ * Gets the logical display to which the view's window has been attached.
+ * <p>
+ * Compatibility:
+ * <ul>
+ * <li>API < 17: Returns the default display when the view is attached. Otherwise, null.
+ * </ul>
+ *
+ * @return The logical display, or null if the view is not currently attached to a window.
+ */
+ public static Display getDisplay(@NonNull View view) {
+ return IMPL.getDisplay(view);
+ }
+
protected ViewCompat() {}
}
diff --git a/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java b/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java
index 4865a8b..c39ef2a 100644
--- a/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java
+++ b/compat/jellybean-mr1/android/support/v4/view/ViewCompatJellybeanMr1.java
@@ -17,6 +17,7 @@
package android.support.v4.view;
import android.graphics.Paint;
+import android.view.Display;
import android.view.View;
/**
@@ -63,4 +64,8 @@
public static boolean isPaddingRelative(View view) {
return view.isPaddingRelative();
}
+
+ public static Display getDisplay(View view) {
+ return view.getDisplay();
+ }
}
diff --git a/compat/jellybean/android/support/v4/view/ViewCompatJB.java b/compat/jellybean/android/support/v4/view/ViewCompatJB.java
index f1c7315..3d64da1 100644
--- a/compat/jellybean/android/support/v4/view/ViewCompatJB.java
+++ b/compat/jellybean/android/support/v4/view/ViewCompatJB.java
@@ -16,6 +16,7 @@
package android.support.v4.view;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewParent;
@@ -89,4 +90,8 @@
public static boolean hasOverlappingRendering(View view) {
return view.hasOverlappingRendering();
}
+
+ public static void setBackground(View view, Drawable drawable) {
+ view.setBackground(drawable);
+ }
}
diff --git a/compat/tests/AndroidManifest.xml b/compat/tests/AndroidManifest.xml
index a46860a..8228476 100644
--- a/compat/tests/AndroidManifest.xml
+++ b/compat/tests/AndroidManifest.xml
@@ -37,6 +37,8 @@
<activity
android:name="android.support.v4.ThemedYellowActivity"
android:theme="@style/YellowTheme" />
+
+ <activity android:name="android.support.v4.view.ViewCompatActivity"/>
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java b/compat/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
similarity index 98%
rename from tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
rename to compat/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
index ea67375..8c1abcc 100644
--- a/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
+++ b/compat/tests/java/android/support/v4/app/NotificationCompatActionWearableExtenderTest.java
@@ -20,15 +20,16 @@
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
-import android.support.tests.R;
+import android.support.compat.test.R;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
-import java.util.Arrays;
import java.util.List;
/**
* Tests for {@link android.support.v4.app.NotificationCompat.Action.WearableExtender}.
*/
+@MediumTest
public class NotificationCompatActionWearableExtenderTest extends AndroidTestCase {
private int mIcon;
diff --git a/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java b/compat/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
similarity index 98%
rename from tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
rename to compat/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
index 2a988ed..4e945dd 100644
--- a/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
+++ b/compat/tests/java/android/support/v4/app/NotificationCompatWearableExtenderTest.java
@@ -20,8 +20,9 @@
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
-import android.support.tests.R;
+import android.support.compat.test.R;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.Gravity;
import java.util.Arrays;
@@ -30,6 +31,7 @@
/**
* Tests for {@link android.support.v4.app.NotificationCompat.WearableExtender}.
*/
+@MediumTest
public class NotificationCompatWearableExtenderTest extends AndroidTestCase {
public static final int CUSTOM_CONTENT_HEIGHT_DP = 256;
diff --git a/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java b/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
index 2905df0..fc144c5 100644
--- a/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
+++ b/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
@@ -16,8 +16,11 @@
package android.support.v4.content;
+import static org.junit.Assert.fail;
+
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -25,8 +28,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import static org.junit.Assert.*;
-
@RunWith(AndroidJUnit4.class)
public class ModernAsyncTaskTest {
@@ -37,6 +38,7 @@
*
* @throws Throwable
*/
+ @LargeTest
@Test
public void testCancellationWithException() throws Throwable {
final CountDownLatch readyToCancel = new CountDownLatch(1);
diff --git a/tests/java/android/support/v4/text/IcuCompatTest.java b/compat/tests/java/android/support/v4/text/IcuCompatTest.java
similarity index 72%
rename from tests/java/android/support/v4/text/IcuCompatTest.java
rename to compat/tests/java/android/support/v4/text/IcuCompatTest.java
index 6f7f459..20aaa9b 100644
--- a/tests/java/android/support/v4/text/IcuCompatTest.java
+++ b/compat/tests/java/android/support/v4/text/IcuCompatTest.java
@@ -16,13 +16,22 @@
package android.support.v4.text;
+import android.os.Build;
+import android.test.suitebuilder.annotation.SmallTest;
+
import junit.framework.TestCase;
import java.util.Locale;
+@SmallTest
public class IcuCompatTest extends TestCase {
public void testMaximizeAndGetScript() {
assertEquals("Latn", ICUCompat.maximizeAndGetScript(new Locale("en", "US")));
- assertEquals("Visp", ICUCompat.maximizeAndGetScript(Locale.forLanguageTag("en-Visp-US")));
+
+ // Script tags were added to java.util.Locale only on API 21.
+ if (Build.VERSION.SDK_INT >= 21) {
+ assertEquals(
+ "Visp", ICUCompat.maximizeAndGetScript(Locale.forLanguageTag("en-Visp-US")));
+ }
}
}
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 f867188..45779c7 100644
--- a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
+++ b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -214,16 +215,9 @@
if (Locale.US.equals(Locale.getDefault())) {
assertTrue(LinkifyCompat.addLinks(spannable, Linkify.PHONE_NUMBERS));
URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
- assertEquals(9, spans.length);
- assertEquals("tel:8121234562", spans[0].getURL());
- assertEquals("tel:8121234563", spans[1].getURL());
- assertEquals("tel:8005551210", spans[2].getURL());
- assertEquals("tel:8005551211", spans[3].getURL());
- assertEquals("tel:5551212", spans[4].getURL());
- assertEquals("tel:+4408121234564", spans[5].getURL());
- assertEquals("tel:+4408121234565", spans[6].getURL());
- assertEquals("tel:+18005551213", spans[7].getURL());
- assertEquals("tel:+18005551214", spans[8].getURL());
+ // We cannot assert the contents of the spans as support library falls back to the
+ // framework libphonenumber which behaves differently for different API levels.
+ assertNotEquals("There should be more than zero phone number spans.", 0, spans.length);
}
try {
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/compat/tests/java/android/support/v4/view/ViewCompatActivity.java
similarity index 62%
copy from compat/api22/android/support/v4/app/ActivityCompat22.java
copy to compat/tests/java/android/support/v4/view/ViewCompatActivity.java
index 3946f1d..28ff642 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/compat/tests/java/android/support/v4/view/ViewCompatActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,13 +14,16 @@
* limitations under the License.
*/
-package android.support.v4.app;
+package android.support.v4.view;
-import android.app.Activity;
-import android.net.Uri;
+import android.support.compat.test.R;
+import android.support.v4.BaseTestActivity;
-class ActivityCompat22 {
- public static Uri getReferrer(Activity activity) {
- return activity.getReferrer();
+public class ViewCompatActivity extends BaseTestActivity {
+
+ @Override
+ protected int getContentViewLayoutResId() {
+ return R.layout.view_compat_activity;
}
+
}
diff --git a/compat/tests/java/android/support/v4/view/ViewCompatTest.java b/compat/tests/java/android/support/v4/view/ViewCompatTest.java
index c4217a5..0b102a6 100644
--- a/compat/tests/java/android/support/v4/view/ViewCompatTest.java
+++ b/compat/tests/java/android/support/v4/view/ViewCompatTest.java
@@ -15,18 +15,39 @@
*/
package android.support.v4.view;
+import android.app.Activity;
import android.support.test.runner.AndroidJUnit4;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.Display;
import android.view.View;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.support.compat.test.R;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ViewCompatTest {
+@MediumTest
+public class ViewCompatTest extends BaseInstrumentationTestCase<ViewCompatActivity> {
+
+ private View mView;
+
+ public ViewCompatTest() {
+ super(ViewCompatActivity.class);
+ }
+
+ @Before
+ public void setUp() {
+ final Activity activity = mActivityTestRule.getActivity();
+ mView = activity.findViewById(R.id.view);
+ }
+
@Test
public void testConstants() {
// Compat constants must match core constants since they can be used interchangeably
@@ -34,4 +55,18 @@
assertEquals("LTR constants", View.LAYOUT_DIRECTION_LTR, ViewCompat.LAYOUT_DIRECTION_LTR);
assertEquals("RTL constants", View.LAYOUT_DIRECTION_RTL, ViewCompat.LAYOUT_DIRECTION_RTL);
}
+
+ @Test
+ public void testGetDisplay() {
+ final Display display = ViewCompat.getDisplay(mView);
+ assertNotNull(display);
+ }
+
+ @Test
+ public void testGetDisplay_returnsNullForUnattachedView() {
+ final View view = new View(mActivityTestRule.getActivity());
+ final Display display = ViewCompat.getDisplay(view);
+ assertNull(display);
+ }
+
}
diff --git a/tests/res/drawable/action_icon.xml b/compat/tests/res/drawable/action_icon.xml
similarity index 100%
rename from tests/res/drawable/action_icon.xml
rename to compat/tests/res/drawable/action_icon.xml
diff --git a/tests/res/drawable/action_icon2.xml b/compat/tests/res/drawable/action_icon2.xml
similarity index 100%
rename from tests/res/drawable/action_icon2.xml
rename to compat/tests/res/drawable/action_icon2.xml
diff --git a/tests/res/drawable/content_icon.xml b/compat/tests/res/drawable/content_icon.xml
similarity index 100%
rename from tests/res/drawable/content_icon.xml
rename to compat/tests/res/drawable/content_icon.xml
diff --git a/tests/res/drawable/content_icon2.xml b/compat/tests/res/drawable/content_icon2.xml
similarity index 100%
rename from tests/res/drawable/content_icon2.xml
rename to compat/tests/res/drawable/content_icon2.xml
diff --git a/compat/tests/res/layout/view_compat_activity.xml b/compat/tests/res/layout/view_compat_activity.xml
new file mode 100644
index 0000000..2a8acac
--- /dev/null
+++ b/compat/tests/res/layout/view_compat_activity.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<FrameLayout
+ android:id="@+id/container"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <View
+ android:id="@+id/view"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:background="#f00"/>
+
+</FrameLayout>
diff --git a/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java b/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
index 452b033..197f96e 100644
--- a/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
+++ b/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
@@ -110,6 +110,9 @@
}
private static class ActionBarDrawerToggleImplBase implements ActionBarDrawerToggleImpl {
+ ActionBarDrawerToggleImplBase() {
+ }
+
@Override
public Drawable getThemeUpIndicator(Activity activity) {
return null;
@@ -130,6 +133,9 @@
}
private static class ActionBarDrawerToggleImplHC implements ActionBarDrawerToggleImpl {
+ ActionBarDrawerToggleImplHC() {
+ }
+
@Override
public Drawable getThemeUpIndicator(Activity activity) {
return ActionBarDrawerToggleHoneycomb.getThemeUpIndicator(activity);
@@ -151,6 +157,9 @@
private static class ActionBarDrawerToggleImplJellybeanMR2
implements ActionBarDrawerToggleImpl {
+ ActionBarDrawerToggleImplJellybeanMR2() {
+ }
+
@Override
public Drawable getThemeUpIndicator(Activity activity) {
return ActionBarDrawerToggleJellybeanMR2.getThemeUpIndicator(activity);
@@ -189,7 +198,7 @@
// android.R.id.home as defined by public API in v11
private static final int ID_HOME = 0x0102002c;
- private final Activity mActivity;
+ final Activity mActivity;
private final Delegate mActivityImpl;
private final DrawerLayout mDrawerLayout;
private boolean mDrawerIndicatorEnabled = true;
@@ -505,7 +514,7 @@
private float mPosition;
private float mOffset;
- private SlideDrawable(Drawable wrapped) {
+ SlideDrawable(Drawable wrapped) {
super(wrapped, 0);
}
diff --git a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java b/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
index 21aaae5..e638d05 100644
--- a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
+++ b/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
@@ -67,9 +67,9 @@
public final class AsyncLayoutInflater {
private static final String TAG = "AsyncLayoutInflater";
- private LayoutInflater mInflater;
- private Handler mHandler;
- private InflateThread mInflateThread;
+ LayoutInflater mInflater;
+ Handler mHandler;
+ InflateThread mInflateThread;
public AsyncLayoutInflater(@NonNull Context context) {
mInflater = new BasicInflater(context);
@@ -116,6 +116,9 @@
int resid;
View view;
OnInflateFinishedListener callback;
+
+ InflateRequest() {
+ }
}
private static class BasicInflater extends LayoutInflater {
diff --git a/core-ui/java/android/support/v4/view/PagerTabStrip.java b/core-ui/java/android/support/v4/view/PagerTabStrip.java
index c53595b..f4c0b21 100644
--- a/core-ui/java/android/support/v4/view/PagerTabStrip.java
+++ b/core-ui/java/android/support/v4/view/PagerTabStrip.java
@@ -24,6 +24,7 @@
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
+import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -140,7 +141,7 @@
* @param resId Resource ID of a color resource to load
*/
public void setTabIndicatorColorResource(@ColorRes int resId) {
- setTabIndicatorColor(getContext().getResources().getColor(resId));
+ setTabIndicatorColor(ContextCompat.getColor(getContext(), resId));
}
/**
diff --git a/core-ui/java/android/support/v4/view/PagerTitleStrip.java b/core-ui/java/android/support/v4/view/PagerTitleStrip.java
index 477e271..d569cd4 100644
--- a/core-ui/java/android/support/v4/view/PagerTitleStrip.java
+++ b/core-ui/java/android/support/v4/view/PagerTitleStrip.java
@@ -22,6 +22,7 @@
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.FloatRange;
+import android.support.v4.widget.TextViewCompat;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.TypedValue;
@@ -54,7 +55,7 @@
TextView mNextText;
private int mLastKnownCurrentPage = -1;
- private float mLastKnownPositionOffset = -1;
+ float mLastKnownPositionOffset = -1;
private int mScaledTextSpacing;
private int mGravity;
@@ -127,9 +128,9 @@
final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
final int textAppearance = a.getResourceId(0, 0);
if (textAppearance != 0) {
- mPrevText.setTextAppearance(context, textAppearance);
- mCurrText.setTextAppearance(context, textAppearance);
- mNextText.setTextAppearance(context, textAppearance);
+ TextViewCompat.setTextAppearance(mPrevText, textAppearance);
+ TextViewCompat.setTextAppearance(mCurrText, textAppearance);
+ TextViewCompat.setTextAppearance(mNextText, textAppearance);
}
final int textSize = a.getDimensionPixelSize(1, 0);
if (textSize != 0) {
@@ -480,6 +481,9 @@
ViewPager.OnAdapterChangeListener {
private int mScrollState;
+ PageListener() {
+ }
+
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffset > 0.5f) {
diff --git a/core-ui/java/android/support/v4/view/ViewPager.java b/core-ui/java/android/support/v4/view/ViewPager.java
index ba4a6a6..50b16fc 100644
--- a/core-ui/java/android/support/v4/view/ViewPager.java
+++ b/core-ui/java/android/support/v4/view/ViewPager.java
@@ -32,6 +32,7 @@
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -121,7 +122,7 @@
private static final int MIN_FLING_VELOCITY = 400; // dips
- private static final int[] LAYOUT_ATTRS = new int[] {
+ static final int[] LAYOUT_ATTRS = new int[] {
android.R.attr.layout_gravity
};
@@ -159,8 +160,8 @@
private final Rect mTempRect = new Rect();
- private PagerAdapter mAdapter;
- private int mCurItem; // Index of currently displayed page.
+ PagerAdapter mAdapter;
+ int mCurItem; // Index of currently displayed page.
private int mRestoredCurItem = -1;
private Parcelable mRestoredAdapterState = null;
private ClassLoader mRestoredClassLoader = null;
@@ -243,6 +244,7 @@
private OnPageChangeListener mInternalPageChangeListener;
private List<OnAdapterChangeListener> mAdapterChangeListeners;
private PageTransformer mPageTransformer;
+ private int mPageTransformerLayerType;
private Method mSetChildrenDrawingOrderEnabled;
private static final int DRAW_ORDER_DEFAULT = 0;
@@ -486,7 +488,7 @@
super.onDetachedFromWindow();
}
- private void setScrollState(int newState) {
+ void setScrollState(int newState) {
if (mScrollState == newState) {
return;
}
@@ -749,18 +751,47 @@
}
/**
- * Set a {@link PageTransformer} that will be called for each attached page whenever
+ * Sets a {@link PageTransformer} that will be called for each attached page whenever
* the scroll position is changed. This allows the application to apply custom property
- * transformations to each page, overriding the default sliding look and feel.
+ * transformations to each page, overriding the default sliding behavior.
*
* <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist.
- * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p>
+ * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.
+ * By default, calling this method will cause contained pages to use
+ * {@link ViewCompat#LAYER_TYPE_HARDWARE}. This layer type allows custom alpha transformations,
+ * but it will cause issues if any of your pages contain a {@link android.view.SurfaceView}
+ * and you have not called {@link android.view.SurfaceView#setZOrderOnTop(boolean)} to put that
+ * {@link android.view.SurfaceView} above your app content. To disable this behavior, call
+ * {@link #setPageTransformer(boolean,PageTransformer,int)} and pass
+ * {@link ViewCompat#LAYER_TYPE_NONE} for {@code pageLayerType}.</p>
*
* @param reverseDrawingOrder true if the supplied PageTransformer requires page views
* to be drawn from last to first instead of first to last.
* @param transformer PageTransformer that will modify each page's animation properties
*/
public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
+ setPageTransformer(reverseDrawingOrder, transformer, ViewCompat.LAYER_TYPE_HARDWARE);
+ }
+
+ /**
+ * Sets a {@link PageTransformer} that will be called for each attached page whenever
+ * the scroll position is changed. This allows the application to apply custom property
+ * transformations to each page, overriding the default sliding behavior.
+ *
+ * <p><em>Note:</em> Prior to Android 3.0 ({@link Build.VERSION_CODES#HONEYCOMB API 11}),
+ * the property animation APIs did not exist. As a result, setting a PageTransformer prior
+ * to API 11 will have no effect.</p>
+ *
+ * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
+ * to be drawn from last to first instead of first to last.
+ * @param transformer PageTransformer that will modify each page's animation properties
+ * @param pageLayerType View layer type that should be used for ViewPager pages. It should be
+ * either {@link ViewCompat#LAYER_TYPE_HARDWARE},
+ * {@link ViewCompat#LAYER_TYPE_SOFTWARE}, or
+ * {@link ViewCompat#LAYER_TYPE_NONE}.
+ */
+ public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer,
+ int pageLayerType) {
if (Build.VERSION.SDK_INT >= 11) {
final boolean hasTransformer = transformer != null;
final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
@@ -768,6 +799,7 @@
setChildrenDrawingOrderEnabledCompat(hasTransformer);
if (hasTransformer) {
mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
+ mPageTransformerLayerType = pageLayerType;
} else {
mDrawingOrder = DRAW_ORDER_DEFAULT;
}
@@ -898,7 +930,7 @@
* @param resId Resource ID of a drawable to display between pages
*/
public void setPageMarginDrawable(@DrawableRes int resId) {
- setPageMarginDrawable(getContext().getResources().getDrawable(resId));
+ setPageMarginDrawable(ContextCompat.getDrawable(getContext(), resId));
}
@Override
@@ -2007,7 +2039,7 @@
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final int layerType = enable
- ? ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE;
+ ? mPageTransformerLayerType : ViewCompat.LAYER_TYPE_NONE;
ViewCompat.setLayerType(getChildAt(i), layerType, null);
}
}
@@ -3077,6 +3109,9 @@
}
private class PagerObserver extends DataSetObserver {
+ PagerObserver() {
+ }
+
@Override
public void onChanged() {
dataSetChanged();
diff --git a/core-ui/java/android/support/v4/widget/AutoScrollHelper.java b/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
index bf4f1e4..4291a25 100644
--- a/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
+++ b/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
@@ -134,13 +134,13 @@
private static final int VERTICAL = 1;
/** Scroller used to control acceleration toward maximum velocity. */
- private final ClampedScroller mScroller = new ClampedScroller();
+ final ClampedScroller mScroller = new ClampedScroller();
/** Interpolator used to scale velocity with touch position. */
private final Interpolator mEdgeInterpolator = new AccelerateInterpolator();
/** The view to auto-scroll. Might not be the source of touch events. */
- private final View mTarget;
+ final View mTarget;
/** Runnable used to animate scrolling. */
private Runnable mRunnable;
@@ -170,13 +170,13 @@
private boolean mAlreadyDelayed;
/** Whether to reset the scroller start time on the next animation. */
- private boolean mNeedsReset;
+ boolean mNeedsReset;
/** Whether to send a cancel motion event to the target view. */
- private boolean mNeedsCancel;
+ boolean mNeedsCancel;
/** Whether the auto-scroller is actively scrolling. */
- private boolean mAnimating;
+ boolean mAnimating;
/** Whether the auto-scroller is enabled. */
private boolean mEnabled;
@@ -488,7 +488,7 @@
/**
* @return whether the target is able to scroll in the requested direction
*/
- private boolean shouldAnimate() {
+ boolean shouldAnimate() {
final ClampedScroller scroller = mScroller;
final int verticalDirection = scroller.getVerticalDirection();
final int horizontalDirection = scroller.getHorizontalDirection();
@@ -649,7 +649,7 @@
return 0;
}
- private static int constrain(int value, int min, int max) {
+ static int constrain(int value, int min, int max) {
if (value > max) {
return max;
} else if (value < min) {
@@ -659,7 +659,7 @@
}
}
- private static float constrain(float value, float min, float max) {
+ static float constrain(float value, float min, float max) {
if (value > max) {
return max;
} else if (value < min) {
@@ -673,7 +673,7 @@
* Sends a {@link MotionEvent#ACTION_CANCEL} event to the target view,
* canceling any ongoing touch events.
*/
- private void cancelTargetTouch() {
+ void cancelTargetTouch() {
final long eventTime = SystemClock.uptimeMillis();
final MotionEvent cancel = MotionEvent.obtain(
eventTime, eventTime, MotionEvent.ACTION_CANCEL, 0, 0, 0);
@@ -682,6 +682,9 @@
}
private class ScrollAnimationRunnable implements Runnable {
+ ScrollAnimationRunnable() {
+ }
+
@Override
public void run() {
if (!mAnimating) {
diff --git a/core-ui/java/android/support/v4/widget/CircleImageView.java b/core-ui/java/android/support/v4/widget/CircleImageView.java
index b04b56e..371c9a2 100644
--- a/core-ui/java/android/support/v4/widget/CircleImageView.java
+++ b/core-ui/java/android/support/v4/widget/CircleImageView.java
@@ -24,6 +24,7 @@
import android.graphics.Shader;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
+import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.view.animation.Animation;
import android.widget.ImageView;
@@ -46,7 +47,7 @@
private static final int SHADOW_ELEVATION = 4;
private Animation.AnimationListener mListener;
- private int mShadowRadius;
+ int mShadowRadius;
CircleImageView(Context context, int color) {
super(context);
@@ -71,7 +72,7 @@
setPadding(padding, padding, padding, padding);
}
circle.getPaint().setColor(color);
- setBackgroundDrawable(circle);
+ ViewCompat.setBackground(this, circle);
}
private boolean elevationSupported() {
@@ -113,7 +114,7 @@
* @param colorRes Id of a color resource.
*/
public void setBackgroundColorRes(int colorRes) {
- setBackgroundColor(getContext().getResources().getColor(colorRes));
+ setBackgroundColor(ContextCompat.getColor(getContext(), colorRes));
}
@Override
diff --git a/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java b/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java
index 3335b9f..98b63a4 100644
--- a/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java
+++ b/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java
@@ -31,13 +31,13 @@
private static final int MIN_SHOW_TIME = 500; // ms
private static final int MIN_DELAY = 500; // ms
- private long mStartTime = -1;
+ long mStartTime = -1;
- private boolean mPostedHide = false;
+ boolean mPostedHide = false;
- private boolean mPostedShow = false;
+ boolean mPostedShow = false;
- private boolean mDismissed = false;
+ boolean mDismissed = false;
private final Runnable mDelayedHide = new Runnable() {
diff --git a/core-ui/java/android/support/v4/widget/CursorAdapter.java b/core-ui/java/android/support/v4/widget/CursorAdapter.java
index d95f048..8beb4ab 100644
--- a/core-ui/java/android/support/v4/widget/CursorAdapter.java
+++ b/core-ui/java/android/support/v4/widget/CursorAdapter.java
@@ -476,6 +476,9 @@
}
private class MyDataSetObserver extends DataSetObserver {
+ MyDataSetObserver() {
+ }
+
@Override
public void onChanged() {
mDataValid = true;
diff --git a/core-ui/java/android/support/v4/widget/DrawerLayout.java b/core-ui/java/android/support/v4/widget/DrawerLayout.java
index 938cb0b..36b465b 100644
--- a/core-ui/java/android/support/v4/widget/DrawerLayout.java
+++ b/core-ui/java/android/support/v4/widget/DrawerLayout.java
@@ -173,12 +173,12 @@
private static final float TOUCH_SLOP_SENSITIVITY = 1.f;
- private static final int[] LAYOUT_ATTRS = new int[] {
+ static final int[] LAYOUT_ATTRS = new int[] {
android.R.attr.layout_gravity
};
/** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */
- private static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
+ static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
/** Whether the drawer shadow comes from setting elevation on the drawer. */
private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION =
@@ -506,7 +506,7 @@
* @param gravity Which drawer the shadow should apply to
*/
public void setDrawerShadow(@DrawableRes int resId, @EdgeGravity int gravity) {
- setDrawerShadow(getResources().getDrawable(resId), gravity);
+ setDrawerShadow(ContextCompat.getDrawable(getContext(), resId), gravity);
}
/**
@@ -1864,7 +1864,7 @@
return findVisibleDrawer() != null;
}
- private View findVisibleDrawer() {
+ View findVisibleDrawer() {
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
@@ -1995,7 +1995,7 @@
}
}
- private static boolean includeChildForAccessibility(View child) {
+ static boolean includeChildForAccessibility(View child) {
// If the child is not important for accessibility we make
// sure this hides the entire subtree rooted at it as the
// IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDATS is not
@@ -2146,7 +2146,7 @@
postDelayed(mPeekRunnable, PEEK_DELAY);
}
- private void peekDrawer() {
+ void peekDrawer() {
final View toCapture;
final int childLeft;
final int peekDistance = mDragger.getEdgeSize();
@@ -2226,9 +2226,9 @@
private static final int FLAG_IS_CLOSING = 0x4;
public int gravity = Gravity.NO_GRAVITY;
- private float onScreen;
- private boolean isPeeking;
- private int openState;
+ float onScreen;
+ boolean isPeeking;
+ int openState;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
index 3e44962..bb43456 100644
--- a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
+++ b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
@@ -717,7 +717,7 @@
* about the specified item
*/
@NonNull
- private AccessibilityNodeInfoCompat obtainAccessibilityNodeInfo(int virtualViewId) {
+ AccessibilityNodeInfoCompat obtainAccessibilityNodeInfo(int virtualViewId) {
if (virtualViewId == HOST_ID) {
return createNodeForHost();
}
@@ -867,7 +867,7 @@
return node;
}
- private boolean performAction(int virtualViewId, int action, Bundle arguments) {
+ boolean performAction(int virtualViewId, int action, Bundle arguments) {
switch (virtualViewId) {
case HOST_ID:
return performActionForHost(action, arguments);
@@ -1221,6 +1221,9 @@
* Exposes a virtual view hierarchy to the accessibility framework.
*/
private class MyNodeProvider extends AccessibilityNodeProviderCompat {
+ MyNodeProvider() {
+ }
+
@Override
public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) {
// The caller takes ownership of the node and is expected to
@@ -1234,5 +1237,15 @@
public boolean performAction(int virtualViewId, int action, Bundle arguments) {
return ExploreByTouchHelper.this.performAction(virtualViewId, action, arguments);
}
+
+ @Override
+ public AccessibilityNodeInfoCompat findFocus(int focusType) {
+ int focusedId = (focusType == AccessibilityNodeInfoCompat.FOCUS_ACCESSIBILITY) ?
+ mAccessibilityFocusedVirtualViewId : mKeyboardFocusedVirtualViewId;
+ if (focusedId == INVALID_ID) {
+ return null;
+ }
+ return createAccessibilityNodeInfo(focusedId);
+ }
}
}
diff --git a/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java b/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
index 6affe47..4cf43fa 100644
--- a/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
+++ b/core-ui/java/android/support/v4/widget/MaterialProgressDrawable.java
@@ -50,7 +50,7 @@
*/
class MaterialProgressDrawable extends Drawable implements Animatable {
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
- private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
+ static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
private static final float FULL_ROTATION = 1080.0f;
@Retention(RetentionPolicy.SOURCE)
@@ -110,7 +110,7 @@
private Resources mResources;
private View mParent;
private Animation mAnimation;
- private float mRotationCount;
+ float mRotationCount;
private double mWidth;
private double mHeight;
boolean mFinishing;
@@ -299,7 +299,7 @@
mRing.resetOriginals();
}
- private float getMinProgressArc(Ring ring) {
+ float getMinProgressArc(Ring ring) {
return (float) Math.toRadians(
ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));
}
@@ -329,7 +329,7 @@
* The new ring color will be a translation from the starting ring color to
* the next color.
*/
- private void updateRingColor(float interpolatedTime, Ring ring) {
+ void updateRingColor(float interpolatedTime, Ring ring) {
if (interpolatedTime > COLOR_START_DELAY_OFFSET) {
// scale the interpolatedTime so that the full
// transformation from 0 - 1 takes place in the
@@ -340,7 +340,7 @@
}
}
- private void applyFinishTranslation(float interpolatedTime, Ring ring) {
+ void applyFinishTranslation(float interpolatedTime, Ring ring) {
// shrink back down and complete a full rotation before
// starting other circles
// Rotation goes between [0..1].
diff --git a/core-ui/java/android/support/v4/widget/NestedScrollView.java b/core-ui/java/android/support/v4/widget/NestedScrollView.java
index 3e4c55f..0d40bc9 100644
--- a/core-ui/java/android/support/v4/widget/NestedScrollView.java
+++ b/core-ui/java/android/support/v4/widget/NestedScrollView.java
@@ -998,7 +998,7 @@
return clampedX || clampedY;
}
- private int getScrollRange() {
+ int getScrollRange() {
int scrollRange = 0;
if (getChildCount() > 0) {
View child = getChildAt(0);
diff --git a/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java b/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
index 7467989..1e5479b 100644
--- a/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
+++ b/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
@@ -31,6 +31,7 @@
import android.os.Parcelable;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
+import android.support.v4.content.ContextCompat;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.AbsSavedState;
@@ -146,13 +147,13 @@
/**
* The child view that can slide, if any.
*/
- private View mSlideableView;
+ View mSlideableView;
/**
* How far the panel is offset from its closed position.
* range [0, 1] where 0 = closed, 1 = open.
*/
- private float mSlideOffset;
+ float mSlideOffset;
/**
* How far the non-sliding panel is parallaxed from its usual position when open.
@@ -163,13 +164,13 @@
/**
* How far in pixels the slideable panel may move.
*/
- private int mSlideRange;
+ int mSlideRange;
/**
* A panel view is locked into internal scrolling or another condition that
* is preventing a drag.
*/
- private boolean mIsUnableToDrag;
+ boolean mIsUnableToDrag;
/**
* Distance in pixels to parallax the fixed pane by when fully closed
@@ -181,19 +182,19 @@
private PanelSlideListener mPanelSlideListener;
- private final ViewDragHelper mDragHelper;
+ final ViewDragHelper mDragHelper;
/**
* Stores whether or not the pane was open the last time it was slideable.
* If open/close operations are invoked this state is modified. Used by
* instance state save/restore.
*/
- private boolean mPreservedOpenState;
+ boolean mPreservedOpenState;
private boolean mFirstLayout = true;
private final Rect mTmpRect = new Rect();
- private final ArrayList<DisableLayerRunnable> mPostedRunnables =
+ final ArrayList<DisableLayerRunnable> mPostedRunnables =
new ArrayList<DisableLayerRunnable>();
static final SlidingPanelLayoutImpl IMPL;
@@ -945,7 +946,7 @@
return mCanSlide;
}
- private void onPanelDragged(int newLeft) {
+ void onPanelDragged(int newLeft) {
if (mSlideableView == null) {
// This can happen if we're aborting motion during layout because everything now fits.
mSlideOffset = 0;
@@ -1043,7 +1044,7 @@
return result;
}
- private void invalidateChildRegion(View v) {
+ void invalidateChildRegion(View v) {
IMPL.invalidateChildRegion(this, v);
}
@@ -1145,7 +1146,7 @@
* @param resId Resource ID of a drawable to use
*/
public void setShadowResourceLeft(int resId) {
- setShadowDrawableLeft(getResources().getDrawable(resId));
+ setShadowDrawableLeft(ContextCompat.getDrawable(getContext(), resId));
}
/**
@@ -1155,10 +1156,9 @@
* @param resId Resource ID of a drawable to use
*/
public void setShadowResourceRight(int resId) {
- setShadowDrawableRight(getResources().getDrawable(resId));
+ setShadowDrawableRight(ContextCompat.getDrawable(getContext(), resId));
}
-
@Override
public void draw(Canvas c) {
super.draw(c);
@@ -1312,6 +1312,9 @@
private class DragHelperCallback extends ViewDragHelper.Callback {
+ DragHelperCallback() {
+ }
+
@Override
public boolean tryCaptureView(View child, int pointerId) {
if (mIsUnableToDrag) {
@@ -1467,7 +1470,7 @@
super(superState);
}
- private SavedState(Parcel in, ClassLoader loader) {
+ SavedState(Parcel in, ClassLoader loader) {
super(in, loader);
isOpen = in.readInt() != 0;
}
@@ -1658,7 +1661,7 @@
}
}
- private boolean isLayoutRtlSupport() {
+ boolean isLayoutRtlSupport() {
return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
}
}
diff --git a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
index 769a08b..4ebdeed 100644
--- a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -23,6 +23,7 @@
import android.support.annotation.ColorRes;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.support.v4.content.ContextCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingChildHelper;
@@ -102,8 +103,8 @@
private static final int DEFAULT_CIRCLE_TARGET = 64;
private View mTarget; // the target of the gesture
- private OnRefreshListener mListener;
- private boolean mRefreshing = false;
+ OnRefreshListener mListener;
+ boolean mRefreshing = false;
private int mTouchSlop;
private float mTotalDragDistance = -1;
@@ -118,14 +119,14 @@
private boolean mNestedScrollInProgress;
private int mMediumAnimationDuration;
- private int mCurrentTargetOffsetTop;
+ int mCurrentTargetOffsetTop;
private float mInitialMotionY;
private float mInitialDownY;
private boolean mIsBeingDragged;
private int mActivePointerId = INVALID_POINTER;
// Whether this item is scaled up rather than clipped
- private boolean mScale;
+ boolean mScale;
// Target is returning to its start offset because it was cancelled or a
// refresh was triggered.
@@ -135,16 +136,18 @@
android.R.attr.enabled
};
- private CircleImageView mCircleView;
+ CircleImageView mCircleView;
private int mCircleViewIndex = -1;
protected int mFrom;
- private float mStartingScale;
+ float mStartingScale;
protected int mOriginalOffsetTop;
- private MaterialProgressDrawable mProgress;
+ int mSpinnerOffsetEnd;
+
+ MaterialProgressDrawable mProgress;
private Animation mScaleAnimation;
@@ -156,14 +159,12 @@
private Animation mScaleDownToStartAnimation;
- private float mSpinnerFinalOffset;
-
- private boolean mNotify;
+ boolean mNotify;
private int mCircleDiameter;
// Whether the client has set a custom starting position;
- private boolean mUsingCustomStart;
+ boolean mUsingCustomStart;
private OnChildScrollUpCallback mChildScrollUpCallback;
@@ -194,7 +195,7 @@
}
};
- private void reset() {
+ void reset() {
mCircleView.clearAnimation();
mProgress.stop();
mCircleView.setVisibility(View.GONE);
@@ -250,13 +251,29 @@
public void setProgressViewOffset(boolean scale, int start, int end) {
mScale = scale;
mOriginalOffsetTop = start;
- mSpinnerFinalOffset = end;
+ mSpinnerOffsetEnd = end;
mUsingCustomStart = true;
reset();
mRefreshing = false;
}
/**
+ * @return The offset in pixels from the top of this view at which the progress spinner should
+ * appear.
+ */
+ public int getProgressViewStartOffset() {
+ return mOriginalOffsetTop;
+ }
+
+ /**
+ * @return The offset in pixels from the top of this view at which the progress spinner should
+ * come to rest after a successful swipe gesture.
+ */
+ public int getProgressViewEndOffset() {
+ return mSpinnerOffsetEnd;
+ }
+
+ /**
* The refresh indicator resting position is always positioned near the top
* of the refreshing content. This position is a consistent location, but
* can be adjusted in either direction based on whether or not there is a
@@ -270,7 +287,7 @@
* gesture.
*/
public void setProgressViewEndTarget(boolean scale, int end) {
- mSpinnerFinalOffset = end;
+ mSpinnerOffsetEnd = end;
mScale = scale;
mCircleView.invalidate();
}
@@ -328,8 +345,8 @@
createProgressView();
ViewCompat.setChildrenDrawingOrderEnabled(this, true);
// the absolute offset has to take into account that the circle starts at an offset
- mSpinnerFinalOffset = DEFAULT_CIRCLE_TARGET * metrics.density;
- mTotalDragDistance = mSpinnerFinalOffset;
+ mSpinnerOffsetEnd = (int) (DEFAULT_CIRCLE_TARGET * metrics.density);
+ mTotalDragDistance = mSpinnerOffsetEnd;
mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
@@ -395,9 +412,9 @@
mRefreshing = refreshing;
int endTarget = 0;
if (!mUsingCustomStart) {
- endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop);
+ endTarget = mSpinnerOffsetEnd + mOriginalOffsetTop;
} else {
- endTarget = (int) mSpinnerFinalOffset;
+ endTarget = mSpinnerOffsetEnd;
}
setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop,
true /* requires update */);
@@ -434,7 +451,7 @@
* Pre API 11, this does an alpha animation.
* @param progress
*/
- private void setAnimationProgress(float progress) {
+ void setAnimationProgress(float progress) {
if (isAlphaUsedForScale()) {
setColorViewAlpha((int) (progress * MAX_ALPHA));
} else {
@@ -456,7 +473,7 @@
}
}
- private void startScaleDownAnimation(Animation.AnimationListener listener) {
+ void startScaleDownAnimation(Animation.AnimationListener listener) {
mScaleDownAnimation = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
@@ -512,7 +529,7 @@
* @param colorRes Resource id of the color.
*/
public void setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) {
- setProgressBackgroundColorSchemeColor(getResources().getColor(colorRes));
+ setProgressBackgroundColorSchemeColor(ContextCompat.getColor(getContext(), colorRes));
}
/**
@@ -541,10 +558,10 @@
* @param colorResIds
*/
public void setColorSchemeResources(@ColorRes int... colorResIds) {
- final Resources res = getResources();
+ final Context context = getContext();
int[] colorRes = new int[colorResIds.length];
for (int i = 0; i < colorResIds.length; i++) {
- colorRes[i] = res.getColor(colorResIds[i]);
+ colorRes[i] = ContextCompat.getColor(context, colorResIds[i]);
}
setColorSchemeColors(colorRes);
}
@@ -915,8 +932,8 @@
float dragPercent = Math.min(1f, Math.abs(originalDragPercent));
float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3;
float extraOS = Math.abs(overscrollTop) - mTotalDragDistance;
- float slingshotDist = mUsingCustomStart ? mSpinnerFinalOffset - mOriginalOffsetTop
- : mSpinnerFinalOffset;
+ float slingshotDist = mUsingCustomStart ? mSpinnerOffsetEnd - mOriginalOffsetTop
+ : mSpinnerOffsetEnd;
float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2)
/ slingshotDist);
float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow(
@@ -1113,9 +1130,9 @@
int targetTop = 0;
int endTarget = 0;
if (!mUsingCustomStart) {
- endTarget = (int) (mSpinnerFinalOffset - Math.abs(mOriginalOffsetTop));
+ endTarget = mSpinnerOffsetEnd - Math.abs(mOriginalOffsetTop);
} else {
- endTarget = (int) mSpinnerFinalOffset;
+ endTarget = mSpinnerOffsetEnd;
}
targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
int offset = targetTop - mCircleView.getTop();
@@ -1124,7 +1141,7 @@
}
};
- private void moveToStart(float interpolatedTime) {
+ void moveToStart(float interpolatedTime) {
int targetTop = 0;
targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
int offset = targetTop - mCircleView.getTop();
@@ -1162,7 +1179,7 @@
mCircleView.startAnimation(mScaleDownToStartAnimation);
}
- private void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
+ void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
mCircleView.bringToFront();
ViewCompat.offsetTopAndBottom(mCircleView, offset);
mCurrentTargetOffsetTop = mCircleView.getTop();
diff --git a/core-utils/tests/AndroidManifest.xml b/core-utils/tests/AndroidManifest.xml
index d80e735..8a30a93 100644
--- a/core-utils/tests/AndroidManifest.xml
+++ b/core-utils/tests/AndroidManifest.xml
@@ -35,7 +35,13 @@
<uses-library android:name="android.test.runner" />
<activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
<activity android:name="android.support.v4.widget.TestActivity"/>
-
+ <activity android:name="android.support.v4.provider.GrantActivity"
+ android:label="_GrantActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="moocow"
diff --git a/tests/java/android/support/v4/provider/DocumentFileTest.java b/core-utils/tests/java/android/support/v4/provider/DocumentFileTest.java
similarity index 98%
rename from tests/java/android/support/v4/provider/DocumentFileTest.java
rename to core-utils/tests/java/android/support/v4/provider/DocumentFileTest.java
index 26c10a4..9dd5a51 100644
--- a/tests/java/android/support/v4/provider/DocumentFileTest.java
+++ b/core-utils/tests/java/android/support/v4/provider/DocumentFileTest.java
@@ -22,7 +22,8 @@
import android.os.Environment;
import android.os.SystemClock;
import android.test.AndroidTestCase;
-import android.util.Log;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -34,7 +35,11 @@
/**
* Tests for {@link DocumentFile}
+ *
*/
+// These tests fail so it is marked @Suppress. Fix is tracked in b/27168036
+@Suppress
+@MediumTest
public class DocumentFileTest extends AndroidTestCase {
private Uri treeUri;
diff --git a/tests/java/android/support/tests/GrantActivity.java b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
similarity index 97%
rename from tests/java/android/support/tests/GrantActivity.java
rename to core-utils/tests/java/android/support/v4/provider/GrantActivity.java
index 854357f..c4dbb27 100644
--- a/tests/java/android/support/tests/GrantActivity.java
+++ b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.tests;
+package android.support.v4.provider;
import android.app.Activity;
import android.content.ContentResolver;
diff --git a/design/Android.mk b/design/Android.mk
index e9ba5b6..38ca592 100644
--- a/design/Android.mk
+++ b/design/Android.mk
@@ -101,7 +101,8 @@
android-support-design-res \
android-support-v4 \
android-support-v7-appcompat \
- android-support-v7-recyclerview
+ android-support-v7-recyclerview \
+ android-support-transition
LOCAL_JAVA_LANGUAGE_VERSION := 1.7
include $(BUILD_STATIC_JAVA_LIBRARY)
@@ -115,7 +116,8 @@
android-support-design-res \
android-support-v4 \
android-support-v7-appcompat \
- android-support-v7-recyclerview
+ android-support-v7-recyclerview \
+ android-support-transition
LOCAL_JAVA_LANGUAGE_VERSION := 1.7
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/design/AndroidManifest.xml b/design/AndroidManifest.xml
index 82f19db..d51186d 100644
--- a/design/AndroidManifest.xml
+++ b/design/AndroidManifest.xml
@@ -14,7 +14,9 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="android.support.design">
- <uses-sdk android:minSdkVersion="9"/>
+ <uses-sdk android:minSdkVersion="9"
+ tools:overrideLibrary="android.support.transition"/>
<application />
</manifest>
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java
similarity index 68%
copy from compat/api22/android/support/v4/app/ActivityCompat22.java
copy to design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java
index 3946f1d..22501c1 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/design/base/android/support/design/internal/BottomNavigationAnimationHelperBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package android.support.v4.app;
+package android.support.design.internal;
-import android.app.Activity;
-import android.net.Uri;
+import android.view.ViewGroup;
-class ActivityCompat22 {
- public static Uri getReferrer(Activity activity) {
- return activity.getReferrer();
+class BottomNavigationAnimationHelperBase {
+ void beginDelayedTransition(ViewGroup view) {
+ // Do nothing.
}
}
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index 9670035..872fae4 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -16,6 +16,7 @@
package android.support.design.widget;
+import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
@@ -25,6 +26,7 @@
import android.graphics.drawable.GradientDrawable;
import android.support.annotation.Nullable;
import android.support.design.R;
+import android.support.v4.content.ContextCompat;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
@@ -148,13 +150,13 @@
}
CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
- final Resources resources = mView.getResources();
+ final Context context = mView.getContext();
CircularBorderDrawable borderDrawable = newCircularDrawable();
borderDrawable.setGradientColors(
- resources.getColor(R.color.design_fab_stroke_top_outer_color),
- resources.getColor(R.color.design_fab_stroke_top_inner_color),
- resources.getColor(R.color.design_fab_stroke_end_inner_color),
- resources.getColor(R.color.design_fab_stroke_end_outer_color));
+ ContextCompat.getColor(context, R.color.design_fab_stroke_top_outer_color),
+ ContextCompat.getColor(context, R.color.design_fab_stroke_top_inner_color),
+ ContextCompat.getColor(context, R.color.design_fab_stroke_end_inner_color),
+ ContextCompat.getColor(context, R.color.design_fab_stroke_end_outer_color));
borderDrawable.setBorderWidth(borderWidth);
borderDrawable.setBorderTint(backgroundTint);
return borderDrawable;
diff --git a/design/base/android/support/design/widget/ShadowDrawableWrapper.java b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
index bd7997f..dfb8e1d 100644
--- a/design/base/android/support/design/widget/ShadowDrawableWrapper.java
+++ b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
@@ -16,7 +16,7 @@
package android.support.design.widget;
-import android.content.res.Resources;
+import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
@@ -28,6 +28,7 @@
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.support.design.R;
+import android.support.v4.content.ContextCompat;
import android.support.v7.graphics.drawable.DrawableWrapper;
/**
@@ -78,13 +79,13 @@
*/
private boolean mPrintedShadowClipWarning = false;
- public ShadowDrawableWrapper(Resources resources, Drawable content, float radius,
+ public ShadowDrawableWrapper(Context context, Drawable content, float radius,
float shadowSize, float maxShadowSize) {
super(content);
- mShadowStartColor = resources.getColor(R.color.design_fab_shadow_start_color);
- mShadowMiddleColor = resources.getColor(R.color.design_fab_shadow_mid_color);
- mShadowEndColor = resources.getColor(R.color.design_fab_shadow_end_color);
+ mShadowStartColor = ContextCompat.getColor(context, R.color.design_fab_shadow_start_color);
+ mShadowMiddleColor = ContextCompat.getColor(context, R.color.design_fab_shadow_mid_color);
+ mShadowEndColor = ContextCompat.getColor(context, R.color.design_fab_shadow_end_color);
mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mCornerShadowPaint.setStyle(Paint.Style.FILL);
diff --git a/design/base/android/support/design/widget/StateListAnimator.java b/design/base/android/support/design/widget/StateListAnimator.java
index 7ef944e..4378ef9 100644
--- a/design/base/android/support/design/widget/StateListAnimator.java
+++ b/design/base/android/support/design/widget/StateListAnimator.java
@@ -25,7 +25,7 @@
private final ArrayList<Tuple> mTuples = new ArrayList<>();
private Tuple mLastMatch = null;
- private ValueAnimatorCompat mRunningAnimator = null;
+ ValueAnimatorCompat mRunningAnimator = null;
private final ValueAnimatorCompat.AnimatorListener mAnimationListener
= new ValueAnimatorCompat.AnimatorListenerAdapter() {
@@ -105,7 +105,7 @@
final int[] mSpecs;
final ValueAnimatorCompat mAnimator;
- private Tuple(int[] specs, ValueAnimatorCompat animator) {
+ Tuple(int[] specs, ValueAnimatorCompat animator) {
mSpecs = specs;
mAnimator = animator;
}
diff --git a/design/build.gradle b/design/build.gradle
index 4407ba9..8ae45d7 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -6,6 +6,7 @@
compile project(':support-v4')
compile project(':support-appcompat-v7')
compile project(':support-recyclerview-v7')
+ compile project(':support-transition')
androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
exclude module: 'support-annotations'
diff --git a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
index 2cd3de5..d17691c 100644
--- a/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
+++ b/design/gingerbread/android/support/design/widget/FloatingActionButtonGingerbread.java
@@ -87,7 +87,7 @@
mContentBackground = new LayerDrawable(layers);
mShadowDrawable = new ShadowDrawableWrapper(
- mView.getResources(),
+ mView.getContext(),
mContentBackground,
mShadowViewDelegate.getRadius(),
mElevation,
@@ -246,6 +246,9 @@
}
private class ResetElevationAnimation extends ShadowAnimatorImpl {
+ ResetElevationAnimation() {
+ }
+
@Override
protected float getTargetShadowSize() {
return mElevation;
@@ -253,6 +256,9 @@
}
private class ElevateToTranslationZAnimation extends ShadowAnimatorImpl {
+ ElevateToTranslationZAnimation() {
+ }
+
@Override
protected float getTargetShadowSize() {
return mElevation + mPressedTranslationZ;
@@ -260,6 +266,9 @@
}
private class DisabledElevationAnimation extends ShadowAnimatorImpl {
+ DisabledElevationAnimation() {
+ }
+
@Override
protected float getTargetShadowSize() {
return 0f;
diff --git a/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java b/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java
new file mode 100644
index 0000000..6681d0b
--- /dev/null
+++ b/design/ics/android/support/design/internal/BottomNavigationAnimationHelperIcs.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.support.transition.AutoTransition;
+import android.support.transition.TransitionManager;
+import android.support.transition.TransitionSet;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.view.ViewGroup;
+
+class BottomNavigationAnimationHelperIcs extends BottomNavigationAnimationHelperBase {
+ private static final long ACTIVE_ANIMATION_DURATION_MS = 115L;
+
+ private final TransitionSet mSet;
+
+ BottomNavigationAnimationHelperIcs() {
+ mSet = new AutoTransition();
+ mSet.setOrdering(TransitionSet.ORDERING_TOGETHER);
+ mSet.setDuration(ACTIVE_ANIMATION_DURATION_MS);
+ mSet.setInterpolator(new FastOutSlowInInterpolator());
+ TextScale textScale = new TextScale();
+ mSet.addTransition(textScale);
+ }
+
+ void beginDelayedTransition(ViewGroup view) {
+ TransitionManager.beginDelayedTransition(view, mSet);
+ }
+}
diff --git a/design/ics/android/support/design/internal/TextScale.java b/design/ics/android/support/design/internal/TextScale.java
new file mode 100644
index 0000000..219353e
--- /dev/null
+++ b/design/ics/android/support/design/internal/TextScale.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.support.transition.Transition;
+import android.support.transition.TransitionValues;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.Map;
+
+/**
+ * @hide
+ */
+public class TextScale extends Transition {
+ private static final String PROPNAME_SCALE = "android:textscale:scale";
+
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ private void captureValues(TransitionValues transitionValues) {
+ if (transitionValues.view instanceof TextView) {
+ TextView textview = (TextView) transitionValues.view;
+ transitionValues.values.put(PROPNAME_SCALE, textview.getScaleX());
+ }
+ }
+
+ @Override
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null || !(startValues.view instanceof TextView)
+ || !(endValues.view instanceof TextView)) {
+ return null;
+ }
+ final TextView view = (TextView) endValues.view;
+ Map<String, Object> startVals = startValues.values;
+ Map<String, Object> endVals = endValues.values;
+ final float startSize = startVals.get(PROPNAME_SCALE) != null ? (float) startVals.get(
+ PROPNAME_SCALE) : 1f;
+ final float endSize = endVals.get(PROPNAME_SCALE) != null ? (float) endVals.get(
+ PROPNAME_SCALE) : 1f;
+ if (startSize == endSize) {
+ return null;
+ }
+
+ ValueAnimator animator = ValueAnimator.ofFloat(startSize, endSize);
+
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ float animatedValue = (float) valueAnimator.getAnimatedValue();
+ view.setScaleX(animatedValue);
+ view.setScaleY(animatedValue);
+ }
+ });
+ return animator;
+ }
+}
diff --git a/design/res-public/values/public_styles.xml b/design/res-public/values/public_styles.xml
index a7c0af6..0dcde45 100644
--- a/design/res-public/values/public_styles.xml
+++ b/design/res-public/values/public_styles.xml
@@ -24,6 +24,7 @@
<public type="style" name="TextAppearance.Design.Snackbar.Message"/>
<public type="style" name="TextAppearance.Design.Tab"/>
<public type="style" name="Theme.Design"/>
+ <public type="style" name="Theme.Design.BottomNavigationView"/>
<public type="style" name="Theme.Design.BottomSheetDialog"/>
<public type="style" name="Theme.Design.Light"/>
<public type="style" name="Theme.Design.Light.BottomSheetDialog"/>
diff --git a/design/res/drawable-v21/design_bottom_navigation_item_background.xml b/design/res/drawable-v21/design_bottom_navigation_item_background.xml
new file mode 100644
index 0000000..f30f08b
--- /dev/null
+++ b/design/res/drawable-v21/design_bottom_navigation_item_background.xml
@@ -0,0 +1,19 @@
+<?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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?attr/colorPrimary" />
\ No newline at end of file
diff --git a/design/res/drawable/design_bottom_navigation_item_background.xml b/design/res/drawable/design_bottom_navigation_item_background.xml
new file mode 100644
index 0000000..7674f42
--- /dev/null
+++ b/design/res/drawable/design_bottom_navigation_item_background.xml
@@ -0,0 +1,29 @@
+<?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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <solid android:color="#ff0000"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="#ffffff"/>
+ </shape>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/design/res/layout/design_bottom_navigation_item.xml b/design/res/layout/design_bottom_navigation_item.xml
new file mode 100644
index 0000000..cc7bb5f
--- /dev/null
+++ b/design/res/layout/design_bottom_navigation_item.xml
@@ -0,0 +1,46 @@
+<?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.
+ -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/design_bottom_navigation_margin"
+ android:layout_marginBottom="@dimen/design_bottom_navigation_margin"
+ android:duplicateParentState="true" />
+ <android.support.design.internal.BaselineLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/design_bottom_navigation_margin"
+ android:layout_gravity="bottom|center_horizontal"
+ android:duplicateParentState="true">
+ <TextView
+ android:id="@+id/smallLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/design_bottom_navigation_text_size"
+ android:duplicateParentState="true" />
+ <TextView
+ android:id="@+id/largeLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="invisible"
+ android:textSize="@dimen/design_bottom_navigation_active_text_size"
+ android:duplicateParentState="true" />
+ </android.support.design.internal.BaselineLayout>
+</merge>
\ No newline at end of file
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index 7ae7433..545a82e 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -463,4 +463,12 @@
<attr name="textColorError" format="color" />
</declare-styleable>
+ <declare-styleable name="BottomNavigationView">
+ <!-- The menu resource to inflate and populate items from. -->
+ <attr name="menu"/>
+ <attr name="itemIconTint"/>
+ <attr name="itemTextColor"/>
+ <attr name="itemBackground"/>
+ </declare-styleable>
+
</resources>
diff --git a/design/res/values/dimens.xml b/design/res/values/dimens.xml
index 546d137..63e98b8 100644
--- a/design/res/values/dimens.xml
+++ b/design/res/values/dimens.xml
@@ -62,6 +62,7 @@
<dimen name="design_bottom_navigation_text_size">12sp</dimen>
<dimen name="design_bottom_navigation_active_text_size">14sp</dimen>
<dimen name="design_bottom_navigation_margin">8dp</dimen>
+ <dimen name="design_bottom_navigation_item_min_width">56dp</dimen>
<dimen name="design_bottom_navigation_item_max_width">96dp</dimen>
<dimen name="design_bottom_navigation_active_item_max_width">168dp</dimen>
diff --git a/design/res/values/styles.xml b/design/res/values/styles.xml
index 848d2cf..c8b9cd5 100644
--- a/design/res/values/styles.xml
+++ b/design/res/values/styles.xml
@@ -42,6 +42,10 @@
<item name="tabMode">fixed</item>
</style>
+ <style name="Widget.Design.BottomNavigationView" parent="">
+ <item name="itemBackground">?attr/selectableItemBackgroundBorderless</item>
+ </style>
+
<style name="Base.Widget.Design.TabLayout" parent="android:Widget">
<item name="tabMaxWidth">@dimen/design_tab_max_width</item>
<item name="tabIndicatorColor">?attr/colorAccent</item>
diff --git a/design/src/android/support/design/internal/BaselineLayout.java b/design/src/android/support/design/internal/BaselineLayout.java
new file mode 100644
index 0000000..eac3542
--- /dev/null
+++ b/design/src/android/support/design/internal/BaselineLayout.java
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.ViewUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A simple ViewGroup that aligns all the views inside on a baseline.
+ *
+ * @hide
+ */
+public class BaselineLayout extends ViewGroup {
+ private int mBaseline = -1;
+
+ public BaselineLayout(Context context) {
+ super(context, null, 0);
+ }
+
+ public BaselineLayout(Context context, AttributeSet attrs) {
+ super(context, attrs, 0);
+ }
+
+ public BaselineLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int count = getChildCount();
+ int maxWidth = 0;
+ int maxHeight = 0;
+ int maxChildBaseline = -1;
+ int maxChildDescent = -1;
+ int childState = 0;
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+
+ measureChild(child, widthMeasureSpec, heightMeasureSpec);
+ final int baseline = child.getBaseline();
+ if (baseline != -1) {
+ maxChildBaseline = Math.max(maxChildBaseline, baseline);
+ maxChildDescent = Math.max(maxChildDescent, child.getMeasuredHeight() - baseline);
+ }
+ maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
+ maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+ childState = ViewUtils.combineMeasuredStates(childState,
+ ViewCompat.getMeasuredState(child));
+ }
+ if (maxChildBaseline != -1) {
+ maxHeight = Math.max(maxHeight, maxChildBaseline + maxChildDescent);
+ mBaseline = maxChildBaseline;
+ }
+ maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+ maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+ setMeasuredDimension(
+ ViewCompat.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+ ViewCompat.resolveSizeAndState(maxHeight, heightMeasureSpec,
+ childState << MEASURED_HEIGHT_STATE_SHIFT));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final int count = getChildCount();
+ final int parentLeft = getPaddingLeft();
+ final int parentRight = right - left - getPaddingRight();
+ final int parentContentWidth = parentRight - parentLeft;
+ final int parentTop = getPaddingTop();
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+
+ final int width = child.getMeasuredWidth();
+ final int height = child.getMeasuredHeight();
+
+ final int childLeft = parentLeft + (parentContentWidth - width) / 2;
+ final int childTop;
+ if (mBaseline != -1 && child.getBaseline() != -1) {
+ childTop = parentTop + mBaseline - child.getBaseline();
+ } else {
+ childTop = parentTop;
+ }
+
+ child.layout(childLeft, childTop, childLeft + width, childTop + height);
+ }
+ }
+
+ @Override
+ public int getBaseline() {
+ return mBaseline;
+ }
+}
diff --git a/design/src/android/support/design/internal/BottomNavigationItemView.java b/design/src/android/support/design/internal/BottomNavigationItemView.java
new file mode 100644
index 0000000..d5e8176
--- /dev/null
+++ b/design/src/android/support/design/internal/BottomNavigationItemView.java
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.design.R;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuView;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * @hide
+ */
+public class BottomNavigationItemView extends FrameLayout implements MenuView.ItemView {
+ public static final int INVALID_ITEM_POSITION = -1;
+
+ private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
+
+ private final int mDefaultMargin;
+ private final int mShiftAmount;
+ private final float mScaleUpFactor;
+ private final float mScaleDownFactor;
+
+ private boolean mShiftingMode;
+
+ private ImageView mIcon;
+ private final TextView mSmallLabel;
+ private final TextView mLargeLabel;
+ private int mItemPosition = INVALID_ITEM_POSITION;
+
+ private MenuItemImpl mItemData;
+
+ private ColorStateList mIconTint;
+
+ public BottomNavigationItemView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public BottomNavigationItemView(@NonNull Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BottomNavigationItemView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ final Resources res = getResources();
+ int inactiveLabelSize =
+ res.getDimensionPixelSize(R.dimen.design_bottom_navigation_text_size);
+ int activeLabelSize = res.getDimensionPixelSize(
+ R.dimen.design_bottom_navigation_active_text_size);
+ mDefaultMargin = res.getDimensionPixelSize(R.dimen.design_bottom_navigation_margin);
+ mShiftAmount = inactiveLabelSize - activeLabelSize;
+ mScaleUpFactor = 1f * activeLabelSize / inactiveLabelSize;
+ mScaleDownFactor = 1f * inactiveLabelSize / activeLabelSize;
+
+ LayoutInflater.from(context).inflate(R.layout.design_bottom_navigation_item, this, true);
+ setBackgroundResource(R.drawable.design_bottom_navigation_item_background);
+ mIcon = (ImageView) findViewById(R.id.icon);
+ mSmallLabel = (TextView) findViewById(R.id.smallLabel);
+ mLargeLabel = (TextView) findViewById(R.id.largeLabel);
+
+ }
+
+ @Override
+ public void initialize(MenuItemImpl itemData, int menuType) {
+ mItemData = itemData;
+ setCheckable(itemData.isCheckable());
+ setChecked(itemData.isChecked());
+ setEnabled(itemData.isEnabled());
+ setIcon(itemData.getIcon());
+ setTitle(itemData.getTitle());
+ setId(itemData.getItemId());
+ }
+
+ public void setItemPosition(int position) {
+ mItemPosition = position;
+ }
+
+ public int getItemPosition() {
+ return mItemPosition;
+ }
+
+ public void setShiftingMode(boolean enabled) {
+ mShiftingMode = enabled;
+ }
+
+ @Override
+ public MenuItemImpl getItemData() {
+ return mItemData;
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ mSmallLabel.setText(title);
+ mLargeLabel.setText(title);
+ }
+
+ @Override
+ public void setCheckable(boolean checkable) {
+ refreshDrawableState();
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ mItemData.setChecked(checked);
+
+ ViewCompat.setPivotX(mLargeLabel, mLargeLabel.getWidth() / 2);
+ ViewCompat.setPivotY(mLargeLabel, mLargeLabel.getBaseline());
+ ViewCompat.setPivotX(mSmallLabel, mSmallLabel.getWidth() / 2);
+ ViewCompat.setPivotY(mSmallLabel, mSmallLabel.getBaseline());
+ if (mShiftingMode) {
+ if (checked) {
+ LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
+ iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+ iconParams.topMargin = mDefaultMargin;
+ mIcon.setLayoutParams(iconParams);
+ mLargeLabel.setVisibility(VISIBLE);
+ ViewCompat.setScaleX(mLargeLabel, 1f);
+ ViewCompat.setScaleY(mLargeLabel, 1f);
+ } else {
+ LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
+ iconParams.gravity = Gravity.CENTER;
+ iconParams.topMargin = mDefaultMargin;
+ mIcon.setLayoutParams(iconParams);
+ mLargeLabel.setVisibility(INVISIBLE);
+ ViewCompat.setScaleX(mLargeLabel, 0.5f);
+ ViewCompat.setScaleY(mLargeLabel, 0.5f);
+ }
+ mSmallLabel.setVisibility(INVISIBLE);
+ } else {
+ if (checked) {
+ LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
+ iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+ iconParams.topMargin = mDefaultMargin + mShiftAmount;
+ mIcon.setLayoutParams(iconParams);
+ mLargeLabel.setVisibility(VISIBLE);
+ mSmallLabel.setVisibility(INVISIBLE);
+
+ ViewCompat.setScaleX(mLargeLabel, 1f);
+ ViewCompat.setScaleY(mLargeLabel, 1f);
+ ViewCompat.setScaleX(mSmallLabel, mScaleUpFactor);
+ ViewCompat.setScaleY(mSmallLabel, mScaleUpFactor);
+ } else {
+ LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
+ iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+ iconParams.topMargin = mDefaultMargin;
+ mIcon.setLayoutParams(iconParams);
+ mLargeLabel.setVisibility(INVISIBLE);
+ mSmallLabel.setVisibility(VISIBLE);
+
+ ViewCompat.setScaleX(mLargeLabel, mScaleDownFactor);
+ ViewCompat.setScaleY(mLargeLabel, mScaleDownFactor);
+ ViewCompat.setScaleX(mSmallLabel, 1f);
+ ViewCompat.setScaleY(mSmallLabel, 1f);
+ }
+ }
+
+ refreshDrawableState();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ mSmallLabel.setEnabled(enabled);
+ mLargeLabel.setEnabled(enabled);
+ mIcon.setEnabled(enabled);
+ }
+
+ @Override
+ public int[] onCreateDrawableState(final int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ if (mItemData != null && mItemData.isCheckable() && mItemData.isChecked()) {
+ mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+ }
+ return drawableState;
+ }
+
+ @Override
+ public void setShortcut(boolean showShortcut, char shortcutKey) {
+ }
+
+ @Override
+ public void setIcon(Drawable icon) {
+ if (icon != null) {
+ Drawable.ConstantState state = icon.getConstantState();
+ icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate();
+ DrawableCompat.setTintList(icon, mIconTint);
+ }
+ mIcon.setImageDrawable(icon);
+ }
+
+ @Override
+ public boolean prefersCondensedTitle() {
+ return false;
+ }
+
+ @Override
+ public boolean showsIcon() {
+ return true;
+ }
+
+ public void setIconTintList(ColorStateList tint) {
+ mIconTint = tint;
+ if (mItemData != null) {
+ // Update the icon so that the tint takes effect
+ setIcon(mItemData.getIcon());
+ }
+ }
+
+ public void setTextColor(ColorStateList color) {
+ mSmallLabel.setTextColor(color);
+ mLargeLabel.setTextColor(color);
+ }
+
+ public void setItemBackground(int background) {
+ Drawable backgroundDrawable = background == 0
+ ? null : ContextCompat.getDrawable(getContext(), background);
+ ViewCompat.setBackground(this, backgroundDrawable);
+ }
+}
diff --git a/design/src/android/support/design/internal/BottomNavigationMenu.java b/design/src/android/support/design/internal/BottomNavigationMenu.java
new file mode 100644
index 0000000..d813ea2
--- /dev/null
+++ b/design/src/android/support/design/internal/BottomNavigationMenu.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.support.v7.view.menu.MenuBuilder;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+/**
+ * @hide
+ */
+public final class BottomNavigationMenu extends MenuBuilder {
+ public static final int MAX_ITEM_COUNT = 5;
+
+ public BottomNavigationMenu(Context context) {
+ super(context);
+ }
+
+ @Override
+ public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) {
+ throw new UnsupportedOperationException("BottomNavigationView does not support submenus");
+ }
+
+ @Override
+ protected MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
+ if (size() + 1 > MAX_ITEM_COUNT) {
+ throw new IllegalArgumentException(
+ "Maximum number of items supported by BottomNavigationView is " + MAX_ITEM_COUNT
+ + ". Limit can be checked with BottomNavigationView#getMaxItemCount()");
+ }
+ return super.addInternal(group, id, categoryOrder, title);
+ }
+}
diff --git a/design/src/android/support/design/internal/BottomNavigationMenuView.java b/design/src/android/support/design/internal/BottomNavigationMenuView.java
new file mode 100644
index 0000000..ec1b542
--- /dev/null
+++ b/design/src/android/support/design/internal/BottomNavigationMenuView.java
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.design.R;
+import android.support.v4.util.Pools;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuView;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * @hide
+ */
+public class BottomNavigationMenuView extends ViewGroup implements MenuView {
+
+ private final int mInactiveItemMaxWidth;
+ private final int mInactiveItemMinWidth;
+ private final int mActiveItemMaxWidth;
+ private final int mItemHeight;
+ private final OnClickListener mOnClickListener;
+ private final BottomNavigationAnimationHelperBase mAnimationHelper;
+ private static final Pools.Pool<BottomNavigationItemView> sItemPool =
+ new Pools.SynchronizedPool<>(5);
+
+ private boolean mShiftingMode = true;
+
+ private BottomNavigationItemView[] mButtons;
+ private int mActiveButton = 0;
+ private ColorStateList mItemIconTint;
+ private ColorStateList mItemTextColor;
+ private int mItemBackgroundRes;
+
+ private BottomNavigationPresenter mPresenter;
+ private MenuBuilder mMenu;
+
+ public BottomNavigationMenuView(Context context) {
+ this(context, null);
+ }
+
+ public BottomNavigationMenuView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final Resources res = getResources();
+ mInactiveItemMaxWidth = res.getDimensionPixelSize(
+ R.dimen.design_bottom_navigation_item_max_width);
+ mInactiveItemMinWidth = res.getDimensionPixelSize(
+ R.dimen.design_bottom_navigation_item_min_width);
+ mActiveItemMaxWidth = res.getDimensionPixelSize(
+ R.dimen.design_bottom_navigation_active_item_max_width);
+ mItemHeight = res.getDimensionPixelSize(R.dimen.design_bottom_navigation_height);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ mAnimationHelper = new BottomNavigationAnimationHelperIcs();
+ } else {
+ mAnimationHelper = new BottomNavigationAnimationHelperBase();
+ }
+
+ mOnClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final BottomNavigationItemView itemView = (BottomNavigationItemView) v;
+ final int itemPosition = itemView.getItemPosition();
+ activateNewButton(itemPosition);
+ mMenu.performItemAction(itemView.getItemData(), mPresenter, 0);
+ }
+ };
+ }
+
+ @Override
+ public void initialize(MenuBuilder menu) {
+ mMenu = menu;
+ if (mMenu == null) return;
+ if (mMenu.size() > mActiveButton) {
+ mMenu.getItem(mActiveButton).setChecked(true);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ final int count = getChildCount();
+
+ final int childState = 0;
+ final int heightSpec = MeasureSpec.makeMeasureSpec(mItemHeight, MeasureSpec.EXACTLY);
+
+ final int[] childWidths = new int[count];
+ if (mShiftingMode) {
+ final int inactiveCount = count - 1;
+ final int activeMaxAvailable = width - inactiveCount * mInactiveItemMinWidth;
+ final int activeWidth = Math.min(activeMaxAvailable, mActiveItemMaxWidth);
+ final int inactiveMaxAvailable = (width - activeWidth) / inactiveCount;
+ final int inactiveWidth = Math.min(inactiveMaxAvailable, mInactiveItemMaxWidth);
+ int extra = width - activeWidth - inactiveWidth * inactiveCount;
+ for (int i = 0; i < count; i++) {
+ childWidths[i] = (i == mActiveButton) ? activeWidth : inactiveWidth;
+ if (extra > 0) {
+ childWidths[i]++;
+ extra--;
+ }
+ }
+ } else {
+ final int maxAvailable = width / count;
+ final int childWidth = Math.min(maxAvailable, mActiveItemMaxWidth);
+ int extra = width - childWidth * count;
+ for (int i = 0; i < count; i++) {
+ childWidths[i] = childWidth;
+ if (extra > 0) {
+ childWidths[i]++;
+ extra--;
+ }
+ }
+ }
+
+ int totalWidth = 0;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+ child.measure(MeasureSpec.makeMeasureSpec(childWidths[i], MeasureSpec.EXACTLY),
+ heightSpec);
+ ViewGroup.LayoutParams params = child.getLayoutParams();
+ params.width = child.getMeasuredWidth();
+ totalWidth += child.getMeasuredWidth();
+ }
+ setMeasuredDimension(
+ ViewCompat.resolveSizeAndState(totalWidth,
+ MeasureSpec.makeMeasureSpec(totalWidth, MeasureSpec.EXACTLY), childState),
+ ViewCompat.resolveSizeAndState(mItemHeight, heightSpec,
+ childState << MEASURED_HEIGHT_STATE_SHIFT));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final int count = getChildCount();
+ final int width = right - left;
+ final int height = bottom - top;
+ int used = 0;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+ if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
+ child.layout(width - used - child.getMeasuredWidth(), 0, width - used, height);
+ } else {
+ child.layout(used, 0, child.getMeasuredWidth() + used, height);
+ }
+ used += child.getMeasuredWidth();
+ }
+ }
+
+ @Override
+ public int getWindowAnimations() {
+ return 0;
+ }
+
+ public void setIconTintList(ColorStateList color) {
+ mItemIconTint = color;
+ if (mButtons == null) return;
+ for (BottomNavigationItemView item : mButtons) {
+ item.setIconTintList(color);
+ }
+ }
+
+ @Nullable
+ public ColorStateList getIconTintList() {
+ return mItemIconTint;
+ }
+
+ public void setItemTextColor(ColorStateList color) {
+ mItemTextColor = color;
+ if (mButtons == null) return;
+ for (BottomNavigationItemView item : mButtons) {
+ item.setTextColor(color);
+ }
+ }
+
+ public ColorStateList getItemTextColor() {
+ return mItemTextColor;
+ }
+
+ public void setItemBackgroundRes(int background) {
+ mItemBackgroundRes = background;
+ if (mButtons == null) return;
+ for (BottomNavigationItemView item : mButtons) {
+ item.setItemBackground(background);
+ }
+ }
+
+ public int getItemBackgroundRes() {
+ return mItemBackgroundRes;
+ }
+
+ public void setPresenter(BottomNavigationPresenter presenter) {
+ mPresenter = presenter;
+ }
+
+ public void buildMenuView() {
+ if (mButtons != null) {
+ for (BottomNavigationItemView item : mButtons) {
+ sItemPool.release(item);
+ }
+ }
+ removeAllViews();
+ mButtons = new BottomNavigationItemView[mMenu.size()];
+ mShiftingMode = mMenu.size() > 3;
+ for (int i = 0; i < mMenu.size(); i++) {
+ mPresenter.setUpdateSuspended(true);
+ mMenu.getItem(i).setCheckable(true);
+ mPresenter.setUpdateSuspended(false);
+ BottomNavigationItemView child = getNewItem();
+ mButtons[i] = child;
+ child.setIconTintList(mItemIconTint);
+ child.setTextColor(mItemTextColor);
+ child.setItemBackground(mItemBackgroundRes);
+ child.setShiftingMode(mShiftingMode);
+ child.initialize((MenuItemImpl) mMenu.getItem(i), 0);
+ child.setItemPosition(i);
+ child.setOnClickListener(mOnClickListener);
+ addView(child);
+ }
+ }
+
+ public void updateMenuView() {
+ final int menuSize = mMenu.size();
+ if (menuSize != mButtons.length) {
+ // The size has changed. Rebuild menu view from scratch.
+ buildMenuView();
+ return;
+ }
+ for (int i = 0; i < menuSize; i++) {
+ mPresenter.setUpdateSuspended(true);
+ mButtons[i].initialize((MenuItemImpl) mMenu.getItem(i), 0);
+ mPresenter.setUpdateSuspended(false);
+ }
+ }
+
+ private void activateNewButton(int newButton) {
+ if (mActiveButton == newButton) return;
+
+ mAnimationHelper.beginDelayedTransition(this);
+
+ mPresenter.setUpdateSuspended(true);
+ mButtons[mActiveButton].setChecked(false);
+ mButtons[newButton].setChecked(true);
+ mPresenter.setUpdateSuspended(false);
+
+ mActiveButton = newButton;
+ }
+
+ private BottomNavigationItemView getNewItem() {
+ BottomNavigationItemView item = sItemPool.acquire();
+ if (item == null) {
+ item = new BottomNavigationItemView(getContext());
+ }
+ return item;
+ }
+}
diff --git a/design/src/android/support/design/internal/BottomNavigationPresenter.java b/design/src/android/support/design/internal/BottomNavigationPresenter.java
new file mode 100644
index 0000000..8dc0549
--- /dev/null
+++ b/design/src/android/support/design/internal/BottomNavigationPresenter.java
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuPresenter;
+import android.support.v7.view.menu.MenuView;
+import android.support.v7.view.menu.SubMenuBuilder;
+import android.view.ViewGroup;
+
+/**
+ * @hide
+ */
+public class BottomNavigationPresenter implements MenuPresenter {
+ private MenuBuilder mMenu;
+ private BottomNavigationMenuView mMenuView;
+ private boolean mUpdateSuspended = false;
+
+ public void setBottomNavigationMenuView(BottomNavigationMenuView menuView) {
+ mMenuView = menuView;
+ }
+
+ @Override
+ public void initForMenu(Context context, MenuBuilder menu) {
+ mMenuView.initialize(mMenu);
+ mMenu = menu;
+ }
+
+ @Override
+ public MenuView getMenuView(ViewGroup root) {
+ return mMenuView;
+ }
+
+ @Override
+ public void updateMenuView(boolean cleared) {
+ if (mUpdateSuspended) return;
+ if (cleared) {
+ mMenuView.buildMenuView();
+ } else {
+ mMenuView.updateMenuView();
+ }
+ }
+
+ @Override
+ public void setCallback(Callback cb) {}
+
+ @Override
+ public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+ return false;
+ }
+
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {}
+
+ @Override
+ public boolean flagActionItems() {
+ return false;
+ }
+
+ @Override
+ public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ return false;
+ }
+
+ @Override
+ public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ return false;
+ }
+
+ @Override
+ public int getId() {
+ return -1;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ return null;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {}
+
+ public void setUpdateSuspended(boolean updateSuspended) {
+ mUpdateSuspended = updateSuspended;
+ }
+}
diff --git a/design/src/android/support/design/internal/NavigationMenuItemView.java b/design/src/android/support/design/internal/NavigationMenuItemView.java
index d1e6027..7b763ea 100644
--- a/design/src/android/support/design/internal/NavigationMenuItemView.java
+++ b/design/src/android/support/design/internal/NavigationMenuItemView.java
@@ -51,7 +51,7 @@
private boolean mNeedsEmptyIcon;
- private boolean mCheckable;
+ boolean mCheckable;
private final CheckedTextView mTextView;
@@ -103,7 +103,7 @@
setVisibility(itemData.isVisible() ? VISIBLE : GONE);
if (getBackground() == null) {
- setBackgroundDrawable(createDefaultBackground());
+ ViewCompat.setBackground(this, createDefaultBackground());
}
setCheckable(itemData.isCheckable());
@@ -250,8 +250,8 @@
}
}
- public void setTextAppearance(Context context, int textAppearance) {
- mTextView.setTextAppearance(context, textAppearance);
+ public void setTextAppearance(int textAppearance) {
+ TextViewCompat.setTextAppearance(mTextView, textAppearance);
}
public void setTextColor(ColorStateList colors) {
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index de2a7c5..c6f887e 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -55,20 +55,20 @@
private static final String STATE_ADAPTER = "android:menu:adapter";
private NavigationMenuView mMenuView;
- private LinearLayout mHeaderLayout;
+ LinearLayout mHeaderLayout;
private Callback mCallback;
- private MenuBuilder mMenu;
+ MenuBuilder mMenu;
private int mId;
- private NavigationMenuAdapter mAdapter;
- private LayoutInflater mLayoutInflater;
+ NavigationMenuAdapter mAdapter;
+ LayoutInflater mLayoutInflater;
- private int mTextAppearance;
- private boolean mTextAppearanceSet;
- private ColorStateList mTextColor;
- private ColorStateList mIconTintList;
- private Drawable mItemBackground;
+ int mTextAppearance;
+ boolean mTextAppearanceSet;
+ ColorStateList mTextColor;
+ ColorStateList mIconTintList;
+ Drawable mItemBackground;
/**
* Padding to be inserted at the top of the list to avoid the first menu item
@@ -79,7 +79,7 @@
/**
* Padding for separators between items
*/
- private int mPaddingSeparator;
+ int mPaddingSeparator;
@Override
public void initForMenu(Context context, MenuBuilder menu) {
@@ -318,7 +318,7 @@
/**
* Handles click events for the menu items. The items has to be {@link NavigationMenuItemView}.
*/
- private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ final View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -403,12 +403,12 @@
NavigationMenuItemView itemView = (NavigationMenuItemView) holder.itemView;
itemView.setIconTintList(mIconTintList);
if (mTextAppearanceSet) {
- itemView.setTextAppearance(itemView.getContext(), mTextAppearance);
+ itemView.setTextAppearance(mTextAppearance);
}
if (mTextColor != null) {
itemView.setTextColor(mTextColor);
}
- itemView.setBackgroundDrawable(mItemBackground != null ?
+ ViewCompat.setBackground(itemView, mItemBackground != null ?
mItemBackground.getConstantState().newDrawable() : null);
NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
itemView.setNeedsEmptyIcon(item.needsEmptyIcon);
@@ -612,7 +612,7 @@
boolean needsEmptyIcon;
- private NavigationMenuTextItem(MenuItemImpl item) {
+ NavigationMenuTextItem(MenuItemImpl item) {
mMenuItem = item;
}
@@ -650,6 +650,8 @@
* Header (not subheader) items.
*/
private static class NavigationMenuHeaderItem implements NavigationMenuItem {
+ NavigationMenuHeaderItem() {
+ }
// The actual content is hold by NavigationMenuPresenter#mHeaderLayout.
}
diff --git a/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java b/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java
index 80aee76..34d3a79 100644
--- a/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java
+++ b/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java
@@ -34,9 +34,9 @@
*/
public class ScrimInsetsFrameLayout extends FrameLayout {
- private Drawable mInsetForeground;
+ Drawable mInsetForeground;
- private Rect mInsets;
+ Rect mInsets;
private Rect mTempRect = new Rect();
diff --git a/design/src/android/support/design/widget/AppBarLayout.java b/design/src/android/support/design/widget/AppBarLayout.java
index c253029..9aadd86 100644
--- a/design/src/android/support/design/widget/AppBarLayout.java
+++ b/design/src/android/support/design/widget/AppBarLayout.java
@@ -103,10 +103,10 @@
@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
public class AppBarLayout extends LinearLayout {
- private static final int PENDING_ACTION_NONE = 0x0;
- private static final int PENDING_ACTION_EXPANDED = 0x1;
- private static final int PENDING_ACTION_COLLAPSED = 0x2;
- private static final int PENDING_ACTION_ANIMATE_ENABLED = 0x4;
+ static final int PENDING_ACTION_NONE = 0x0;
+ static final int PENDING_ACTION_EXPANDED = 0x1;
+ static final int PENDING_ACTION_COLLAPSED = 0x2;
+ static final int PENDING_ACTION_ANIMATE_ENABLED = 0x4;
/**
* Interface definition for a callback to be invoked when an {@link AppBarLayout}'s vertical
@@ -166,7 +166,7 @@
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
0, R.style.Widget_Design_AppBarLayout);
- setBackgroundDrawable(a.getDrawable(R.styleable.AppBarLayout_android_background));
+ ViewCompat.setBackground(this, a.getDrawable(R.styleable.AppBarLayout_android_background));
if (a.hasValue(R.styleable.AppBarLayout_expanded)) {
setExpanded(a.getBoolean(R.styleable.AppBarLayout_expanded, false));
}
@@ -325,7 +325,7 @@
return new LayoutParams(p);
}
- private boolean hasChildWithInterpolator() {
+ boolean hasChildWithInterpolator() {
return mHaveChildWithInterpolator;
}
@@ -366,21 +366,21 @@
return mTotalScrollRange = Math.max(0, range - getTopInset());
}
- private boolean hasScrollableChildren() {
+ boolean hasScrollableChildren() {
return getTotalScrollRange() != 0;
}
/**
* Return the scroll range when scrolling up from a nested pre-scroll.
*/
- private int getUpNestedPreScrollRange() {
+ int getUpNestedPreScrollRange() {
return getTotalScrollRange();
}
/**
* Return the scroll range when scrolling down from a nested pre-scroll.
*/
- private int getDownNestedPreScrollRange() {
+ int getDownNestedPreScrollRange() {
if (mDownPreScrollRange != INVALID_SCROLL_RANGE) {
// If we already have a valid value, return it
return mDownPreScrollRange;
@@ -419,7 +419,7 @@
/**
* Return the scroll range when scrolling down from a nested scroll.
*/
- private int getDownNestedScrollRange() {
+ int getDownNestedScrollRange() {
if (mDownScrollRange != INVALID_SCROLL_RANGE) {
// If we already have a valid value, return it
return mDownScrollRange;
@@ -454,7 +454,7 @@
return mDownScrollRange = Math.max(0, range);
}
- private void dispatchOffsetUpdates(int offset) {
+ void dispatchOffsetUpdates(int offset) {
// Iterate backwards through the list so that most recently added listeners
// get the first chance to decide
if (mListeners != null) {
@@ -519,7 +519,7 @@
*
* @return true if the collapsed state changed
*/
- private boolean setCollapsedState(boolean collapsed) {
+ boolean setCollapsedState(boolean collapsed) {
if (mCollapsed != collapsed) {
mCollapsed = collapsed;
refreshDrawableState();
@@ -553,11 +553,11 @@
return 0;
}
- private int getPendingAction() {
+ int getPendingAction() {
return mPendingAction;
}
- private void resetPendingAction() {
+ void resetPendingAction() {
mPendingAction = PENDING_ACTION_NONE;
}
@@ -566,7 +566,7 @@
return mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
}
- private WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
+ WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
WindowInsetsCompat newInsets = null;
if (ViewCompat.getFitsSystemWindows(this)) {
@@ -742,7 +742,7 @@
/**
* Returns true if the scroll flags are compatible for 'collapsing'
*/
- private boolean isCollapsible() {
+ boolean isCollapsible() {
return (mScrollFlags & SCROLL_FLAG_SCROLL) == SCROLL_FLAG_SCROLL
&& (mScrollFlags & COLLAPSIBLE_FLAGS) != 0;
}
diff --git a/design/src/android/support/design/widget/BottomNavigationView.java b/design/src/android/support/design/widget/BottomNavigationView.java
new file mode 100644
index 0000000..476889f
--- /dev/null
+++ b/design/src/android/support/design/widget/BottomNavigationView.java
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.design.R;
+import android.support.design.internal.BottomNavigationMenu;
+import android.support.design.internal.BottomNavigationMenuView;
+import android.support.design.internal.BottomNavigationPresenter;
+import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.widget.TintTypedArray;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+/**
+ * <p>
+ * Represents a standard bottom navigation bar for application. It is an implementation of
+ * <a href="https://material.google.com/components/bottom-navigation.html">material design bottom
+ * navigation</a>.
+ * </p>
+ *
+ * <p>
+ * Bottom navigation bars make it easy for users to explore and switch between top-level views in
+ * a single tap. It should be used when application has three to five top-level destinations.
+ * </p>
+ *
+ * <p>
+ * The bar contents can be populated by specifying a menu resource file. Each menu item title, icon
+ * and enabled state will be used for displaying bottom navigation bar items.
+ * </p>
+ *
+ * <pre>
+ * <android.support.design.widget.BottomNavigationView
+ * xmlns:android="http://schemas.android.com/apk/res/android"
+ * xmlns:design="http://schema.android.com/apk/res/android.support.design"
+ * android:id="@+id/navigation"
+ * android:layout_width="wrap_content"
+ * android:layout_height="match_parent"
+ * android:layout_gravity="start"
+ * design:menu="@menu/my_navigation_items" />
+ * </pre>
+ */
+public class BottomNavigationView extends FrameLayout {
+
+ private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
+ private static final int[] DISABLED_STATE_SET = {-android.R.attr.state_enabled};
+
+ private final MenuBuilder mMenu;
+ private final BottomNavigationMenuView mMenuView;
+ private final BottomNavigationPresenter mPresenter = new BottomNavigationPresenter();
+ private MenuInflater mMenuInflater;
+
+ private OnNavigationItemSelectedListener mListener;
+
+ public BottomNavigationView(Context context) {
+ this(context, null);
+ }
+
+ public BottomNavigationView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ ThemeUtils.checkAppCompatTheme(context);
+
+ // Create the menu
+ mMenu = new BottomNavigationMenu(context);
+
+ mMenuView = new BottomNavigationMenuView(context);
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ params.gravity = Gravity.CENTER;
+ mMenuView.setLayoutParams(params);
+
+ mPresenter.setBottomNavigationMenuView(mMenuView);
+ mMenuView.setPresenter(mPresenter);
+ mMenu.addMenuPresenter(mPresenter);
+
+
+ // Custom attributes
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
+ R.styleable.BottomNavigationView, defStyleAttr,
+ R.style.Widget_Design_BottomNavigationView);
+
+ if (a.hasValue(R.styleable.BottomNavigationView_itemIconTint)) {
+ mMenuView.setIconTintList(
+ a.getColorStateList(R.styleable.BottomNavigationView_itemIconTint));
+ } else {
+ mMenuView.setIconTintList(
+ createDefaultColorStateList(android.R.attr.textColorSecondary));
+ }
+ if (a.hasValue(R.styleable.BottomNavigationView_itemTextColor)) {
+ mMenuView.setItemTextColor(
+ a.getColorStateList(R.styleable.BottomNavigationView_itemTextColor));
+ } else {
+ mMenuView.setItemTextColor(
+ createDefaultColorStateList(android.R.attr.textColorSecondary));
+ }
+
+ int itemBackground = a.getResourceId(R.styleable.BottomNavigationView_itemBackground, 0);
+ mMenuView.setItemBackgroundRes(itemBackground);
+
+ if (a.hasValue(R.styleable.BottomNavigationView_menu)) {
+ inflateMenu(a.getResourceId(R.styleable.BottomNavigationView_menu, 0));
+ }
+ a.recycle();
+
+ addView(mMenuView, params);
+
+ mMenu.setCallback(new MenuBuilder.Callback() {
+ @Override
+ public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+ return mListener != null && mListener.onNavigationItemSelected(item);
+ }
+
+ @Override
+ public void onMenuModeChange(MenuBuilder menu) {}
+ });
+ }
+
+ /**
+ * Set a listener that will be notified when a bottom navigation item is selected.
+ *
+ * @param listener The listener to notify
+ */
+ public void setOnNavigationItemSelectedListener(
+ @Nullable OnNavigationItemSelectedListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Returns the {@link Menu} instance associated with this bottom navigation bar.
+ */
+ @NonNull
+ public Menu getMenu() {
+ return mMenu;
+ }
+
+ /**
+ * Inflate a menu resource into this navigation view.
+ *
+ * <p>Existing items in the menu will not be modified or removed.</p>
+ *
+ * @param resId ID of a menu resource to inflate
+ */
+ public void inflateMenu(int resId) {
+ mPresenter.setUpdateSuspended(true);
+ getMenuInflater().inflate(resId, mMenu);
+ mPresenter.initForMenu(getContext(), mMenu);
+ mPresenter.setUpdateSuspended(false);
+ mPresenter.updateMenuView(true);
+ }
+
+ /**
+ * @return The maximum number of items that can be shown in BottomNavigationView.
+ */
+ public int getMaxItemCount() {
+ return BottomNavigationMenu.MAX_ITEM_COUNT;
+ }
+
+ /**
+ * Returns the tint which is applied to our menu items' icons.
+ *
+ * @see #setItemIconTintList(ColorStateList)
+ *
+ * @attr ref R.styleable#BottomNavigationView_itemIconTint
+ */
+ @Nullable
+ public ColorStateList getItemIconTintList() {
+ return mMenuView.getIconTintList();
+ }
+
+ /**
+ * Set the tint which is applied to our menu items' icons.
+ *
+ * @param tint the tint to apply.
+ *
+ * @attr ref R.styleable#BottomNavigationView_itemIconTint
+ */
+ public void setItemIconTintList(@Nullable ColorStateList tint) {
+ mMenuView.setIconTintList(tint);
+ }
+
+ /**
+ * Returns the tint which is applied to menu items' icons.
+ *
+ * @see #setItemTextColor(ColorStateList)
+ *
+ * @attr ref R.styleable#BottomNavigationView_itemTextColor
+ */
+ @Nullable
+ public ColorStateList getItemTextColor() {
+ return mMenuView.getItemTextColor();
+ }
+
+ /**
+ * Set the text color to be used on menu items.
+ *
+ * @see #getItemTextColor()
+ *
+ * @attr ref R.styleable#BottomNavigationView_itemTextColor
+ */
+ public void setItemTextColor(@Nullable ColorStateList textColor) {
+ mMenuView.setItemTextColor(textColor);
+ }
+
+ /**
+ * Returns the background resource of the menu items.
+ *
+ * @see #setItemBackgroundResource(int)
+ *
+ * @attr ref R.styleable#BottomNavigationView_itemBackground
+ */
+ @DrawableRes
+ public int getItemBackgroundResource() {
+ return mMenuView.getItemBackgroundRes();
+ }
+
+ /**
+ * Set the background of our menu items to the given resource.
+ *
+ * @param resId The identifier of the resource.
+ *
+ * @attr ref R.styleable#BottomNavigationView_itemBackground
+ */
+ public void setItemBackgroundResource(@DrawableRes int resId) {
+ mMenuView.setItemBackgroundRes(resId);
+ }
+
+ /**
+ * Listener for handling events on bottom navigation items.
+ */
+ public interface OnNavigationItemSelectedListener {
+
+ /**
+ * Called when an item in the bottom navigation menu is selected.
+ *
+ * @param item The selected item
+ *
+ * @return true to display the item as the selected item
+ */
+ boolean onNavigationItemSelected(@NonNull MenuItem item);
+ }
+
+ private MenuInflater getMenuInflater() {
+ if (mMenuInflater == null) {
+ mMenuInflater = new SupportMenuInflater(getContext());
+ }
+ return mMenuInflater;
+ }
+
+ private ColorStateList createDefaultColorStateList(int baseColorThemeAttr) {
+ final TypedValue value = new TypedValue();
+ if (!getContext().getTheme().resolveAttribute(baseColorThemeAttr, value, true)) {
+ return null;
+ }
+ ColorStateList baseColor = AppCompatResources.getColorStateList(
+ getContext(), value.resourceId);
+ if (!getContext().getTheme().resolveAttribute(
+ android.support.v7.appcompat.R.attr.colorPrimary, value, true)) {
+ return null;
+ }
+ int colorPrimary = value.data;
+ int defaultColor = baseColor.getDefaultColor();
+ return new ColorStateList(new int[][]{
+ DISABLED_STATE_SET,
+ CHECKED_STATE_SET,
+ EMPTY_STATE_SET
+ }, new int[]{
+ baseColor.getColorForState(DISABLED_STATE_SET, defaultColor),
+ colorPrimary,
+ defaultColor
+ });
+ }
+}
diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
index 1337352..222e0f6 100644
--- a/design/src/android/support/design/widget/BottomSheetBehavior.java
+++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
@@ -22,6 +22,7 @@
import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
import android.support.design.R;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
@@ -128,18 +129,18 @@
private int mPeekHeightMin;
- private int mMinOffset;
+ int mMinOffset;
- private int mMaxOffset;
+ int mMaxOffset;
- private boolean mHideable;
+ boolean mHideable;
private boolean mSkipCollapsed;
@State
- private int mState = STATE_COLLAPSED;
+ int mState = STATE_COLLAPSED;
- private ViewDragHelper mViewDragHelper;
+ ViewDragHelper mViewDragHelper;
private boolean mIgnoreEvents;
@@ -147,21 +148,21 @@
private boolean mNestedScrolled;
- private int mParentHeight;
+ int mParentHeight;
- private WeakReference<V> mViewRef;
+ WeakReference<V> mViewRef;
- private WeakReference<View> mNestedScrollingChildRef;
+ WeakReference<View> mNestedScrollingChildRef;
private BottomSheetCallback mCallback;
private VelocityTracker mVelocityTracker;
- private int mActivePointerId;
+ int mActivePointerId;
private int mInitialY;
- private boolean mTouchingScrollingChild;
+ boolean mTouchingScrollingChild;
/**
* Default constructor for instantiating BottomSheetBehaviors.
@@ -253,6 +254,7 @@
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
if (!child.isShown()) {
+ mIgnoreEvents = true;
return false;
}
int action = MotionEventCompat.getActionMasked(event);
@@ -560,7 +562,7 @@
return mState;
}
- private void setStateInternal(@State int state) {
+ void setStateInternal(@State int state) {
if (mState == state) {
return;
}
@@ -579,7 +581,7 @@
}
}
- private boolean shouldHide(View child, float yvel) {
+ boolean shouldHide(View child, float yvel) {
if (mSkipCollapsed) {
return true;
}
@@ -612,7 +614,7 @@
return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId);
}
- private void startSettlingAnimation(View child, int state) {
+ void startSettlingAnimation(View child, int state) {
int top;
if (state == STATE_COLLAPSED) {
top = mMaxOffset;
@@ -713,7 +715,7 @@
}
};
- private void dispatchOnSlide(int top) {
+ void dispatchOnSlide(int top) {
View bottomSheet = mViewRef.get();
if (bottomSheet != null && mCallback != null) {
if (top > mMaxOffset) {
@@ -725,6 +727,11 @@
}
}
+ @VisibleForTesting
+ int getPeekHeightMin() {
+ return mPeekHeightMin;
+ }
+
private class SettleRunnable implements Runnable {
private final View mView;
diff --git a/design/src/android/support/design/widget/BottomSheetDialog.java b/design/src/android/support/design/widget/BottomSheetDialog.java
index 0473e54..4c124f3 100644
--- a/design/src/android/support/design/widget/BottomSheetDialog.java
+++ b/design/src/android/support/design/widget/BottomSheetDialog.java
@@ -38,7 +38,7 @@
private BottomSheetBehavior<FrameLayout> mBehavior;
- private boolean mCancelable = true;
+ boolean mCancelable = true;
private boolean mCanceledOnTouchOutside = true;
private boolean mCanceledOnTouchOutsideSet;
@@ -130,7 +130,7 @@
return coordinator;
}
- private boolean shouldWindowCloseOnTouchOutside() {
+ boolean shouldWindowCloseOnTouchOutside() {
if (!mCanceledOnTouchOutsideSet) {
if (Build.VERSION.SDK_INT < 11) {
mCanceledOnTouchOutside = true;
diff --git a/design/src/android/support/design/widget/CollapsingToolbarLayout.java b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
index 6d95dec..b969af7 100644
--- a/design/src/android/support/design/widget/CollapsingToolbarLayout.java
+++ b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
@@ -114,12 +114,12 @@
private int mExpandedMarginBottom;
private final Rect mTmpRect = new Rect();
- private final CollapsingTextHelper mCollapsingTextHelper;
+ final CollapsingTextHelper mCollapsingTextHelper;
private boolean mCollapsingTitleEnabled;
private boolean mDrawCollapsingTitle;
private Drawable mContentScrim;
- private Drawable mStatusBarScrim;
+ Drawable mStatusBarScrim;
private int mScrimAlpha;
private boolean mScrimsAreShown;
private ValueAnimatorCompat mScrimAnimator;
@@ -128,9 +128,9 @@
private AppBarLayout.OnOffsetChangedListener mOnOffsetChangedListener;
- private int mCurrentOffset;
+ int mCurrentOffset;
- private WindowInsetsCompat mLastInsets;
+ WindowInsetsCompat mLastInsets;
public CollapsingToolbarLayout(Context context) {
this(context, null);
@@ -258,7 +258,7 @@
super.onDetachedFromWindow();
}
- private WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
+ WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
WindowInsetsCompat newInsets = null;
if (ViewCompat.getFitsSystemWindows(this)) {
@@ -272,7 +272,9 @@
requestLayout();
}
- return insets;
+ // Consume the insets. This is done so that child views with fitSystemWindows=true do not
+ // get the default padding functionality from View
+ return insets.consumeSystemWindowInsets();
}
@Override
@@ -490,7 +492,7 @@
return view.getHeight();
}
- private static ViewOffsetHelper getViewOffsetHelper(View view) {
+ static ViewOffsetHelper getViewOffsetHelper(View view) {
ViewOffsetHelper offsetHelper = (ViewOffsetHelper) view.getTag(R.id.view_offset_helper);
if (offsetHelper == null) {
offsetHelper = new ViewOffsetHelper(view);
@@ -609,7 +611,7 @@
mScrimAnimator.start();
}
- private void setScrimAlpha(int alpha) {
+ void setScrimAlpha(int alpha) {
if (alpha != mScrimAlpha) {
final Drawable contentScrim = mContentScrim;
if (contentScrim != null && mToolbar != null) {
@@ -1050,7 +1052,7 @@
* Returns the amount of visible height in pixels used to define when to trigger a scrim
* visibility change.
*
- * @see #setScrimTriggerOffset(int)
+ * @see #setScrimVisibleHeightTrigger(int)
*/
public int getScrimVisibleHeightTrigger() {
if (mScrimVisibleHeightTrigger >= 0) {
@@ -1241,6 +1243,9 @@
}
private class OffsetUpdateListener implements AppBarLayout.OnOffsetChangedListener {
+ OffsetUpdateListener() {
+ }
+
@Override
public void onOffsetChanged(AppBarLayout layout, int verticalOffset) {
mCurrentOffset = verticalOffset;
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index 201ed9b..dbcfabb 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -132,9 +132,9 @@
new ThreadLocal<>();
- private static final int EVENT_PRE_DRAW = 0;
- private static final int EVENT_NESTED_SCROLL = 1;
- private static final int EVENT_VIEW_REMOVED = 2;
+ static final int EVENT_PRE_DRAW = 0;
+ static final int EVENT_NESTED_SCROLL = 1;
+ static final int EVENT_VIEW_REMOVED = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -172,7 +172,7 @@
private boolean mDrawStatusBarBackground;
private Drawable mStatusBarBackground;
- private OnHierarchyChangeListener mOnHierarchyChangeListener;
+ OnHierarchyChangeListener mOnHierarchyChangeListener;
private android.support.v4.view.OnApplyWindowInsetsListener mApplyWindowInsetsListener;
private final NestedScrollingParentHelper mNestedScrollingParentHelper =
@@ -624,13 +624,7 @@
return result;
}
- private void prepareChildren(final boolean forceRefresh) {
- if (!forceRefresh && mChildDag.size() == getChildCount()
- && mChildDag.size() == mDependencySortedChildren.size()) {
- // If we're not being forced and everything looks good, lets skip the call
- return;
- }
-
+ private void prepareChildren() {
mDependencySortedChildren.clear();
mChildDag.clear();
@@ -709,7 +703,7 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- prepareChildren(true);
+ prepareChildren();
ensurePreDrawListener();
final int paddingLeft = getPaddingLeft();
@@ -1395,12 +1389,10 @@
* @param view the View to find dependents of to dispatch the call.
*/
public void dispatchDependentViewsChanged(View view) {
- prepareChildren(false);
-
final List<View> dependents = mChildDag.getIncomingEdges(view);
if (dependents != null && !dependents.isEmpty()) {
for (int i = 0; i < dependents.size(); i++) {
- final View child = (View) dependents.get(i);
+ final View child = dependents.get(i);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)
child.getLayoutParams();
CoordinatorLayout.Behavior b = lp.getBehavior();
@@ -1421,8 +1413,6 @@
*/
@NonNull
public List<View> getDependencies(@NonNull View child) {
- prepareChildren(false);
-
final List<View> dependencies = mChildDag.getOutgoingEdges(child);
mTempDependenciesList.clear();
if (dependencies != null) {
@@ -1441,8 +1431,6 @@
*/
@NonNull
public List<View> getDependents(@NonNull View child) {
- prepareChildren(false);
-
final List<View> edges = mChildDag.getIncomingEdges(child);
mTempDependenciesList.clear();
if (edges != null) {
@@ -1453,7 +1441,7 @@
@VisibleForTesting
final List<View> getDependencySortedChildren() {
- prepareChildren(true);
+ prepareChildren();
return Collections.unmodifiableList(mDependencySortedChildren);
}
@@ -1483,8 +1471,7 @@
/**
* Check if the given child has any layout dependencies on other child views.
*/
- boolean hasDependencies(View child) {
- prepareChildren(false);
+ private boolean hasDependencies(View child) {
return mChildDag.hasOutgoingEdges(child);
}
@@ -2502,8 +2489,8 @@
*/
public int dodgeInsetEdges = Gravity.NO_GRAVITY;
- private int mInsetOffsetX;
- private int mInsetOffsetY;
+ int mInsetOffsetX;
+ int mInsetOffsetY;
View mAnchorView;
View mAnchorDirectChild;
@@ -2851,6 +2838,9 @@
}
private class HierarchyChangeListener implements OnHierarchyChangeListener {
+ HierarchyChangeListener() {
+ }
+
@Override
public void onChildViewAdded(View parent, View child) {
if (mOnHierarchyChangeListener != null) {
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index 68b7c5b..eb379b9 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -130,11 +130,11 @@
private int mBorderWidth;
private int mRippleColor;
private int mSize;
- private int mImagePadding;
+ int mImagePadding;
private int mMaxImageSize;
- private boolean mCompatPadding;
- private final Rect mShadowPadding = new Rect();
+ boolean mCompatPadding;
+ final Rect mShadowPadding = new Rect();
private final Rect mTouchArea = new Rect();
private AppCompatImageHelper mImageHelper;
@@ -201,13 +201,25 @@
}
/**
- * Set the ripple color for this {@link FloatingActionButton}.
- * <p>
- * When running on devices with KitKat or below, we draw a fill rather than a ripple.
+ * Returns the ripple color for this button.
*
- * @param color ARGB color to use for the ripple.
+ * @return the ARGB color used for the ripple
+ * @see #setRippleColor(int)
+ */
+ @ColorInt
+ public int getRippleColor() {
+ return mRippleColor;
+ }
+
+ /**
+ * Sets the ripple color for this button.
*
+ * <p>When running on devices with KitKat or below, we draw this color as a filled circle
+ * rather than a ripple.</p>
+ *
+ * @param color ARGB color to use for the ripple
* @attr ref android.support.design.R.styleable#FloatingActionButton_rippleColor
+ * @see #getRippleColor()
*/
public void setRippleColor(@ColorInt int color) {
if (mRippleColor != color) {
@@ -217,7 +229,7 @@
}
/**
- * Return the tint applied to the background drawable, if specified.
+ * Returns the tint applied to the background drawable, if specified.
*
* @return the tint applied to the background drawable
* @see #setBackgroundTintList(ColorStateList)
@@ -242,7 +254,7 @@
}
/**
- * Return the blending mode used to apply the tint to the background
+ * Returns the blending mode used to apply the tint to the background
* drawable, if specified.
*
* @return the blending mode used to apply the tint to the background
@@ -309,7 +321,7 @@
show(listener, true);
}
- private void show(OnVisibilityChangedListener listener, boolean fromUser) {
+ void show(OnVisibilityChangedListener listener, boolean fromUser) {
getImpl().show(wrapOnVisibilityChangedListener(listener), fromUser);
}
@@ -331,7 +343,7 @@
hide(listener, true);
}
- private void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) {
+ void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) {
getImpl().hide(wrapOnVisibilityChangedListener(listener), fromUser);
}
@@ -414,7 +426,7 @@
};
}
- private int getSizeDimension() {
+ int getSizeDimension() {
return getSizeDimension(mSize);
}
@@ -790,6 +802,9 @@
}
private class ShadowDelegateImpl implements ShadowViewDelegate {
+ ShadowDelegateImpl() {
+ }
+
@Override
public float getRadius() {
return getSizeDimension() / 2f;
diff --git a/design/src/android/support/design/widget/HeaderBehavior.java b/design/src/android/support/design/widget/HeaderBehavior.java
index 7dd2700..5e555de 100644
--- a/design/src/android/support/design/widget/HeaderBehavior.java
+++ b/design/src/android/support/design/widget/HeaderBehavior.java
@@ -37,7 +37,7 @@
private static final int INVALID_POINTER = -1;
private Runnable mFlingRunnable;
- private ScrollerCompat mScroller;
+ ScrollerCompat mScroller;
private boolean mIsBeingDragged;
private int mActivePointerId = INVALID_POINTER;
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index e53b7e8..428b565 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -84,7 +84,7 @@
private final NavigationMenu mMenu;
private final NavigationMenuPresenter mPresenter = new NavigationMenuPresenter();
- private OnNavigationItemSelectedListener mListener;
+ OnNavigationItemSelectedListener mListener;
private int mMaxWidth;
private MenuInflater mMenuInflater;
@@ -110,8 +110,8 @@
R.styleable.NavigationView, defStyleAttr,
R.style.Widget_Design_NavigationView);
- //noinspection deprecation
- setBackgroundDrawable(a.getDrawable(R.styleable.NavigationView_android_background));
+ ViewCompat.setBackground(
+ this, a.getDrawable(R.styleable.NavigationView_android_background));
if (a.hasValue(R.styleable.NavigationView_elevation)) {
ViewCompat.setElevation(this, a.getDimensionPixelSize(
R.styleable.NavigationView_elevation, 0));
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index bc5df7f..2c87529 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -154,9 +154,9 @@
static final int ANIMATION_DURATION = 250;
static final int ANIMATION_FADE_DURATION = 180;
- private static final Handler sHandler;
- private static final int MSG_SHOW = 0;
- private static final int MSG_DISMISS = 1;
+ static final Handler sHandler;
+ static final int MSG_SHOW = 0;
+ static final int MSG_DISMISS = 1;
static {
sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
@@ -177,7 +177,7 @@
private final ViewGroup mTargetParent;
private final Context mContext;
- private final SnackbarLayout mView;
+ final SnackbarLayout mView;
private int mDuration;
private Callback mCallback;
@@ -401,7 +401,7 @@
dispatchDismiss(Callback.DISMISS_EVENT_MANUAL);
}
- private void dispatchDismiss(@Callback.DismissEvent int event) {
+ void dispatchDismiss(@Callback.DismissEvent int event) {
SnackbarManager.getInstance().dismiss(mManagerCallback, event);
}
@@ -429,7 +429,7 @@
return SnackbarManager.getInstance().isCurrentOrNext(mManagerCallback);
}
- private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
+ final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
@Override
public void show() {
sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, Snackbar.this));
@@ -531,7 +531,7 @@
}
}
- private void animateViewIn() {
+ void animateViewIn() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
ViewCompat.setTranslationY(mView, mView.getHeight());
ViewCompat.animate(mView)
@@ -618,14 +618,14 @@
}
}
- private void onViewShown() {
+ void onViewShown() {
SnackbarManager.getInstance().onShown(mManagerCallback);
if (mCallback != null) {
mCallback.onShown(this);
}
}
- private void onViewHidden(int event) {
+ void onViewHidden(int event) {
// First tell the SnackbarManager that it has been dismissed
SnackbarManager.getInstance().onDismissed(mManagerCallback);
// Now call the dismiss listener (if available)
@@ -650,7 +650,7 @@
/**
* Returns true if we should animate the Snackbar view in/out.
*/
- private boolean shouldAnimate() {
+ boolean shouldAnimate() {
return !mAccessibilityManager.isEnabled();
}
diff --git a/design/src/android/support/design/widget/SnackbarManager.java b/design/src/android/support/design/widget/SnackbarManager.java
index e0c3922..b391a3a 100644
--- a/design/src/android/support/design/widget/SnackbarManager.java
+++ b/design/src/android/support/design/widget/SnackbarManager.java
@@ -27,7 +27,7 @@
*/
class SnackbarManager {
- private static final int MSG_TIMEOUT = 0;
+ static final int MSG_TIMEOUT = 0;
private static final int SHORT_DURATION_MS = 1500;
private static final int LONG_DURATION_MS = 2750;
@@ -166,8 +166,8 @@
}
private static class SnackbarRecord {
- private final WeakReference<Callback> callback;
- private int duration;
+ final WeakReference<Callback> callback;
+ int duration;
SnackbarRecord(int duration, Callback callback) {
this.callback = new WeakReference<>(callback);
@@ -229,7 +229,7 @@
mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_TIMEOUT, r), durationMs);
}
- private void handleTimeout(SnackbarRecord record) {
+ void handleTimeout(SnackbarRecord record) {
synchronized (mLock) {
if (mCurrentSnackbar == record || mNextSnackbar == record) {
cancelSnackbarLocked(record, Snackbar.Callback.DISMISS_EVENT_TIMEOUT);
diff --git a/design/src/android/support/design/widget/SwipeDismissBehavior.java b/design/src/android/support/design/widget/SwipeDismissBehavior.java
index ae1ef86..c2e02cd 100644
--- a/design/src/android/support/design/widget/SwipeDismissBehavior.java
+++ b/design/src/android/support/design/widget/SwipeDismissBehavior.java
@@ -78,17 +78,17 @@
private static final float DEFAULT_ALPHA_START_DISTANCE = 0f;
private static final float DEFAULT_ALPHA_END_DISTANCE = DEFAULT_DRAG_DISMISS_THRESHOLD;
- private ViewDragHelper mViewDragHelper;
- private OnDismissListener mListener;
+ ViewDragHelper mViewDragHelper;
+ OnDismissListener mListener;
private boolean mInterceptingEvents;
private float mSensitivity = 0f;
private boolean mSensitivitySet;
- private int mSwipeDirection = SWIPE_DIRECTION_ANY;
- private float mDragDismissThreshold = DEFAULT_DRAG_DISMISS_THRESHOLD;
- private float mAlphaStartSwipeDistance = DEFAULT_ALPHA_START_DISTANCE;
- private float mAlphaEndSwipeDistance = DEFAULT_ALPHA_END_DISTANCE;
+ int mSwipeDirection = SWIPE_DIRECTION_ANY;
+ float mDragDismissThreshold = DEFAULT_DRAG_DISMISS_THRESHOLD;
+ float mAlphaStartSwipeDistance = DEFAULT_ALPHA_START_DISTANCE;
+ float mAlphaEndSwipeDistance = DEFAULT_ALPHA_END_DISTANCE;
/**
* Callback interface used to notify the application that the view has been dismissed.
@@ -381,11 +381,11 @@
}
}
- private static float clamp(float min, float value, float max) {
+ static float clamp(float min, float value, float max) {
return Math.min(Math.max(min, value), max);
}
- private static int clamp(int min, int value, int max) {
+ static int clamp(int min, int value, int max) {
return Math.min(Math.max(min, value), max);
}
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 01ca835..4b8ccf8 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -53,6 +53,7 @@
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
+import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
@@ -144,12 +145,12 @@
public class TabLayout extends HorizontalScrollView {
private static final int DEFAULT_HEIGHT_WITH_TEXT_ICON = 72; // dps
- private static final int DEFAULT_GAP_TEXT_ICON = 8; // dps
+ static final int DEFAULT_GAP_TEXT_ICON = 8; // dps
private static final int INVALID_WIDTH = -1;
private static final int DEFAULT_HEIGHT = 48; // dps
private static final int TAB_MIN_WIDTH_MARGIN = 56; //dps
- private static final int FIXED_WRAP_GUTTER_MIN = 16; //dps
- private static final int MOTION_NON_ADJACENT_OFFSET = 24;
+ static final int FIXED_WRAP_GUTTER_MIN = 16; //dps
+ static final int MOTION_NON_ADJACENT_OFFSET = 24;
private static final int ANIMATION_DURATION = 300;
@@ -239,27 +240,27 @@
private final SlidingTabStrip mTabStrip;
- private int mTabPaddingStart;
- private int mTabPaddingTop;
- private int mTabPaddingEnd;
- private int mTabPaddingBottom;
+ int mTabPaddingStart;
+ int mTabPaddingTop;
+ int mTabPaddingEnd;
+ int mTabPaddingBottom;
- private int mTabTextAppearance;
- private ColorStateList mTabTextColors;
- private float mTabTextSize;
- private float mTabTextMultiLineSize;
+ int mTabTextAppearance;
+ ColorStateList mTabTextColors;
+ float mTabTextSize;
+ float mTabTextMultiLineSize;
- private final int mTabBackgroundResId;
+ final int mTabBackgroundResId;
- private int mTabMaxWidth = Integer.MAX_VALUE;
+ int mTabMaxWidth = Integer.MAX_VALUE;
private final int mRequestedTabMinWidth;
private final int mRequestedTabMaxWidth;
private final int mScrollableTabMinWidth;
private int mContentInsetStart;
- private int mTabGravity;
- private int mMode;
+ int mTabGravity;
+ int mMode;
private OnTabSelectedListener mSelectedListener;
private final ArrayList<OnTabSelectedListener> mSelectedListeners = new ArrayList<>();
@@ -267,7 +268,7 @@
private ValueAnimatorCompat mScrollAnimator;
- private ViewPager mViewPager;
+ ViewPager mViewPager;
private PagerAdapter mPagerAdapter;
private DataSetObserver mPagerAdapterObserver;
private TabLayoutOnPageChangeListener mPageChangeListener;
@@ -399,7 +400,7 @@
setScrollPosition(position, positionOffset, updateSelectedText, true);
}
- private void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
+ void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
boolean updateIndicatorPosition) {
final int roundedPosition = Math.round(position + positionOffset);
if (roundedPosition < 0 || roundedPosition >= mTabStrip.getChildCount()) {
@@ -874,7 +875,7 @@
- getPaddingRight());
}
- private void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
+ void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
if (mPagerAdapter != null && mPagerAdapterObserver != null) {
// If we already have a PagerAdapter, unregister our observer
mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
@@ -894,7 +895,7 @@
populateFromPagerAdapter();
}
- private void populateFromPagerAdapter() {
+ void populateFromPagerAdapter() {
removeAllTabs();
if (mPagerAdapter != null) {
@@ -990,7 +991,7 @@
}
}
- private int dpToPx(int dps) {
+ int dpToPx(int dps) {
return Math.round(getResources().getDisplayMetrics().density * dps);
}
@@ -1199,7 +1200,7 @@
updateTabViews(true);
}
- private void updateTabViews(final boolean requestLayout) {
+ void updateTabViews(final boolean requestLayout) {
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
View child = mTabStrip.getChildAt(i);
child.setMinimumWidth(getTabMinWidth());
@@ -1229,10 +1230,10 @@
private int mPosition = INVALID_POSITION;
private View mCustomView;
- private TabLayout mParent;
- private TabView mView;
+ TabLayout mParent;
+ TabView mView;
- private Tab() {
+ Tab() {
// Private constructor
}
@@ -1462,13 +1463,13 @@
return mContentDesc;
}
- private void updateView() {
+ void updateView() {
if (mView != null) {
mView.update();
}
}
- private void reset() {
+ void reset() {
mParent = null;
mView = null;
mTag = null;
@@ -1494,7 +1495,8 @@
public TabView(Context context) {
super(context);
if (mTabBackgroundResId != 0) {
- setBackgroundDrawable(AppCompatResources.getDrawable(context, mTabBackgroundResId));
+ ViewCompat.setBackground(
+ this, AppCompatResources.getDrawable(context, mTabBackgroundResId));
}
ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,
mTabPaddingEnd, mTabPaddingBottom);
@@ -1505,13 +1507,16 @@
@Override
public boolean performClick() {
- final boolean value = super.performClick();
+ final boolean handled = super.performClick();
if (mTab != null) {
+ if (!handled) {
+ playSoundEffect(SoundEffectConstants.CLICK);
+ }
mTab.select();
return true;
} else {
- return value;
+ return handled;
}
}
@@ -1621,14 +1626,14 @@
}
}
- private void setTab(@Nullable final Tab tab) {
+ void setTab(@Nullable final Tab tab) {
if (tab != mTab) {
mTab = tab;
update();
}
}
- private void reset() {
+ void reset() {
setTab(null);
setSelected(false);
}
@@ -1683,7 +1688,7 @@
mTextView = textView;
mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
}
- mTextView.setTextAppearance(getContext(), mTabTextAppearance);
+ TextViewCompat.setTextAppearance(mTextView, mTabTextAppearance);
if (mTabTextColors != null) {
mTextView.setTextColor(mTabTextColors);
}
@@ -1798,8 +1803,8 @@
private int mSelectedIndicatorHeight;
private final Paint mSelectedIndicatorPaint;
- private int mSelectedPosition = -1;
- private float mSelectionOffset;
+ int mSelectedPosition = -1;
+ float mSelectionOffset;
private int mIndicatorLeft = -1;
private int mIndicatorRight = -1;
@@ -1947,7 +1952,7 @@
setIndicatorPosition(left, right);
}
- private void setIndicatorPosition(int left, int right) {
+ void setIndicatorPosition(int left, int right) {
if (left != mIndicatorLeft || right != mIndicatorRight) {
// If the indicator's left/right has changed, invalidate
mIndicatorLeft = left;
@@ -2084,7 +2089,7 @@
return generateDefaultLayoutParams();
}
- private int getTabMaxWidth() {
+ int getTabMaxWidth() {
return mTabMaxWidth;
}
@@ -2145,7 +2150,7 @@
}
}
- private void reset() {
+ void reset() {
mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
}
}
@@ -2178,6 +2183,9 @@
}
private class PagerAdapterObserver extends DataSetObserver {
+ PagerAdapterObserver() {
+ }
+
@Override
public void onChanged() {
populateFromPagerAdapter();
@@ -2192,6 +2200,9 @@
private class AdapterChangeListener implements ViewPager.OnAdapterChangeListener {
private boolean mAutoRefresh;
+ AdapterChangeListener() {
+ }
+
@Override
public void onAdapterChanged(@NonNull ViewPager viewPager,
@Nullable PagerAdapter oldAdapter, @Nullable PagerAdapter newAdapter) {
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 44925f7..fefbf99 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -102,7 +102,7 @@
private static final String LOG_TAG = "TextInputLayout";
private final FrameLayout mInputFrame;
- private EditText mEditText;
+ EditText mEditText;
private boolean mHintEnabled;
private CharSequence mHint;
@@ -114,12 +114,12 @@
private int mIndicatorsAdded;
private boolean mErrorEnabled;
- private TextView mErrorView;
+ TextView mErrorView;
private int mErrorTextAppearance;
private boolean mErrorShown;
private CharSequence mError;
- private boolean mCounterEnabled;
+ boolean mCounterEnabled;
private TextView mCounterView;
private int mCounterMaxLength;
private int mCounterTextAppearance;
@@ -144,7 +144,7 @@
// Only used for testing
private boolean mHintExpanded;
- private final CollapsingTextHelper mCollapsingTextHelper = new CollapsingTextHelper(this);
+ final CollapsingTextHelper mCollapsingTextHelper = new CollapsingTextHelper(this);
private boolean mHintAnimationEnabled;
private ValueAnimatorCompat mAnimator;
@@ -371,7 +371,7 @@
}
}
- private void updateLabelState(boolean animate) {
+ void updateLabelState(boolean animate) {
final boolean isEnabled = isEnabled();
final boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
final boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
@@ -560,7 +560,7 @@
mErrorView = new TextView(getContext());
boolean useDefaultColor = false;
try {
- mErrorView.setTextAppearance(getContext(), mErrorTextAppearance);
+ TextViewCompat.setTextAppearance(mErrorView, mErrorTextAppearance);
if (Build.VERSION.SDK_INT >= 23
&& mErrorView.getTextColors().getDefaultColor() == Color.MAGENTA) {
@@ -577,7 +577,7 @@
if (useDefaultColor) {
// Probably caused by our theme not extending from Theme.Design*. Instead
// we manually set something appropriate
- mErrorView.setTextAppearance(getContext(),
+ TextViewCompat.setTextAppearance(mErrorView,
android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Caption);
mErrorView.setTextColor(ContextCompat.getColor(
getContext(), R.color.design_textinput_error_color_light));
@@ -700,11 +700,11 @@
mCounterView = new TextView(getContext());
mCounterView.setMaxLines(1);
try {
- mCounterView.setTextAppearance(getContext(), mCounterTextAppearance);
+ TextViewCompat.setTextAppearance(mCounterView, mCounterTextAppearance);
} catch (Exception e) {
// Probably caused by our theme not extending from Theme.Design*. Instead
// we manually set something appropriate
- mCounterView.setTextAppearance(getContext(),
+ TextViewCompat.setTextAppearance(mCounterView,
android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Caption);
mCounterView.setTextColor(ContextCompat.getColor(
getContext(), R.color.design_textinput_error_color_light));
@@ -782,7 +782,7 @@
return mCounterMaxLength;
}
- private void updateCounter(int length) {
+ void updateCounter(int length) {
boolean wasCounterOverflowed = mCounterOverflowed;
if (mCounterMaxLength == INVALID_MAX_LENGTH) {
mCounterView.setText(String.valueOf(length));
@@ -790,7 +790,7 @@
} else {
mCounterOverflowed = length > mCounterMaxLength;
if (wasCounterOverflowed != mCounterOverflowed) {
- mCounterView.setTextAppearance(getContext(), mCounterOverflowed ?
+ TextViewCompat.setTextAppearance(mCounterView, mCounterOverflowed ?
mCounterOverflowTextAppearance : mCounterTextAppearance);
}
mCounterView.setText(getContext().getString(R.string.character_counter_pattern,
@@ -867,7 +867,7 @@
// as the background. This has the unfortunate side-effect of wiping out any
// user set padding, but I'd hope that use of custom padding on an EditText
// is limited.
- mEditText.setBackgroundDrawable(newBg);
+ ViewCompat.setBackground(mErrorView, newBg);
mHasReconstructedEditTextBackground = true;
}
}
@@ -1193,7 +1193,7 @@
applyPasswordToggleTint();
}
- private void passwordVisibilityToggleRequested() {
+ void passwordVisibilityToggleRequested() {
if (mPasswordToggleEnabled) {
// Store the current cursor position
final int selection = mEditText.getSelectionEnd();
@@ -1346,6 +1346,9 @@
}
private class TextInputAccessibilityDelegate extends AccessibilityDelegateCompat {
+ TextInputAccessibilityDelegate() {
+ }
+
@Override
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(host, event);
diff --git a/design/src/android/support/design/widget/ViewGroupUtils.java b/design/src/android/support/design/widget/ViewGroupUtils.java
index a5d2f8a..bb5e1b6 100644
--- a/design/src/android/support/design/widget/ViewGroupUtils.java
+++ b/design/src/android/support/design/widget/ViewGroupUtils.java
@@ -28,6 +28,9 @@
}
private static class ViewGroupUtilsImplBase implements ViewGroupUtilsImpl {
+ ViewGroupUtilsImplBase() {
+ }
+
@Override
public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) {
parent.offsetDescendantRectToMyCoords(child, rect);
@@ -39,6 +42,9 @@
}
private static class ViewGroupUtilsImplHoneycomb implements ViewGroupUtilsImpl {
+ ViewGroupUtilsImplHoneycomb() {
+ }
+
@Override
public void offsetDescendantRect(ViewGroup parent, View child, Rect rect) {
ViewGroupUtilsHoneycomb.offsetDescendantRect(parent, child, rect);
diff --git a/design/tests/AndroidManifest.xml b/design/tests/AndroidManifest.xml
index 9582f81..9e859e6 100755
--- a/design/tests/AndroidManifest.xml
+++ b/design/tests/AndroidManifest.xml
@@ -78,6 +78,10 @@
android:name="android.support.design.widget.NavigationViewActivity"/>
<activity
+ android:theme="@style/Theme.AppCompat.NoActionBar"
+ android:name="android.support.design.widget.BottomNavigationViewActivity"/>
+
+ <activity
android:theme="@style/Theme.AppCompat.NoActionBar"
android:name="android.support.design.widget.TextInputLayoutActivity"/>
diff --git a/design/tests/res/layout/design_bottom_navigation_view.xml b/design/tests/res/layout/design_bottom_navigation_view.xml
new file mode 100644
index 0000000..0e85aad
--- /dev/null
+++ b/design/tests/res/layout/design_bottom_navigation_view.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+
+<FrameLayout
+ 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="match_parent">
+ <android.support.design.widget.BottomNavigationView
+ android:id="@+id/bottom_navigation"
+ android:layout_height="56dp"
+ android:layout_width="match_parent"
+ app:menu="@menu/bottom_navigation_view_content"
+ app:itemIconTint="@color/emerald_translucent"
+ app:itemTextColor="@color/emerald_text"
+ app:itemBackground="@color/sand_default" />
+</FrameLayout>
\ No newline at end of file
diff --git a/design/tests/res/menu/bottom_navigation_view_content.xml b/design/tests/res/menu/bottom_navigation_view_content.xml
new file mode 100644
index 0000000..6d19060
--- /dev/null
+++ b/design/tests/res/menu/bottom_navigation_view_content.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 Google Inc.
+
+ 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/destination_home"
+ android:title="@string/navigate_home"
+ android:icon="@drawable/test_drawable_red" />
+ <item android:id="@+id/destination_profile"
+ android:title="@string/navigate_profile"
+ android:icon="@drawable/test_drawable_green" />
+ <item android:id="@+id/destination_people"
+ android:title="@string/navigate_people"
+ android:icon="@drawable/test_drawable_blue" />
+</menu>
diff --git a/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java b/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java
new file mode 100644
index 0000000..31b527f
--- /dev/null
+++ b/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package android.support.design.testutils;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.IdRes;
+import android.support.annotation.Nullable;
+import android.support.design.widget.BottomNavigationView;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.view.View;
+
+import org.hamcrest.Matcher;
+
+
+public class BottomNavigationViewActions {
+ /**
+ * Sets item icon tint list on the content of the bottom navigation view.
+ */
+ public static ViewAction setItemIconTintList(@Nullable final ColorStateList tint) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Set item icon tint list";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ BottomNavigationView navigationView = (BottomNavigationView) view;
+ navigationView.setItemIconTintList(tint);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+
+ /**
+ * Sets icon for the menu item of the navigation view.
+ */
+ public static ViewAction setIconForMenuItem(@IdRes final int menuItemId,
+ final Drawable iconDrawable) {
+ return new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Set menu item icon";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadUntilIdle();
+
+ BottomNavigationView navigationView = (BottomNavigationView) view;
+ navigationView.getMenu().findItem(menuItemId).setIcon(iconDrawable);
+
+ uiController.loopMainThreadUntilIdle();
+ }
+ };
+ }
+}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
index 4199fa9..d04a510 100644
--- a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
+++ b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
@@ -308,6 +308,13 @@
final ImageView parallaxImageView =
(ImageView) mCoordinatorLayout.findViewById(R.id.app_bar_image);
+ // We have not set any padding on the ImageView, so ensure that none is set via
+ // window insets handling
+ assertEquals(0, parallaxImageView.getPaddingLeft());
+ assertEquals(0, parallaxImageView.getPaddingTop());
+ assertEquals(0, parallaxImageView.getPaddingRight());
+ assertEquals(0, parallaxImageView.getPaddingBottom());
+
CollapsingToolbarLayout.LayoutParams parallaxImageViewLp =
(CollapsingToolbarLayout.LayoutParams) parallaxImageView.getLayoutParams();
assertEquals(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PARALLAX,
diff --git a/compat/api22/android/support/v4/app/ActivityCompat22.java b/design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java
similarity index 63%
copy from compat/api22/android/support/v4/app/ActivityCompat22.java
copy to design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java
index 3946f1d..2afe695 100644
--- a/compat/api22/android/support/v4/app/ActivityCompat22.java
+++ b/design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.support.design.widget;
-package android.support.v4.app;
+import android.support.design.test.R;
-import android.app.Activity;
-import android.net.Uri;
-
-class ActivityCompat22 {
- public static Uri getReferrer(Activity activity) {
- return activity.getReferrer();
+public class BottomNavigationViewActivity extends BaseTestActivity {
+ @Override
+ protected int getContentViewLayoutResId() {
+ return R.layout.design_bottom_navigation_view;
}
}
diff --git a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
new file mode 100644
index 0000000..98851b4
--- /dev/null
+++ b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+package android.support.design.widget;
+
+import static android.support.design.testutils.BottomNavigationViewActions.setIconForMenuItem;
+import static android.support.design.testutils.BottomNavigationViewActions.setItemIconTintList;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static org.hamcrest.core.AllOf.allOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.res.Resources;
+import android.support.annotation.ColorInt;
+import android.support.design.test.R;
+import android.support.design.testutils.TestDrawable;
+import android.support.design.testutils.TestUtilsMatchers;
+import android.support.v4.content.res.ResourcesCompat;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class BottomNavigationViewTest
+ extends BaseInstrumentationTestCase<BottomNavigationViewActivity> {
+ private static final int[] MENU_CONTENT_ITEM_IDS = { R.id.destination_home,
+ R.id.destination_profile, R.id.destination_people };
+ private Map<Integer, String> mMenuStringContent;
+
+ private BottomNavigationView mBottomNavigation;
+
+ public BottomNavigationViewTest() {
+ super(BottomNavigationViewActivity.class);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ final BottomNavigationViewActivity activity = mActivityTestRule.getActivity();
+ mBottomNavigation = (BottomNavigationView) activity.findViewById(R.id.bottom_navigation);
+
+ final Resources res = activity.getResources();
+ mMenuStringContent = new HashMap<>(MENU_CONTENT_ITEM_IDS.length);
+ mMenuStringContent.put(R.id.destination_home, res.getString(R.string.navigate_home));
+ mMenuStringContent.put(R.id.destination_profile, res.getString(R.string.navigate_profile));
+ mMenuStringContent.put(R.id.destination_people, res.getString(R.string.navigate_people));
+ }
+
+ @Test
+ @SmallTest
+ public void testBasics() {
+ // Check the contents of the Menu object
+ final Menu menu = mBottomNavigation.getMenu();
+ assertNotNull("Menu should not be null", menu);
+ assertEquals("Should have matching number of items", MENU_CONTENT_ITEM_IDS.length,
+ menu.size());
+ for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
+ final MenuItem currItem = menu.getItem(i);
+ assertEquals("ID for Item #" + i, MENU_CONTENT_ITEM_IDS[i], currItem.getItemId());
+ }
+
+ }
+
+ @Test
+ @SmallTest
+ public void testNavigationSelectionListener() {
+ BottomNavigationView.OnNavigationItemSelectedListener mockedListener =
+ mock(BottomNavigationView.OnNavigationItemSelectedListener.class);
+ mBottomNavigation.setOnNavigationItemSelectedListener(mockedListener);
+
+ // Click one of our items
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
+ isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
+ // And that our listener has been notified of the click
+ verify(mockedListener, times(1)).onNavigationItemSelected(
+ mBottomNavigation.getMenu().findItem(R.id.destination_profile));
+
+ // Set null listener to test that the next click is not going to notify the
+ // previously set listener
+ mBottomNavigation.setOnNavigationItemSelectedListener(null);
+
+ // Click one of our items
+ onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
+ isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
+ // And that our previous listener has not been notified of the click
+ verifyNoMoreInteractions(mockedListener);
+ }
+
+ @Test
+ @SmallTest
+ public void testIconTinting() {
+ final Resources res = mActivityTestRule.getActivity().getResources();
+ @ColorInt final int redFill = ResourcesCompat.getColor(res, R.color.test_red, null);
+ @ColorInt final int greenFill = ResourcesCompat.getColor(res, R.color.test_green, null);
+ @ColorInt final int blueFill = ResourcesCompat.getColor(res, R.color.test_blue, null);
+ final int iconSize = res.getDimensionPixelSize(R.dimen.drawable_small_size);
+ onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_home,
+ new TestDrawable(redFill, iconSize, iconSize)));
+ onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_profile,
+ new TestDrawable(greenFill, iconSize, iconSize)));
+ onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_people,
+ new TestDrawable(blueFill, iconSize, iconSize)));
+
+ @ColorInt final int defaultTintColor = ResourcesCompat.getColor(res,
+ R.color.emerald_translucent, null);
+
+ // We're allowing a margin of error in checking the color of the items' icons.
+ // This is due to the translucent color being used in the icon tinting
+ // and off-by-one discrepancies of SRC_IN when it's compositing
+ // translucent color. Note that all the checks below are written for the current
+ // logic on BottomNavigationView that uses the default SRC_IN tint mode - effectively
+ // replacing all non-transparent pixels in the destination (original icon) with
+ // our translucent tint color.
+ final int allowedComponentVariance = 1;
+
+ // Note that here we're tying ourselves to the implementation details of the internal
+ // structure of the BottomNavigationView. Specifically, we're checking the drawable the
+ // ImageView with id R.id.icon. If the internal implementation of BottomNavigationView
+ // changes, the second Matcher in the lookups below will need to be tweaked.
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
+ matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
+ matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
+ matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
+
+ @ColorInt final int newTintColor = ResourcesCompat.getColor(res,
+ R.color.red_translucent, null);
+ onView(withId(R.id.bottom_navigation)).perform(setItemIconTintList(
+ ResourcesCompat.getColorStateList(res, R.color.color_state_list_red_translucent,
+ null)));
+ // Check that all menu items with icons now have icons tinted with the newly set color
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
+ matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
+ matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
+ matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
+
+ // And now remove all icon tinting
+ onView(withId(R.id.bottom_navigation)).perform(setItemIconTintList(null));
+ // And verify that all menu items with icons now have the original colors for their icons.
+ // Note that since there is no tinting at this point, we don't allow any color variance
+ // in these checks.
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
+ matches(TestUtilsMatchers.drawable(redFill, allowedComponentVariance)));
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
+ matches(TestUtilsMatchers.drawable(greenFill, allowedComponentVariance)));
+ onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
+ matches(TestUtilsMatchers.drawable(blueFill, allowedComponentVariance)));
+ }
+}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java
index 050739b..7cfce3d 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java
@@ -24,11 +24,13 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class BottomSheetBehaviorInitialStateTest {
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
index 4c03fd6..cb91cec 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
@@ -55,6 +55,7 @@
import android.widget.TextView;
import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
import org.junit.Test;
public class BottomSheetBehaviorTest extends
@@ -183,7 +184,7 @@
@Override
public Matcher<View> getConstraints() {
- return ViewMatchers.isDisplayed();
+ return Matchers.any(View.class);
}
@Override
@@ -213,7 +214,6 @@
MotionEvents.sendCancel(uiController, downEvent);
throw new RuntimeException("Cannot drag: failed to send a move event.");
}
- BottomSheetBehavior behavior = BottomSheetBehavior.from(view);
}
int duration = ViewConfiguration.getPressedStateDuration();
if (duration > 0) {
@@ -460,6 +460,46 @@
@Test
@MediumTest
+ public void testInvisibleThenVisible() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ // The bottom sheet is initially invisible
+ getBottomSheet().setVisibility(View.INVISIBLE);
+ // Then it becomes visible when the CoL is touched
+ getCoordinatorLayout().setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent e) {
+ if (e.getAction() == MotionEvent.ACTION_DOWN) {
+ getBottomSheet().setVisibility(View.VISIBLE);
+ return true;
+ }
+ return false;
+ }
+ });
+ assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
+ }
+ });
+ // Drag over the CoL
+ Espresso.onView(ViewMatchers.withId(R.id.coordinator))
+ // Drag (and not release)
+ .perform(new DragAction(
+ GeneralLocation.BOTTOM_CENTER,
+ GeneralLocation.TOP_CENTER,
+ Press.FINGER))
+ .check(new ViewAssertion() {
+ @Override
+ public void check(View view, NoMatchingViewException e) {
+ // The bottom sheet should not react to the touch events
+ assertThat(getBottomSheet(), is(ViewMatchers.isDisplayed()));
+ assertThat(getBehavior().getState(),
+ is(BottomSheetBehavior.STATE_COLLAPSED));
+ }
+ });
+ }
+
+ @Test
+ @MediumTest
public void testNestedScroll() {
final ViewGroup bottomSheet = getBottomSheet();
final BottomSheetBehavior behavior = getBehavior();
@@ -491,7 +531,7 @@
// Swipe from the very bottom of the bottom sheet to the top edge of the screen so that the
// scrolling content is also scrolled
Espresso.onView(ViewMatchers.withId(R.id.coordinator))
- .perform(new GeneralSwipeAction(Swipe.FAST,
+ .perform(new GeneralSwipeAction(Swipe.SLOW,
new CoordinatesProvider() {
@Override
public float[] calculateCoordinates(View view) {
@@ -618,8 +658,10 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
+ CoordinatorLayout col = getCoordinatorLayout();
assertThat(getBottomSheet().getTop(),
- is(getCoordinatorLayout().getWidth() * 9 / 16));
+ is(Math.min(col.getWidth() * 9 / 16,
+ col.getHeight() - getBehavior().getPeekHeightMin())));
}
});
}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
index ea5872e..fe62e441 100644
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
+++ b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
@@ -28,6 +28,7 @@
import android.support.test.espresso.ViewAssertion;
import android.support.test.espresso.action.ViewActions;
import android.support.v4.view.MotionEventCompat;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
@@ -35,6 +36,7 @@
import org.junit.Before;
import org.junit.Test;
+@MediumTest
public class BottomSheetBehaviorTouchTest extends
BaseInstrumentationTestCase<CoordinatorLayoutActivity> {
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
index 5471c38..f6350c1 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
@@ -293,4 +293,45 @@
// And assert that View B's Behavior was called appropriately
verify(behavior, times(1)).onDependentViewRemoved(col, viewB, viewA);
}
+
+ @Test
+ public void testGetDependenciesAfterDependentViewRemoved() {
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+ // Add two views, A & B, where B depends on A
+ final View viewA = new View(col.getContext());
+ final View viewB = new View(col.getContext());
+ final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
+ final CoordinatorLayout.Behavior behavior
+ = new CoordinatorLayoutUtils.DependentBehavior(viewA) {
+ @Override
+ public void onDependentViewRemoved(CoordinatorLayout parent, View child,
+ View dependency) {
+ parent.getDependencies(child);
+ }
+ };
+ lpB.setBehavior(behavior);
+
+ // Now add views
+ instrumentation.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ col.addView(viewA);
+ col.addView(viewB, lpB);
+ }
+ });
+
+ // Wait for a layout
+ instrumentation.waitForIdleSync();
+
+ // Now remove view A, which will trigger onDependentViewRemoved() on view B's behavior
+ instrumentation.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ col.removeView(viewA);
+ }
+ });
+ }
+
}
diff --git a/fragment/java/android/support/v4/app/BackStackRecord.java b/fragment/java/android/support/v4/app/BackStackRecord.java
index 042cf9d..2b8cd13 100644
--- a/fragment/java/android/support/v4/app/BackStackRecord.java
+++ b/fragment/java/android/support/v4/app/BackStackRecord.java
@@ -348,7 +348,7 @@
writer.println("Removed:");
}
writer.print(innerPrefix); writer.print(" #"); writer.print(i);
- writer.print(": ");
+ writer.print(": ");
}
writer.println(op.removed.get(i));
}
@@ -678,7 +678,7 @@
disallowAddToBackStack();
mManager.execSingleAction(this, true);
}
-
+
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) {
@@ -1349,7 +1349,7 @@
}
}
- private void callSharedElementEnd(TransitionState state, Fragment inFragment,
+ void callSharedElementEnd(TransitionState state, Fragment inFragment,
Fragment outFragment, boolean isBack, ArrayMap<String, View> namedViews) {
SharedElementCallback sharedElementCallback = isBack ?
outFragment.mEnterTransitionCallback :
@@ -1361,7 +1361,7 @@
}
}
- private void setEpicenterIn(ArrayMap<String, View> namedViews, TransitionState state) {
+ void setEpicenterIn(ArrayMap<String, View> namedViews, TransitionState state) {
if (mSharedElementTargetNames != null && !namedViews.isEmpty()) {
// now we know the epicenter of the entering transition.
View epicenter = namedViews
@@ -1372,7 +1372,7 @@
}
}
- private ArrayMap<String, View> mapSharedElementsIn(TransitionState state,
+ ArrayMap<String, View> mapSharedElementsIn(TransitionState state,
boolean isBack, Fragment inFragment) {
// Now map the shared elements in the incoming fragment
ArrayMap<String, View> namedViews = mapEnteringSharedElements(state, inFragment, isBack);
@@ -1459,7 +1459,7 @@
});
}
- private void excludeHiddenFragments(TransitionState state, int containerId, Object transition) {
+ void excludeHiddenFragments(TransitionState state, int containerId, Object transition) {
if (mManager.mAdded != null) {
for (int i = 0; i < mManager.mAdded.size(); i++) {
Fragment fragment = mManager.mAdded.get(i);
diff --git a/fragment/java/android/support/v4/app/FragmentActivity.java b/fragment/java/android/support/v4/app/FragmentActivity.java
index c4953c0..18ee2ae 100644
--- a/fragment/java/android/support/v4/app/FragmentActivity.java
+++ b/fragment/java/android/support/v4/app/FragmentActivity.java
@@ -34,7 +34,6 @@
import android.support.v4.util.SparseArrayCompat;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -200,7 +199,7 @@
final public void setSupportMediaController(MediaControllerCompat mediaController) {
mMediaController = mediaController;
if (android.os.Build.VERSION.SDK_INT >= 21) {
- ActivityCompat21.setMediaController(this, mediaController.getMediaController());
+ ActivityCompatApi21.setMediaController(this, mediaController.getMediaController());
}
}
@@ -406,11 +405,11 @@
if (super.onMenuItemSelected(featureId, item)) {
return true;
}
-
+
switch (featureId) {
case Window.FEATURE_OPTIONS_PANEL:
return mFragments.dispatchOptionsItemSelected(item);
-
+
case Window.FEATURE_CONTEXT_MENU:
return mFragments.dispatchContextItemSelected(item);
@@ -431,7 +430,7 @@
}
super.onPanelClosed(featureId, menu);
}
-
+
/**
* Dispatch onPause() to fragments.
*/
@@ -985,7 +984,7 @@
/**
* Called by Fragment.requestPermissions() to implement its behavior.
*/
- private void requestPermissionsFromFragment(Fragment fragment, String[] permissions,
+ void requestPermissionsFromFragment(Fragment fragment, String[] permissions,
int requestCode) {
if (requestCode == -1) {
ActivityCompat.requestPermissions(this, permissions, requestCode);
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
index 6f251e7..481a9bd 100644
--- a/fragment/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/java/android/support/v4/app/FragmentManager.java
@@ -76,7 +76,7 @@
* with {@link FragmentTransaction#addToBackStack(String)
* FragmentTransaction.addToBackStack()}. Entries can later be
* retrieved with {@link FragmentManager#getBackStackEntryAt(int)
- * FragmentManager.getBackStackEntry()}.
+ * FragmentManager.getBackStackEntryAt()}.
*
* <p>Note that you should never hold on to a BackStackEntry object;
* the identifier as returned by {@link #getId} is the only thing that
@@ -137,7 +137,7 @@
/**
* Start a series of edit operations on the Fragments associated with
* this FragmentManager.
- *
+ *
* <p>Note: A fragment transaction can only be created/committed prior
* to an activity saving its state. If you try to commit a transaction
* after {@link FragmentActivity#onSaveInstanceState FragmentActivity.onSaveInstanceState()}
@@ -157,7 +157,7 @@
public FragmentTransaction openTransaction() {
return beginTransaction();
}
-
+
/**
* After a {@link FragmentTransaction} is committed with
* {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
@@ -230,7 +230,7 @@
* This function is asynchronous -- it enqueues the
* request to pop, but the action will not be performed until the application
* returns to its event loop.
- *
+ *
* @param name If non-null, this is the name of a previous back state
* to look for; if found, all states up to that state will be popped. The
* {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
@@ -252,7 +252,7 @@
* This function is asynchronous -- it enqueues the
* request to pop, but the action will not be performed until the application
* returns to its event loop.
- *
+ *
* @param id Identifier of the stated to be popped. If no identifier exists,
* false is returned.
* The identifier is the number returned by
@@ -378,10 +378,10 @@
FragmentState[] mActive;
int[] mAdded;
BackStackState[] mBackStack;
-
+
public FragmentManagerState() {
}
-
+
public FragmentManagerState(Parcel in) {
mActive = in.createTypedArray(FragmentState.CREATOR);
mAdded = in.createIntArray();
@@ -399,7 +399,7 @@
dest.writeIntArray(mAdded);
dest.writeTypedArray(mBackStack, flags);
}
-
+
public static final Parcelable.Creator<FragmentManagerState> CREATOR
= new Parcelable.Creator<FragmentManagerState>() {
@Override
@@ -420,7 +420,7 @@
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
static boolean DEBUG = false;
static final String TAG = "FragmentManager";
-
+
static final boolean HONEYCOMB = android.os.Build.VERSION.SDK_INT >= 11;
static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
@@ -431,7 +431,7 @@
static class AnimateOnHWLayerIfNeededListener implements AnimationListener {
private AnimationListener mOriginalListener;
private boolean mShouldRunOnHWLayer;
- private View mView;
+ View mView;
public AnimateOnHWLayerIfNeededListener(final View v, Animation anim) {
if (v == null || anim == null) {
@@ -499,13 +499,13 @@
ArrayList<Runnable> mPendingActions;
Runnable[] mTmpActions;
boolean mExecutingActions;
-
+
ArrayList<Fragment> mActive;
ArrayList<Fragment> mAdded;
ArrayList<Integer> mAvailIndices;
ArrayList<BackStackRecord> mBackStack;
ArrayList<Fragment> mCreatedMenus;
-
+
// Must be accessed while locked.
ArrayList<BackStackRecord> mBackStackIndices;
ArrayList<Integer> mAvailBackStackIndices;
@@ -519,17 +519,17 @@
Fragment mParent;
static Field sAnimationListenerField = null;
-
+
boolean mNeedMenuInvalidate;
boolean mStateSaved;
boolean mDestroyed;
String mNoTransactionsBecause;
boolean mHavePendingDeferredStart;
-
+
// Temporary vars for state save and restore.
Bundle mStateBundle = null;
SparseArray<Parcelable> mStateArray = null;
-
+
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
@@ -850,9 +850,9 @@
static final Interpolator DECELERATE_CUBIC = new DecelerateInterpolator(1.5f);
static final Interpolator ACCELERATE_QUINT = new AccelerateInterpolator(2.5f);
static final Interpolator ACCELERATE_CUBIC = new AccelerateInterpolator(1.5f);
-
+
static final int ANIM_DUR = 220;
-
+
static Animation makeOpenCloseAnimation(Context context, float startScale,
float endScale, float startAlpha, float endAlpha) {
AnimationSet set = new AnimationSet(false);
@@ -867,7 +867,7 @@
set.addAnimation(alpha);
return set;
}
-
+
static Animation makeFadeAnimation(Context context, float start, float end) {
AlphaAnimation anim = new AlphaAnimation(start, end);
anim.setInterpolator(DECELERATE_CUBIC);
@@ -882,18 +882,18 @@
if (animObj != null) {
return animObj;
}
-
+
if (fragment.mNextAnim != 0) {
Animation anim = AnimationUtils.loadAnimation(mHost.getContext(), fragment.mNextAnim);
if (anim != null) {
return anim;
}
}
-
+
if (transit == 0) {
return null;
}
-
+
int styleIndex = transitToStyleIndex(transit, enter);
if (styleIndex < 0) {
return null;
@@ -913,27 +913,27 @@
case ANIM_STYLE_FADE_EXIT:
return makeFadeAnimation(mHost.getContext(), 1, 0);
}
-
+
if (transitionStyle == 0 && mHost.onHasWindowAnimations()) {
transitionStyle = mHost.onGetWindowAnimations();
}
if (transitionStyle == 0) {
return null;
}
-
+
//TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
// com.android.internal.R.styleable.FragmentAnimation);
//int anim = attrs.getResourceId(styleIndex, 0);
//attrs.recycle();
-
+
//if (anim == 0) {
// return null;
//}
-
+
//return AnimatorInflater.loadAnimator(mActivity, anim);
return null;
}
-
+
public void performPendingDeferredStart(Fragment f) {
if (f.mDeferStart) {
if (mExecutingActions) {
@@ -1004,7 +1004,7 @@
// being reloaded from the layout.
if (f.mFromLayout && !f.mInLayout) {
return;
- }
+ }
if (f.mAnimatingAway != null) {
// The fragment is currently being animated... but! Now we
// want to move our state back up. Give up on waiting for the
@@ -1263,7 +1263,7 @@
f.mState = newState;
}
}
-
+
void moveToState(Fragment f) {
moveToState(f, mCurState, 0, 0, false);
}
@@ -1271,7 +1271,7 @@
void moveToState(int newState, boolean always) {
moveToState(newState, 0, 0, always);
}
-
+
void moveToState(int newState, int transit, int transitStyle, boolean always) {
if (mHost == null && newState != Fragment.INITIALIZING) {
throw new IllegalStateException("No host");
@@ -1315,31 +1315,31 @@
}
}
}
-
+
void makeActive(Fragment f) {
if (f.mIndex >= 0) {
return;
}
-
+
if (mAvailIndices == null || mAvailIndices.size() <= 0) {
if (mActive == null) {
mActive = new ArrayList<Fragment>();
}
f.setIndex(mActive.size(), mParent);
mActive.add(f);
-
+
} else {
f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
mActive.set(f.mIndex, f);
}
if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
}
-
+
void makeInactive(Fragment f) {
if (f.mIndex < 0) {
return;
}
-
+
if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
mActive.set(f.mIndex, null);
if (mAvailIndices == null) {
@@ -1349,7 +1349,7 @@
mHost.inactivateFragment(f.mWho);
f.initState();
}
-
+
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
@@ -1371,7 +1371,7 @@
}
}
}
-
+
public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
final boolean inactive = !fragment.isInBackStack();
@@ -1388,7 +1388,7 @@
transition, transitionStyle, false);
}
}
-
+
public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "hide: " + fragment);
if (!fragment.mHidden) {
@@ -1408,7 +1408,7 @@
fragment.onHiddenChanged(true);
}
}
-
+
public void showFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "show: " + fragment);
if (fragment.mHidden) {
@@ -1428,7 +1428,7 @@
fragment.onHiddenChanged(false);
}
}
-
+
public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "detach: " + fragment);
if (!fragment.mDetached) {
@@ -1515,7 +1515,7 @@
}
return null;
}
-
+
public Fragment findFragmentByWho(String who) {
if (mActive != null && who != null) {
for (int i=mActive.size()-1; i>=0; i--) {
@@ -1527,7 +1527,7 @@
}
return null;
}
-
+
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
@@ -1564,7 +1564,7 @@
}
}
}
-
+
public int allocBackStackIndex(BackStackRecord bse) {
synchronized (this) {
if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
@@ -1648,7 +1648,7 @@
if (mExecutingActions) {
throw new IllegalStateException("FragmentManager is already executing transactions");
}
-
+
if (Looper.myLooper() != mHost.getHandler().getLooper()) {
throw new IllegalStateException("Must be called from main thread of fragment host");
}
@@ -1657,12 +1657,12 @@
while (true) {
int numActions;
-
+
synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
break;
}
-
+
numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
@@ -1671,7 +1671,7 @@
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
-
+
mExecutingActions = true;
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
@@ -1680,7 +1680,7 @@
mExecutingActions = false;
didSomething = true;
}
-
+
doPendingDeferredStart();
return didSomething;
@@ -1717,7 +1717,7 @@
mBackStack.add(state);
reportBackStackChanged();
}
-
+
@SuppressWarnings("unused")
boolean popBackStackState(Handler handler, String name, int id, int flags) {
if (mBackStack == null) {
@@ -1795,7 +1795,7 @@
}
return true;
}
-
+
FragmentManagerNonConfig retainNonConfig() {
ArrayList<Fragment> fragments = null;
ArrayList<FragmentManagerNonConfig> childFragments = null;
@@ -1837,7 +1837,7 @@
}
return new FragmentManagerNonConfig(fragments, childFragments);
}
-
+
void saveFragmentViewState(Fragment f) {
if (f.mInnerView == null) {
return;
@@ -1853,7 +1853,7 @@
mStateArray = null;
}
}
-
+
Bundle saveFragmentBasicState(Fragment f) {
Bundle result = null;
@@ -1908,7 +1908,7 @@
if (mActive == null || mActive.size() <= 0) {
return null;
}
-
+
// First collect all active fragments.
int N = mActive.size();
FragmentState[] active = new FragmentState[N];
@@ -1923,10 +1923,10 @@
}
haveFragments = true;
-
+
FragmentState fs = new FragmentState(f);
active[i] = fs;
-
+
if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
fs.mSavedFragmentState = saveFragmentBasicState(f);
@@ -1951,20 +1951,20 @@
} else {
fs.mSavedFragmentState = f.mSavedFragmentState;
}
-
+
if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
+ fs.mSavedFragmentState);
}
}
-
+
if (!haveFragments) {
if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
return null;
}
-
+
int[] added = null;
BackStackState[] backStack = null;
-
+
// Build list of currently added fragments.
if (mAdded != null) {
N = mAdded.size();
@@ -1982,7 +1982,7 @@
}
}
}
-
+
// Now save back stack.
if (mBackStack != null) {
N = mBackStack.size();
@@ -1995,14 +1995,14 @@
}
}
}
-
+
FragmentManagerState fms = new FragmentManagerState();
fms.mActive = active;
fms.mAdded = added;
fms.mBackStack = backStack;
return fms;
}
-
+
void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
// If there is no saved state at all, then there can not be
// any nonConfig fragments either, so that is that.
@@ -2036,7 +2036,7 @@
}
}
}
-
+
// Build the full list of active fragments, instantiating them from
// their saved state.
mActive = new ArrayList<>(fms.mActive.length);
@@ -2066,7 +2066,7 @@
mAvailIndices.add(i);
}
}
-
+
// Update the target of all retained fragments.
if (nonConfig != null) {
List<Fragment> nonConfigFragments = nonConfig.getFragments();
@@ -2104,7 +2104,7 @@
} else {
mAdded = null;
}
-
+
// Build the back stack.
if (fms.mBackStack != null) {
mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
@@ -2134,35 +2134,35 @@
mContainer = container;
mParent = parent;
}
-
+
public void noteStateNotSaved() {
mStateSaved = false;
}
-
+
public void dispatchCreate() {
mStateSaved = false;
moveToState(Fragment.CREATED, false);
}
-
+
public void dispatchActivityCreated() {
mStateSaved = false;
moveToState(Fragment.ACTIVITY_CREATED, false);
}
-
+
public void dispatchStart() {
mStateSaved = false;
moveToState(Fragment.STARTED, false);
}
-
+
public void dispatchResume() {
mStateSaved = false;
moveToState(Fragment.RESUMED, false);
}
-
+
public void dispatchPause() {
moveToState(Fragment.STARTED, false);
}
-
+
public void dispatchStop() {
// See saveAllState() for the explanation of this. We do this for
// all platform versions, to keep our behavior more consistent between
@@ -2171,7 +2171,7 @@
moveToState(Fragment.STOPPED, false);
}
-
+
public void dispatchReallyStop() {
moveToState(Fragment.ACTIVITY_CREATED, false);
}
@@ -2266,7 +2266,7 @@
return show;
}
-
+
public boolean dispatchPrepareOptionsMenu(Menu menu) {
boolean show = false;
if (mAdded != null) {
@@ -2281,7 +2281,7 @@
}
return show;
}
-
+
public boolean dispatchOptionsItemSelected(MenuItem item) {
if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) {
@@ -2295,7 +2295,7 @@
}
return false;
}
-
+
public boolean dispatchContextItemSelected(MenuItem item) {
if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) {
@@ -2309,7 +2309,7 @@
}
return false;
}
-
+
public void dispatchOptionsMenuClosed(Menu menu) {
if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) {
@@ -2335,16 +2335,16 @@
break;
}
return rev;
-
+
}
-
+
public static final int ANIM_STYLE_OPEN_ENTER = 1;
public static final int ANIM_STYLE_OPEN_EXIT = 2;
public static final int ANIM_STYLE_CLOSE_ENTER = 3;
public static final int ANIM_STYLE_CLOSE_EXIT = 4;
public static final int ANIM_STYLE_FADE_ENTER = 5;
public static final int ANIM_STYLE_FADE_EXIT = 6;
-
+
public static int transitToStyleIndex(int transit, boolean enter) {
int animAttr = -1;
switch (transit) {
diff --git a/fragment/java/android/support/v4/app/FragmentTabHost.java b/fragment/java/android/support/v4/app/FragmentTabHost.java
index 2faf5e9..09b89b7 100644
--- a/fragment/java/android/support/v4/app/FragmentTabHost.java
+++ b/fragment/java/android/support/v4/app/FragmentTabHost.java
@@ -21,6 +21,8 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -49,7 +51,8 @@
*/
public class FragmentTabHost extends TabHost
implements TabHost.OnTabChangeListener {
- private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
+ private final ArrayList<TabInfo> mTabs = new ArrayList<>();
+
private FrameLayout mRealTabContent;
private Context mContext;
private FragmentManager mFragmentManager;
@@ -59,12 +62,12 @@
private boolean mAttached;
static final class TabInfo {
- private final String tag;
- private final Class<?> clss;
- private final Bundle args;
- private Fragment fragment;
+ final @NonNull String tag;
+ final @NonNull Class<?> clss;
+ final @Nullable Bundle args;
+ Fragment fragment;
- TabInfo(String _tag, Class<?> _class, Bundle _args) {
+ TabInfo(@NonNull String _tag, @NonNull Class<?> _class, @Nullable Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
@@ -94,7 +97,7 @@
super(superState);
}
- private SavedState(Parcel in) {
+ SavedState(Parcel in) {
super(in);
curTab = in.readString();
}
@@ -139,7 +142,7 @@
}
private void initFragmentTabHost(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs,
+ final TypedArray a = context.obtainStyledAttributes(attrs,
new int[] { android.R.attr.inflatedId }, 0, 0);
mContainerId = a.getResourceId(0, 0);
a.recycle();
@@ -225,11 +228,12 @@
mOnTabChangeListener = l;
}
- public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
+ public void addTab(@NonNull TabHost.TabSpec tabSpec, @NonNull Class<?> clss,
+ @Nullable Bundle args) {
tabSpec.setContent(new DummyTabFactory(mContext));
- String tag = tabSpec.getTag();
- TabInfo info = new TabInfo(tag, clss, args);
+ final String tag = tabSpec.getTag();
+ final TabInfo info = new TabInfo(tag, clss, args);
if (mAttached) {
// If we are already attached to the window, then check to make
@@ -237,7 +241,7 @@
// normally happen.
info.fragment = mFragmentManager.findFragmentByTag(tag);
if (info.fragment != null && !info.fragment.isDetached()) {
- FragmentTransaction ft = mFragmentManager.beginTransaction();
+ final FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.detach(info.fragment);
ft.commit();
}
@@ -251,16 +255,16 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- String currentTab = getCurrentTabTag();
+ final String currentTag = getCurrentTabTag();
// Go through all tabs and make sure their fragments match
// the correct state.
FragmentTransaction ft = null;
- for (int i=0; i<mTabs.size(); i++) {
- TabInfo tab = mTabs.get(i);
+ for (int i = 0, count = mTabs.size(); i < count; i++) {
+ final TabInfo tab = mTabs.get(i);
tab.fragment = mFragmentManager.findFragmentByTag(tab.tag);
if (tab.fragment != null && !tab.fragment.isDetached()) {
- if (tab.tag.equals(currentTab)) {
+ if (tab.tag.equals(currentTag)) {
// The fragment for this tab is already there and
// active, and it is what we really want to have
// as the current tab. Nothing to do.
@@ -279,7 +283,7 @@
// We are now ready to go. Make sure we are switched to the
// correct tab.
mAttached = true;
- ft = doTabChanged(currentTab, ft);
+ ft = doTabChanged(currentTag, ft);
if (ft != null) {
ft.commit();
mFragmentManager.executePendingTransactions();
@@ -314,7 +318,7 @@
@Override
public void onTabChanged(String tabId) {
if (mAttached) {
- FragmentTransaction ft = doTabChanged(tabId, null);
+ final FragmentTransaction ft = doTabChanged(tabId, null);
if (ft != null) {
ft.commit();
}
@@ -324,26 +328,21 @@
}
}
- private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
- TabInfo newTab = null;
- for (int i=0; i<mTabs.size(); i++) {
- TabInfo tab = mTabs.get(i);
- if (tab.tag.equals(tabId)) {
- newTab = tab;
- }
- }
- if (newTab == null) {
- throw new IllegalStateException("No tab known for tag " + tabId);
- }
+ @Nullable
+ private FragmentTransaction doTabChanged(@Nullable String tag,
+ @Nullable FragmentTransaction ft) {
+ final TabInfo newTab = getTabInfoForTag(tag);
if (mLastTab != newTab) {
if (ft == null) {
ft = mFragmentManager.beginTransaction();
}
+
if (mLastTab != null) {
if (mLastTab.fragment != null) {
ft.detach(mLastTab.fragment);
}
}
+
if (newTab != null) {
if (newTab.fragment == null) {
newTab.fragment = Fragment.instantiate(mContext,
@@ -356,6 +355,18 @@
mLastTab = newTab;
}
+
return ft;
}
+
+ @Nullable
+ private TabInfo getTabInfoForTag(String tabId) {
+ for (int i = 0, count = mTabs.size(); i < count; i++) {
+ final TabInfo tab = mTabs.get(i);
+ if (tab.tag.equals(tabId)) {
+ return tab;
+ }
+ }
+ return null;
+ }
}
diff --git a/fragment/java/android/support/v4/app/LoaderManager.java b/fragment/java/android/support/v4/app/LoaderManager.java
index 634a6bc..8d777a1 100644
--- a/fragment/java/android/support/v4/app/LoaderManager.java
+++ b/fragment/java/android/support/v4/app/LoaderManager.java
@@ -33,7 +33,7 @@
* on Android 3.0 or above, this implementation is still used; it does not try
* to switch to the framework's implementation. See the framework SDK
* documentation for a class overview.
- *
+ *
* <p>Your activity must derive from {@link FragmentActivity} to use this.
*/
public abstract class LoaderManager {
@@ -56,7 +56,7 @@
* transactions while in this call, since it can happen after an
* activity's state is saved. See {@link FragmentManager#beginTransaction()
* FragmentManager.openTransaction()} for further discussion on this.
- *
+ *
* <p>This function is guaranteed to be called prior to the release of
* the last data that was supplied for this Loader. At this point
* you should remove all use of the old data (since it will be released
@@ -100,7 +100,7 @@
*/
public void onLoaderReset(Loader<D> loader);
}
-
+
/**
* Ensures a loader is initialized and active. If the loader doesn't
* already exist, one is created and (if the activity/fragment is currently
@@ -207,9 +207,9 @@
boolean mStarted;
boolean mRetaining;
boolean mRetainingStarted;
-
+
boolean mCreatingLoader;
- private FragmentHostCallback mHost;
+ FragmentHostCallback mHost;
final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
Loader.OnLoadCanceledListener<Object> {
@@ -231,13 +231,13 @@
boolean mListenerRegistered;
LoaderInfo mPendingLoader;
-
+
public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
mId = id;
mArgs = args;
mCallbacks = callbacks;
}
-
+
void start() {
if (mRetaining && mRetainingStarted) {
// Our owner is started, but we were being retained from a
@@ -253,7 +253,7 @@
}
mStarted = true;
-
+
if (DEBUG) Log.v(TAG, " Starting: " + this);
if (mLoader == null && mCallbacks != null) {
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
@@ -273,7 +273,7 @@
mLoader.startLoading();
}
}
-
+
void retain() {
if (DEBUG) Log.v(TAG, " Retaining: " + this);
mRetaining = true;
@@ -281,7 +281,7 @@
mStarted = false;
mCallbacks = null;
}
-
+
void finishRetain() {
if (mRetaining) {
if (DEBUG) Log.v(TAG, " Finished Retaining: " + this);
@@ -306,7 +306,7 @@
callOnLoadFinished(mLoader, mData);
}
}
-
+
void reportStart() {
if (mStarted) {
if (mReportNextStart) {
@@ -412,7 +412,7 @@
@Override
public void onLoadComplete(Loader<Object> loader, Object data) {
if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
-
+
if (mDestroyed) {
if (DEBUG) Log.v(TAG, " Ignoring load complete -- destroyed");
return;
@@ -424,7 +424,7 @@
if (DEBUG) Log.v(TAG, " Ignoring load complete -- not active");
return;
}
-
+
LoaderInfo pending = mPendingLoader;
if (pending != null) {
// There is a new request pending and we were just
@@ -437,7 +437,7 @@
installLoader(pending);
return;
}
-
+
// Notify of the new data so the app can switch out the old data before
// we try to destroy it.
if (mData != data || !mHaveData) {
@@ -485,7 +485,7 @@
mDeliveredData = true;
}
}
-
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(64);
@@ -525,17 +525,17 @@
}
}
}
-
+
LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) {
mWho = who;
mHost = host;
mStarted = started;
}
-
+
void updateHostController(FragmentHostCallback host) {
mHost = host;
}
-
+
private LoaderInfo createLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
LoaderInfo info = new LoaderInfo(id, args, callback);
@@ -543,7 +543,7 @@
info.mLoader = loader;
return info;
}
-
+
private LoaderInfo createAndInstallLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
try {
@@ -555,7 +555,7 @@
mCreatingLoader = false;
}
}
-
+
void installLoader(LoaderInfo info) {
mLoaders.put(info.mId, info);
if (mStarted) {
@@ -565,23 +565,23 @@
info.start();
}
}
-
+
/**
* Call to initialize a particular ID with a Loader. If this ID already
* has a Loader associated with it, it is left unchanged and any previous
* callbacks replaced with the newly provided ones. If there is not currently
* a Loader for the ID, a new one is created and started.
- *
+ *
* <p>This function should generally be used when a component is initializing,
* to ensure that a Loader it relies on is created. This allows it to re-use
* an existing Loader's data if there already is one, so that for example
* when an {@link Activity} is re-created after a configuration change it
* does not need to re-create its loaders.
- *
+ *
* <p>Note that in the case where an existing Loader is re-used, the
* <var>args</var> given here <em>will be ignored</em> because you will
* continue using the previous Loader.
- *
+ *
* @param id A unique (to this LoaderManager instance) identifier under
* which to manage the new Loader.
* @param args Optional arguments that will be propagated to
@@ -596,9 +596,9 @@
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
-
+
LoaderInfo info = mLoaders.get(id);
-
+
if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
if (info == null) {
@@ -609,30 +609,30 @@
if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
-
+
if (info.mHaveData && mStarted) {
// If the loader has already generated its data, report it now.
info.callOnLoadFinished(info.mLoader, info.mData);
}
-
+
return (Loader<D>)info.mLoader;
}
-
+
/**
* Call to re-create the Loader associated with a particular ID. If there
* is currently a Loader associated with this ID, it will be
* canceled/stopped/destroyed as appropriate. A new Loader with the given
* arguments will be created and its data delivered to you once available.
- *
+ *
* <p>This function does some throttling of Loaders. If too many Loaders
* have been created for the given ID but not yet generated their data,
* new calls to this function will create and return a new Loader but not
* actually start it until some previous loaders have completed.
- *
+ *
* <p>After calling this function, any previous Loaders associated with
* this ID will be considered invalid, and you will receive no further
* data updates from them.
- *
+ *
* @param id A unique (to this LoaderManager instance) identifier under
* which to manage the new Loader.
* @param args Optional arguments that will be propagated to
@@ -647,7 +647,7 @@
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
-
+
LoaderInfo info = mLoaders.get(id);
if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
if (info != null) {
@@ -686,7 +686,7 @@
info.mPendingLoader = null;
}
if (DEBUG) Log.v(TAG, " Enqueuing as new pending loader");
- info.mPendingLoader = createLoader(id, args,
+ info.mPendingLoader = createLoader(id, args,
(LoaderManager.LoaderCallbacks<Object>)callback);
return (Loader<D>)info.mPendingLoader.mLoader;
}
@@ -699,11 +699,11 @@
mInactiveLoaders.put(id, info);
}
}
-
+
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
return (Loader<D>)info.mLoader;
}
-
+
/**
* Rip down, tear apart, shred to pieces a current Loader ID. After returning
* from this function, any Loader objects associated with this ID are
@@ -716,7 +716,7 @@
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
-
+
if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
int idx = mLoaders.indexOfKey(id);
if (idx >= 0) {
@@ -745,7 +745,7 @@
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
-
+
LoaderInfo loaderInfo = mLoaders.get(id);
if (loaderInfo != null) {
if (loaderInfo.mPendingLoader != null) {
@@ -755,7 +755,7 @@
}
return null;
}
-
+
void doStart() {
if (DEBUG) Log.v(TAG, "Starting in " + this);
if (mStarted) {
@@ -764,7 +764,7 @@
Log.w(TAG, "Called doStart when already started: " + this, e);
return;
}
-
+
mStarted = true;
// Call out to sub classes so they can start their loaders
@@ -773,7 +773,7 @@
mLoaders.valueAt(i).start();
}
}
-
+
void doStop() {
if (DEBUG) Log.v(TAG, "Stopping in " + this);
if (!mStarted) {
@@ -788,7 +788,7 @@
}
mStarted = false;
}
-
+
void doRetain() {
if (DEBUG) Log.v(TAG, "Retaining in " + this);
if (!mStarted) {
@@ -804,7 +804,7 @@
mLoaders.valueAt(i).retain();
}
}
-
+
void finishRetain() {
if (mRetaining) {
if (DEBUG) Log.v(TAG, "Finished Retaining in " + this);
@@ -815,7 +815,7 @@
}
}
}
-
+
void doReportNextStart() {
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).mReportNextStart = true;
@@ -836,7 +836,7 @@
}
mLoaders.clear();
}
-
+
if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
mInactiveLoaders.valueAt(i).destroy();
diff --git a/fragment/tests/java/android/support/v4/app/ChildFragmentStateTest.java b/fragment/tests/java/android/support/v4/app/ChildFragmentStateTest.java
index 78c3e28..188c3b1 100644
--- a/fragment/tests/java/android/support/v4/app/ChildFragmentStateTest.java
+++ b/fragment/tests/java/android/support/v4/app/ChildFragmentStateTest.java
@@ -21,7 +21,9 @@
import android.support.v4.app.test.FragmentTestActivity.ParentFragment;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
+@SmallTest
public class ChildFragmentStateTest extends ActivityInstrumentationTestCase2<FragmentTestActivity> {
public ChildFragmentStateTest() {
super(FragmentTestActivity.class);
diff --git a/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java b/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
index cc884f9..84700ff 100644
--- a/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
+++ b/fragment/tests/java/android/support/v4/app/NestedFragmentTest.java
@@ -26,10 +26,12 @@
import android.support.v4.app.test.FragmentTestActivity.ParentFragment;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.LargeTest;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+@LargeTest
public class NestedFragmentTest extends ActivityInstrumentationTestCase2<FragmentTestActivity> {
ParentFragment mParentFragment;
diff --git a/gradlew b/gradlew
index d1c75a2..9d82f78 100755
--- a/gradlew
+++ b/gradlew
@@ -157,4 +157,4 @@
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
\ No newline at end of file
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
index 0822e20..639e906 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -50,7 +50,7 @@
import java.util.List;
/**
- * For API 23 and above, this class is delegating to the framework's {@link AnimatedVectorDrawable}.
+ * For API 24 and above, this class is delegating to the framework's {@link AnimatedVectorDrawable}.
* For older API version, this class uses {@link android.animation.ObjectAnimator} and
* {@link android.animation.AnimatorSet} to animate the properties of a
* {@link VectorDrawableCompat} to create an animated drawable.
@@ -118,7 +118,7 @@
@Nullable
public static AnimatedVectorDrawableCompat create(@NonNull Context context,
@DrawableRes int resId) {
- if (Build.VERSION.SDK_INT >= 23) {
+ if (Build.VERSION.SDK_INT >= 24) {
final AnimatedVectorDrawableCompat drawable = new AnimatedVectorDrawableCompat(context);
drawable.mDelegateDrawable = ResourcesCompat.getDrawable(context.getResources(), resId,
context.getTheme());
@@ -165,7 +165,7 @@
/**
* {@inheritDoc}
- * <strong>Note</strong> that we don't support constant state when SDK < 23.
+ * <strong>Note</strong> that we don't support constant state when SDK < 24.
* Make sure you check the return value before using it.
*/
@Override
@@ -510,12 +510,12 @@
@Override
public Drawable newDrawable() {
- throw new IllegalStateException("No constant state support for SDK < 23.");
+ throw new IllegalStateException("No constant state support for SDK < 24.");
}
@Override
public Drawable newDrawable(Resources res) {
- throw new IllegalStateException("No constant state support for SDK < 23.");
+ throw new IllegalStateException("No constant state support for SDK < 24.");
}
@Override
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java b/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
index b2b720c..2e50823 100644
--- a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
+++ b/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
@@ -27,6 +27,8 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.ViewCompat;
+import android.test.suitebuilder.annotation.MediumTest;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -47,6 +49,7 @@
import static org.junit.Assert.*;
+@MediumTest
@RunWith(AndroidJUnit4.class)
public class AnimatedVectorDrawableTest {
@Rule public final ActivityTestRule<DrawableStubActivity> mActivityTestRule;
@@ -199,7 +202,7 @@
public void run() {
AnimatedVectorDrawableCompat avd = AnimatedVectorDrawableCompat.create(mContext,
R.drawable.animated_color_fill);
- imageButton.setBackgroundDrawable(avd);
+ ViewCompat.setBackground(imageButton, avd);
avd.start();
}
});
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
index 40f4c1a..927b5b3 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -54,7 +54,7 @@
import java.util.Stack;
/**
- * For API 23 and above, this class is delegating to the framework's {@link VectorDrawable}.
+ * For API 24 and above, this class is delegating to the framework's {@link VectorDrawable}.
* For older API version, this class lets you create a drawable based on an XML vector graphic.
* <p>
* VectorDrawableCompat are defined in the same XML format as {@link VectorDrawable}.
@@ -401,7 +401,7 @@
@Nullable
public static VectorDrawableCompat create(@NonNull Resources res, @DrawableRes int resId,
@Nullable Theme theme) {
- if (Build.VERSION.SDK_INT >= 23) {
+ if (Build.VERSION.SDK_INT >= 24) {
final VectorDrawableCompat drawable = new VectorDrawableCompat();
drawable.mDelegateDrawable = ResourcesCompat.getDrawable(res, resId, theme);
drawable.mCachedConstantStateDelegate = new VectorDrawableDelegateState(
@@ -720,7 +720,7 @@
}
/**
- * Constant state for delegating the creating drawable job for SDK >= 23.
+ * Constant state for delegating the creating drawable job for SDK >= 24.
* Instead of creating a VectorDrawable, create a VectorDrawableCompat instance which contains
* a delegated VectorDrawable instance.
*/
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_share_golden.png b/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_share_golden.png
new file mode 100644
index 0000000..a233b1d
--- /dev/null
+++ b/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_share_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_wishlist_golden.png b/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_wishlist_golden.png
new file mode 100644
index 0000000..4ea9aef
--- /dev/null
+++ b/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_wishlist_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_share.xml b/graphics/drawable/static/tests/res/drawable/vector_icon_share.xml
new file mode 100644
index 0000000..155302c
--- /dev/null
+++ b/graphics/drawable/static/tests/res/drawable/vector_icon_share.xml
@@ -0,0 +1,29 @@
+<?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.
+ */
+-->
+
+<vector android:height="24dp" android:viewportHeight="72.0"
+ android:viewportWidth="72.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <group
+ android:scaleX = "2"
+ android:scaleY = "2"
+ android:translateY = "-16"
+ android:translateX = "-36">
+ <path android:fillColor="#FF000000" android:pathData="M60.64,49.29a11.35,11.35 0,0 0,-9.74 5.54L22,39.65a11.14,11.14 0,0 0,0 -7.72L50.87,17.11a11.47,11.47 0,1 0,-1.17 -2.77l-29,14.93a11.36,11.36 0,1 0,0 13L49.71,57.59A11.35,11.35 0,1 0,60.64 49.29ZM60.64,3a8.36,8.36 0,1 1,-8.36 8.36A8.37,8.37 0,0 1,60.64 3ZM11.36,44.13a8.36,8.36 0,1 1,8.36 -8.36A8.37,8.37 0,0 1,11.36 44.13ZM60.64,69A8.36,8.36 0,1 1,69 60.64,8.37 8.37,0 0,1 60.64,69Z"/>
+ </group>
+</vector>
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_wishlist.xml b/graphics/drawable/static/tests/res/drawable/vector_icon_wishlist.xml
new file mode 100644
index 0000000..fd4a52f
--- /dev/null
+++ b/graphics/drawable/static/tests/res/drawable/vector_icon_wishlist.xml
@@ -0,0 +1,28 @@
+<?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.
+ */
+-->
+
+<vector android:height="24dp" android:viewportHeight="72.0"
+ android:viewportWidth="72.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <group
+ android:scaleX = "2"
+ android:scaleY = "2"
+ android:translateX = "-72">
+ <path android:fillColor="#FF000000" android:pathData="M36,69.46h0c-1.56,0 -2.79,-1.17 -4.37,-2.81L4.72,34.93l-0.1,-0.13C2.39,31.48 0,27.47 0,22 0,11.25 8.41,2.54 18.75,2.54c6.18,0 11.85,2.59 17.3,7.91 4.5,-4.06 10,-7.91 17.2,-7.91C63.59,2.54 72,11.25 72,22A19.71,19.71 0,0 1,67.31 34.9L40.41,66.58C38.76,68.3 37.53,69.46 36,69.46ZM7.07,33.06L33.82,64.64A6.8,6.8 0,0 0,36 66.46c0.26,0 1,-0.64 2.21,-1.89L65,33a16.64,16.64 0,0 0,4 -11c0,-7.89 -6,-16.41 -15.75,-16.41C46.57,5.54 41.5,9.42 37,13.62a1.5,1.5 0,0 1,-2.11 -0.06c-5.17,-5.4 -10.46,-8 -16.17,-8C9,5.54 3,14.06 3,22 3,26.59 5,30 7.07,33.06Z"/>
+ </group>
+</vector>
diff --git a/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java b/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java
index 9049b35..8fb9c2d 100644
--- a/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java
+++ b/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java
@@ -71,6 +71,8 @@
R.drawable.vector_icon_stroke_3,
R.drawable.vector_icon_scale_1,
R.drawable.vector_icon_group_clip,
+ R.drawable.vector_icon_share,
+ R.drawable.vector_icon_wishlist,
};
private static final int[] GOLDEN_IMAGES = new int[]{
@@ -97,6 +99,8 @@
R.drawable.vector_icon_stroke_3_golden,
R.drawable.vector_icon_scale_1_golden,
R.drawable.vector_icon_group_clip_golden,
+ R.drawable.vector_icon_share_golden,
+ R.drawable.vector_icon_wishlist_golden,
};
private static final int TEST_ICON = R.drawable.vector_icon_create;
diff --git a/samples/Support13Demos/AndroidManifest.xml b/samples/Support13Demos/AndroidManifest.xml
index dfa4e64..01bab26 100644
--- a/samples/Support13Demos/AndroidManifest.xml
+++ b/samples/Support13Demos/AndroidManifest.xml
@@ -87,5 +87,13 @@
</intent-filter>
</activity>
+ <activity android:name=".view.inputmethod.CommitContentSupport"
+ android:label="@string/commit_content_support">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv13.SUPPORT13_SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
</application>
</manifest>
diff --git a/samples/Support13Demos/res/layout/commit_content.xml b/samples/Support13Demos/res/layout/commit_content.xml
new file mode 100644
index 0000000..414df18
--- /dev/null
+++ b/samples/Support13Demos/res/layout/commit_content.xml
@@ -0,0 +1,142 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black">
+
+ <WebView
+ android:id="@+id/commit_content_webview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#77000000"
+ android:orientation="vertical">
+
+ <HorizontalScrollView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fadeScrollbars="false"
+ android:scrollbars="horizontal">
+
+ <TableLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TableRow>
+
+ <TextView
+ android:layout_column="1"
+ android:gravity="end"
+ android:padding="3dip"
+ android:text="MIME"
+ android:textColor="@android:color/white"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/text_commit_content_mime_types"
+ android:padding="3dip"
+ android:textColor="@android:color/white" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_column="1"
+ android:gravity="end"
+ android:padding="3dip"
+ android:text="Label"
+ android:textColor="@android:color/white"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/text_commit_content_label"
+ android:padding="3dip"
+ android:textColor="@android:color/white" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_column="1"
+ android:gravity="end"
+ android:padding="3dip"
+ android:text="URI"
+ android:textColor="@android:color/white"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/text_commit_content_content_uri"
+ android:padding="3dip"
+ android:textColor="@android:color/white" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_column="1"
+ android:gravity="end"
+ android:padding="3dip"
+ android:text="Link"
+ android:textColor="@android:color/white"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/text_commit_content_link_uri"
+ android:padding="3dip"
+ android:textColor="@android:color/white" />
+ </TableRow>
+
+ <TableRow>
+
+ <TextView
+ android:layout_column="1"
+ android:gravity="end"
+ android:padding="3dip"
+ android:text="Flags"
+ android:textColor="@android:color/white"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/text_commit_content_link_flags"
+ android:padding="3dip"
+ android:textColor="@android:color/white" />
+ </TableRow>
+ </TableLayout>
+ </HorizontalScrollView>
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:fadeScrollbars="false"
+ android:scrollbars="vertical">
+
+ <LinearLayout
+ android:id="@+id/commit_content_sample_edit_boxes"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" />
+ </ScrollView>
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/samples/Support13Demos/res/values/strings.xml b/samples/Support13Demos/res/values/strings.xml
index 92316d0..30b6a18 100644
--- a/samples/Support13Demos/res/values/strings.xml
+++ b/samples/Support13Demos/res/values/strings.xml
@@ -36,4 +36,7 @@
<string name="fragment_state_pager_support">Fragment/State Pager</string>
<string name="action_bar_tabs_pager">Fragment/Action Bar Tabs Pager</string>
+
+ <string name="commit_content_support">View/Input Method/Commit Content</string>
+
</resources>
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java b/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
index 301a2f8..1bf7691 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
@@ -103,7 +103,7 @@
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
- mViewPager.setOnPageChangeListener(this);
+ mViewPager.addOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentNestingPagerSupport.java b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentNestingPagerSupport.java
index 0a88a05..3896d9a 100644
--- a/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentNestingPagerSupport.java
+++ b/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentNestingPagerSupport.java
@@ -101,7 +101,7 @@
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
- mViewPager.setOnPageChangeListener(this);
+ mViewPager.addOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
diff --git a/samples/Support13Demos/src/com/example/android/supportv13/view/inputmethod/CommitContentSupport.java b/samples/Support13Demos/src/com/example/android/supportv13/view/inputmethod/CommitContentSupport.java
new file mode 100644
index 0000000..29f8a91
--- /dev/null
+++ b/samples/Support13Demos/src/com/example/android/supportv13/view/inputmethod/CommitContentSupport.java
@@ -0,0 +1,258 @@
+/*
+ * 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
+ */
+
+package com.example.android.supportv13.view.inputmethod;
+
+import com.example.android.supportv13.R;
+
+import android.support.v13.view.inputmethod.EditorInfoCompat;
+import android.support.v13.view.inputmethod.InputConnectionCompat;
+import android.support.v13.view.inputmethod.InputContentInfoCompat;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.webkit.WebView;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import static android.widget.LinearLayout.VERTICAL;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class CommitContentSupport extends Activity {
+ private static final String INPUT_CONTENT_INFO_KEY = "COMMIT_CONTENT_INPUT_CONTENT_INFO";
+ private static final String COMMIT_CONTENT_FLAGS_KEY = "COMMIT_CONTENT_FLAGS";
+
+ private static String TAG = "CommitContentSupport";
+
+ private WebView mWebView;
+ private TextView mLabel;
+ private TextView mContentUri;
+ private TextView mLinkUri;
+ private TextView mMimeTypes;
+ private TextView mFlags;
+
+ private InputContentInfoCompat mCurrentInputContentInfo;
+ private int mCurrentFlags;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.commit_content);
+
+ final LinearLayout layout =
+ (LinearLayout) findViewById(R.id.commit_content_sample_edit_boxes);
+
+ // This declares that the IME cannot commit any content with
+ // InputConnectionCompat#commitContent().
+ layout.addView(createEditTextWithContentMimeTypes(null));
+
+ // This declares that the IME can commit contents with
+ // InputConnectionCompat#commitContent() if they match "image/gif".
+ layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/gif"}));
+
+ // This declares that the IME can commit contents with
+ // InputConnectionCompat#commitContent() if they match "image/png".
+ layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/png"}));
+
+ // This declares that the IME can commit contents with
+ // InputConnectionCompat#commitContent() if they match "image/jpeg".
+ layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/jpeg"}));
+
+ // This declares that the IME can commit contents with
+ // InputConnectionCompat#commitContent() if they match "image/webp".
+ layout.addView(createEditTextWithContentMimeTypes(new String[]{"image/webp"}));
+
+ // This declares that the IME can commit contents with
+ // InputConnectionCompat#commitContent() if they match "image/png", "image/gif",
+ // "image/jpeg", or "image/webp".
+ layout.addView(createEditTextWithContentMimeTypes(
+ new String[]{"image/png", "image/gif", "image/jpeg", "image/webp"}));
+
+ mWebView = (WebView) findViewById(R.id.commit_content_webview);
+ mMimeTypes = (TextView) findViewById(R.id.text_commit_content_mime_types);
+ mLabel = (TextView) findViewById(R.id.text_commit_content_label);
+ mContentUri = (TextView) findViewById(R.id.text_commit_content_content_uri);
+ mLinkUri = (TextView) findViewById(R.id.text_commit_content_link_uri);
+ mFlags = (TextView) findViewById(R.id.text_commit_content_link_flags);
+
+ if (savedInstanceState != null) {
+ final InputContentInfoCompat previousInputContentInfo = InputContentInfoCompat.wrap(
+ savedInstanceState.getParcelable(INPUT_CONTENT_INFO_KEY));
+ final int previousFlags = savedInstanceState.getInt(COMMIT_CONTENT_FLAGS_KEY);
+ if (previousInputContentInfo != null) {
+ onCommitContentInternal(previousInputContentInfo, previousFlags);
+ }
+ }
+ }
+
+ private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags,
+ Bundle opts, String[] contentMimeTypes) {
+ // Clear the temporary permission (if any). See below about why we do this here.
+ try {
+ if (mCurrentInputContentInfo != null) {
+ mCurrentInputContentInfo.releasePermission();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "InputContentInfo#releasePermission() failed.", e);
+ } finally {
+ mCurrentInputContentInfo = null;
+ }
+
+ mWebView.loadUrl("about:blank");
+ mMimeTypes.setText("");
+ mContentUri.setText("");
+ mLabel.setText("");
+ mLinkUri.setText("");
+ mFlags.setText("");
+
+ boolean supported = false;
+ for (final String mimeType : contentMimeTypes) {
+ if (inputContentInfo.getDescription().hasMimeType(mimeType)) {
+ supported = true;
+ break;
+ }
+ }
+ if (!supported) {
+ return false;
+ }
+
+ return onCommitContentInternal(inputContentInfo, flags);
+ }
+
+ private boolean onCommitContentInternal(InputContentInfoCompat inputContentInfo, int flags) {
+ if ((flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+ try {
+ inputContentInfo.requestPermission();
+ } catch (Exception e) {
+ Log.e(TAG, "InputContentInfo#requestPermission() failed.", e);
+ return false;
+ }
+ }
+
+ mMimeTypes.setText(
+ Arrays.toString(inputContentInfo.getDescription().filterMimeTypes("*/*")));
+ mContentUri.setText(inputContentInfo.getContentUri().toString());
+ mLabel.setText(inputContentInfo.getDescription().getLabel());
+ Uri linkUri = inputContentInfo.getLinkUri();
+ mLinkUri.setText(linkUri != null ? linkUri.toString() : "null");
+ mFlags.setText(flagsToString(flags));
+ mWebView.loadUrl(inputContentInfo.getContentUri().toString());
+ mWebView.setBackgroundColor(Color.TRANSPARENT);
+
+ // Due to the asynchronous nature of WebView, it is a bit too early to call
+ // inputContentInfo.releasePermission() here. Hence we call IC#releasePermission() when this
+ // method is called next time. Note that calling IC#releasePermission() is just to be a
+ // good citizen. Even if we failed to call that method, the system would eventually revoke
+ // the permission sometime after inputContentInfo object gets garbage-collected.
+ mCurrentInputContentInfo = inputContentInfo;
+ mCurrentFlags = flags;
+
+ return true;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ if (mCurrentInputContentInfo != null) {
+ savedInstanceState.putParcelable(INPUT_CONTENT_INFO_KEY,
+ (Parcelable) mCurrentInputContentInfo.unwrap());
+ savedInstanceState.putInt(COMMIT_CONTENT_FLAGS_KEY, mCurrentFlags);
+ }
+ mCurrentInputContentInfo = null;
+ mCurrentFlags = 0;
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ /**
+ * Creates a new instance of {@link EditText} that is configured to specify the given content
+ * MIME types to {@link EditorInfo#contentMimeTypes} so that developers
+ * can locally test how the current input method behaves for such content MIME types.
+ *
+ * @param contentMimeTypes A {@link String} array that indicates the supported content MIME
+ * types
+ * @return a new instance of {@link EditText}, which specifies
+ * {@link EditorInfo#contentMimeTypes} with the given content
+ * MIME types
+ */
+ private EditText createEditTextWithContentMimeTypes(String[] contentMimeTypes) {
+ final CharSequence hintText;
+ final String[] mimeTypes; // our own copy of contentMimeTypes.
+ if (contentMimeTypes == null || contentMimeTypes.length == 0) {
+ hintText = "MIME: []";
+ mimeTypes = new String[0];
+ } else {
+ hintText = "MIME: " + Arrays.toString(contentMimeTypes);
+ mimeTypes = Arrays.copyOf(contentMimeTypes, contentMimeTypes.length);
+ }
+ EditText exitText = new EditText(this) {
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
+ final InputConnection ic = super.onCreateInputConnection(editorInfo);
+ EditorInfoCompat.setContentMimeTypes(editorInfo, mimeTypes);
+ final InputConnectionCompat.OnCommitContentListener callback =
+ new InputConnectionCompat.OnCommitContentListener() {
+ @Override
+ public boolean onCommitContent(InputContentInfoCompat inputContentInfo,
+ int flags, Bundle opts) {
+ return CommitContentSupport.this.onCommitContent(
+ inputContentInfo, flags, opts, mimeTypes);
+ }
+ };
+ return InputConnectionCompat.createWrapper(ic, editorInfo, callback);
+ }
+ };
+ exitText.setHint(hintText);
+ exitText.setTextColor(Color.WHITE);
+ exitText.setHintTextColor(Color.WHITE);
+ return exitText;
+ }
+
+ /**
+ * Converts {@code flags} specified in {@link InputConnectionCompat#commitContent(
+ *InputConnection, EditorInfo, InputContentInfoCompat, int, Bundle)} to a human readable
+ * string.
+ *
+ * @param flags the 2nd parameter of
+ * {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo,
+ * InputContentInfoCompat, int, Bundle)}
+ * @return a human readable string that corresponds to the given {@code flags}
+ */
+ private static String flagsToString(int flags) {
+ final ArrayList<String> tokens = new ArrayList<>();
+ if ((flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+ tokens.add("INPUT_CONTENT_GRANT_READ_URI_PERMISSION");
+ flags &= ~InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
+ }
+ if (flags != 0) {
+ tokens.add("0x" + Integer.toHexString(flags));
+ }
+ return TextUtils.join(" | ", tokens);
+ }
+
+}
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
index 4be078b..8c9d40c 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/accessibility/AccessibilityManagerSupportActivity.java
@@ -23,7 +23,6 @@
import android.os.Bundle;
import android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat;
import android.support.v4.view.accessibility.AccessibilityManagerCompat;
-import android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat;
import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
import android.widget.Toast;
@@ -85,7 +84,7 @@
// platform API version is lower and the called API is not available no listener
// is added and you will not receive a call of onAccessibilityStateChanged.
AccessibilityManagerCompat.addAccessibilityStateChangeListener(mAccessibilityManager,
- new AccessibilityStateChangeListenerCompat() {
+ new AccessibilityManagerCompat.AccessibilityStateChangeListener() {
@Override
public void onAccessibilityStateChanged(boolean enabled) {
Toast.makeText(AccessibilityManagerSupportActivity.this,
@@ -119,7 +118,8 @@
R.string.accessibility_manager_enabled_service,
resolveInfo.loadLabel(getPackageManager()),
AccessibilityServiceInfoCompat.feedbackTypeToString(service.feedbackType),
- AccessibilityServiceInfoCompat.getDescription(service),
+ AccessibilityServiceInfoCompat.loadDescription(
+ service, getPackageManager()),
AccessibilityServiceInfoCompat.getSettingsActivityName(service));
builder.append(serviceDescription);
}
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentArgumentsSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentArgumentsSupport.java
index 8def8af..a9f4439 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentArgumentsSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentArgumentsSupport.java
@@ -16,21 +16,22 @@
package com.example.android.supportv4.app;
-import com.example.android.supportv4.R;
-
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-
-import android.app.Activity;
+import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.example.android.supportv4.R;
+
/**
* Demonstrates a fragment that can be configured through both Bundle arguments
* and layout attributes.
@@ -71,11 +72,11 @@
* Parse attributes during inflation from a view hierarchy into the
* arguments we handle.
*/
- @Override public void onInflate(Activity activity, AttributeSet attrs,
- Bundle savedInstanceState) {
- super.onInflate(activity, attrs, savedInstanceState);
+ @Override
+ public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
+ super.onInflate(context, attrs, savedInstanceState);
- TypedArray a = activity.obtainStyledAttributes(attrs,
+ TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.FragmentArguments);
mLabel = a.getText(R.styleable.FragmentArguments_android_label);
a.recycle();
@@ -85,7 +86,8 @@
* During creation, if arguments have been supplied to the fragment
* then parse those out.
*/
- @Override public void onCreate(Bundle savedInstanceState) {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
@@ -100,12 +102,14 @@
/**
* Create the view for this fragment, using the arguments given to it.
*/
- @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.hello_world, container, false);
View tv = v.findViewById(R.id.text);
((TextView)tv).setText(mLabel != null ? mLabel : "(no label)");
- tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
+ ViewCompat.setBackground(
+ tv, ContextCompat.getDrawable(getContext(), android.R.drawable.gallery_thumb));
return v;
}
}
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.java b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.java
index cf734d7..66a1b2d 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.java
@@ -15,8 +15,6 @@
*/
package com.example.android.supportv4.app;
-import com.example.android.supportv4.R;
-
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@@ -28,6 +26,8 @@
import android.widget.TabHost;
import android.widget.TabWidget;
+import com.example.android.supportv4.R;
+
import java.util.ArrayList;
/**
@@ -125,7 +125,7 @@
mViewPager = pager;
mTabHost.setOnTabChangedListener(this);
mViewPager.setAdapter(this);
- mViewPager.setOnPageChangeListener(this);
+ mViewPager.addOnPageChangeListener(this);
}
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
index 312aba4..d858fae 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/app/LoaderCustomSupport.java
@@ -37,8 +37,6 @@
import android.support.v4.content.pm.ActivityInfoCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SearchViewCompat;
-import android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat;
-import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -411,8 +409,6 @@
// If non-null, this is the current filter the user has provided.
String mCurFilter;
- OnQueryTextListenerCompat mOnQueryTextListenerCompat;
-
@Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -444,18 +440,23 @@
final View searchView = SearchViewCompat.newSearchView(getActivity());
if (searchView != null) {
SearchViewCompat.setOnQueryTextListener(searchView,
- new OnQueryTextListenerCompat() {
- @Override
- public boolean onQueryTextChange(String newText) {
- // Called when the action bar search text has changed. Since this
- // is a simple array adapter, we can just have it do the filtering.
- mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
- mAdapter.getFilter().filter(mCurFilter);
- return true;
- }
- });
+ new SearchViewCompat.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ // Called when the action bar search text has changed. Since this
+ // is a simple array adapter, we can just have it do the filtering.
+ mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
+ mAdapter.getFilter().filter(mCurFilter);
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ return false;
+ }
+ });
SearchViewCompat.setOnCloseListener(searchView,
- new OnCloseListenerCompat() {
+ new SearchViewCompat.OnCloseListener() {
@Override
public boolean onClose() {
if (!TextUtils.isEmpty(SearchViewCompat.getQuery(searchView))) {
@@ -463,8 +464,7 @@
}
return true;
}
-
- });
+ });
MenuItemCompat.setActionView(item, searchView);
}
}
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
index f26e038..b408349 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/SlidingPaneLayoutActivity.java
@@ -29,8 +29,9 @@
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
-import com.example.android.supportv4.Shakespeare;
+
import com.example.android.supportv4.R;
+import com.example.android.supportv4.Shakespeare;
/**
* This example illustrates a common usage of SlidingPaneLayout in the Android support library.
@@ -98,7 +99,7 @@
* as the left pane contains content one level up in the navigation hierarchy.
*/
if (item.getItemId() == android.R.id.home && !mSlidingLayout.isOpen()) {
- mSlidingLayout.smoothSlideOpen();
+ mSlidingLayout.openPane();
return true;
}
return super.onOptionsItemSelected(item);
@@ -114,7 +115,7 @@
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mContent.setText(Shakespeare.DIALOGUE[position]);
mActionBar.setTitle(Shakespeare.TITLES[position]);
- mSlidingLayout.smoothSlideClosed();
+ mSlidingLayout.closePane();
}
}
@@ -206,7 +207,7 @@
@Override
public void onFirstLayout() {
- if (mSlidingLayout.canSlide() && !mSlidingLayout.isOpen()) {
+ if (mSlidingLayout.isSlideable() && !mSlidingLayout.isOpen()) {
onPanelClosed();
} else {
onPanelOpened();
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 066afc3..a416f07 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -389,8 +389,17 @@
</activity>
<activity android:name=".widget.LinearLayoutManagerActivity"
- android:label="@string/linear_layout_manager"
- android:theme="@style/Theme.AppCompat">
+ android:label="@string/linear_layout_manager"
+ android:theme="@style/Theme.AppCompat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".widget.LinearLayoutManagerJankActivity"
+ android:label="@string/linear_layout_manager"
+ android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 4bf046e..ad87a6a 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -144,6 +144,9 @@
<string name="enableAnimations">Animate</string>
<string name="enablePredictiveAnimations">Predictive</string>
<string name="enableInPlaceChange">In Place Change</string>
+ <string name="enable_inflate_slowdown">Slow inflate</string>
+ <string name="enable_bind_slowdown">Slow bind</string>
+ <string name="enable_prefetch">Prefetch</string>
<string name="add_item">Add</string>
<string name="delete_item">Del</string>
<string name="add_delete_item">A+D</string>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/graphics/PaletteActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/graphics/PaletteActivity.java
index e82aa3a..0759e33 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/graphics/PaletteActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/graphics/PaletteActivity.java
@@ -29,6 +29,7 @@
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
+import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ResourceCursorAdapter;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.graphics.Palette;
@@ -190,12 +191,12 @@
ImageView imageView = (ImageView) view.findViewById(R.id.image);
imageView.setImageDrawable(null);
- view.findViewById(R.id.text_vibrant).setBackgroundDrawable(null);
- view.findViewById(R.id.text_muted).setBackgroundDrawable(null);
- view.findViewById(R.id.text_light_vibrant).setBackgroundDrawable(null);
- view.findViewById(R.id.text_light_muted).setBackgroundDrawable(null);
- view.findViewById(R.id.text_dark_vibrant).setBackgroundDrawable(null);
- view.findViewById(R.id.text_dark_muted).setBackgroundDrawable(null);
+ ViewCompat.setBackground(view.findViewById(R.id.text_vibrant), null);
+ ViewCompat.setBackground(view.findViewById(R.id.text_muted), null);
+ ViewCompat.setBackground(view.findViewById(R.id.text_light_vibrant), null);
+ ViewCompat.setBackground(view.findViewById(R.id.text_light_muted), null);
+ ViewCompat.setBackground(view.findViewById(R.id.text_dark_vibrant), null);
+ ViewCompat.setBackground(view.findViewById(R.id.text_dark_muted), null);
final long id = cursor.getLong(
cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID));
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
index 7482e3e..914f1e8 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
@@ -16,11 +16,11 @@
package com.example.android.supportv7.widget;
-import com.example.android.supportv7.widget.decorator.DividerItemDecoration;
-
import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
+
import com.example.android.supportv7.R;
import com.example.android.supportv7.widget.util.ConfigToggle;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerJankActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerJankActivity.java
new file mode 100644
index 0000000..1709d3e
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerJankActivity.java
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+package com.example.android.supportv7.widget;
+
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.ViewGroup;
+
+import com.example.android.supportv7.Cheeses;
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+
+/**
+ * A configurably janky activity that uses {@link LinearLayoutManager}.
+ */
+public class LinearLayoutManagerJankActivity extends LinearLayoutManagerActivity {
+
+ private boolean mBindSlowdownEnabled = true;
+ private boolean mInflateSlowdownEnabled = true;
+
+ /**
+ * Spin wait. Used instead of sleeping so a core is used up for the duration, and so
+ * traces/sampled profiling show the sections as expensive, and not just a scheduling mistake.
+ */
+ private static void spinWaitMs(long ms) {
+ long start = System.nanoTime();
+ while (System.nanoTime() - start < ms * 1000L * 1000L);
+ }
+
+ @Override
+ protected RecyclerView.Adapter createAdapter() {
+ return new SimpleStringAdapter(this, Cheeses.sCheeseStrings) {
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ super.onBindViewHolder(holder, position);
+ if (mBindSlowdownEnabled) spinWaitMs(8);
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (mInflateSlowdownEnabled) spinWaitMs(4);
+ return super.onCreateViewHolder(parent, viewType);
+ }
+ };
+ }
+
+ @Override
+ ConfigToggle[] createConfigToggles() {
+ return new ConfigToggle[]{
+ new ConfigToggle(this, R.string.enable_bind_slowdown) {
+ @Override
+ public boolean isChecked() { return mBindSlowdownEnabled; }
+
+ @Override
+ public void onChange(boolean newValue) { mBindSlowdownEnabled = newValue; }
+ },
+ new ConfigToggle(this, R.string.enable_inflate_slowdown) {
+ @Override
+ public boolean isChecked() { return mInflateSlowdownEnabled; }
+
+ @Override
+ public void onChange(boolean newValue) { mInflateSlowdownEnabled = newValue; }
+ },
+ new ConfigToggle(this, R.string.enable_prefetch) {
+ @Override
+ public boolean isChecked() { return mLayoutManager.isItemPrefetchEnabled(); }
+
+ @Override
+ public void onChange(boolean newValue) {
+ mLayoutManager.setItemPrefetchEnabled(newValue);
+ }
+ },
+ };
+ }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
index 38b50bd..a49ddbe 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
@@ -17,14 +17,11 @@
package com.example.android.supportv7.widget;
-import com.example.android.supportv7.Cheeses;
-import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
-import com.example.android.supportv7.widget.decorator.DividerItemDecoration;
-
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
+import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.Menu;
@@ -32,6 +29,9 @@
import android.view.View;
import android.view.ViewGroup;
+import com.example.android.supportv7.Cheeses;
+import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
+
public class RecyclerViewActivity extends Activity {
private static final String TAG = "RecyclerViewActivity";
@@ -68,7 +68,7 @@
return vh;
}
});
- rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
+ rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
setContentView(rv);
mRecyclerView = rv;
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java
deleted file mode 100644
index 4386f4f..0000000
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/decorator/DividerItemDecoration.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.supportv7.widget.decorator;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-
-public class DividerItemDecoration extends RecyclerView.ItemDecoration {
-
- private static final int[] ATTRS = new int[]{
- android.R.attr.listDivider
- };
-
- public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
-
- public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
-
- private Drawable mDivider;
-
- private int mOrientation;
-
- public DividerItemDecoration(Context context, int orientation) {
- final TypedArray a = context.obtainStyledAttributes(ATTRS);
- mDivider = a.getDrawable(0);
- a.recycle();
- setOrientation(orientation);
- }
-
- public void setOrientation(int orientation) {
- if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
- throw new IllegalArgumentException("invalid orientation");
- }
- mOrientation = orientation;
- }
-
- @Override
- public void onDraw(Canvas c, RecyclerView parent) {
- if (mOrientation == VERTICAL_LIST) {
- drawVertical(c, parent);
- } else {
- drawHorizontal(c, parent);
- }
- }
-
- public void drawVertical(Canvas c, RecyclerView parent) {
- final int left = parent.getPaddingLeft();
- final int right = parent.getWidth() - parent.getPaddingRight();
-
- final int childCount = parent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = parent.getChildAt(i);
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
- .getLayoutParams();
- final int top = child.getBottom() + params.bottomMargin +
- Math.round(ViewCompat.getTranslationY(child));
- final int bottom = top + mDivider.getIntrinsicHeight();
- mDivider.setBounds(left, top, right, bottom);
- mDivider.draw(c);
- }
- }
-
- public void drawHorizontal(Canvas c, RecyclerView parent) {
- final int top = parent.getPaddingTop();
- final int bottom = parent.getHeight() - parent.getPaddingBottom();
-
- final int childCount = parent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = parent.getChildAt(i);
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
- .getLayoutParams();
- final int left = child.getRight() + params.rightMargin +
- Math.round(ViewCompat.getTranslationX(child));
- final int right = left + mDivider.getIntrinsicHeight();
- mDivider.setBounds(left, top, right, bottom);
- mDivider.draw(c);
- }
- }
-
- @Override
- public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
- if (mOrientation == VERTICAL_LIST) {
- outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
- } else {
- outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
- }
- }
-}
diff --git a/samples/SupportDesignDemos/Android.mk b/samples/SupportDesignDemos/Android.mk
index de9e302..8ae120e 100644
--- a/samples/SupportDesignDemos/Android.mk
+++ b/samples/SupportDesignDemos/Android.mk
@@ -28,16 +28,19 @@
android-support-v4 \
android-support-v7-appcompat \
android-support-v7-recyclerview \
+ android-support-transition \
android-support-design
LOCAL_RESOURCE_DIR = \
$(LOCAL_PATH)/res \
frameworks/support/v7/appcompat/res \
frameworks/support/v7/recyclerview/res \
+ frameworks/support/transition/res \
frameworks/support/design/res
LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
--extra-packages android.support.v7.appcompat \
--extra-packages android.support.v7.recyclerview \
+ --extra-packages android.support.transition \
--extra-packages android.support.design \
--no-version-vectors
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/samples/SupportDesignDemos/AndroidManifest.xml b/samples/SupportDesignDemos/AndroidManifest.xml
index 0ee0470..13071ea 100644
--- a/samples/SupportDesignDemos/AndroidManifest.xml
+++ b/samples/SupportDesignDemos/AndroidManifest.xml
@@ -291,6 +291,14 @@
</intent-filter>
</activity>
+ <activity android:name=".widget.BottomNavigationViewUsage"
+ android:label="@string/design_bottom_navigation_view">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.support.design.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
<activity android:name=".widget.CoordinatorLayoutInset"
android:label="@string/design_coordinatorlayout_insetView"
android:theme="@style/Theme.Design">
diff --git a/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml b/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml
new file mode 100644
index 0000000..83e7314
--- /dev/null
+++ b/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+<RelativeLayout
+ 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="match_parent">
+
+ <Button
+ android:id="@+id/button_disable"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bottomnavigation_disable"/>
+
+ <Button
+ android:id="@+id/button_add"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bottomnavigation_add"
+ android:layout_below="@+id/button_disable"/>
+
+ <Button
+ android:id="@+id/button_remove"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bottomnavigation_remove"
+ android:layout_below="@+id/button_add"/>
+
+ <Button
+ android:id="@+id/button_tint"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bottomnavigation_tint"
+ android:layout_below="@+id/button_remove"/>
+
+ <android.support.design.widget.BottomNavigationView
+ android:id="@+id/bottom_navigation"
+ android:layout_width="match_parent"
+ android:layout_height="56dp"
+ android:layout_gravity="bottom"
+ android:background="#eee"
+ android:layout_alignParentBottom="true"
+ app:menu="@menu/sample_bottom_menu"/>
+
+</RelativeLayout>
diff --git a/samples/SupportDesignDemos/res/values/strings.xml b/samples/SupportDesignDemos/res/values/strings.xml
index a6a1bc9..95900ca 100644
--- a/samples/SupportDesignDemos/res/values/strings.xml
+++ b/samples/SupportDesignDemos/res/values/strings.xml
@@ -124,6 +124,7 @@
<string name="design_bottom_navigation_view">Bottom navigation view</string>
<string name="bottomnavigation_disable">Disable item</string>
- <string name="bottomnavigation_add">Add item</string>
+ <string name="bottomnavigation_add">Add an item</string>
+ <string name="bottomnavigation_remove">Remove an item</string>
<string name="bottomnavigation_tint">Toggle tint</string>
</resources>
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java
new file mode 100644
index 0000000..72b50db
--- /dev/null
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package com.example.android.support.design.widget;
+
+import android.content.res.ColorStateList;
+import android.os.Bundle;
+import android.support.design.widget.BottomNavigationView;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+
+import com.example.android.support.design.R;
+
+/**
+ * This demonstrates idiomatic usage of the bottom navigation widget.
+ */
+public class BottomNavigationViewUsage extends AppCompatActivity {
+ private ColorStateList mOriginalTint;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.design_bottom_navigation_view);
+ Button buttonDisable = (Button) findViewById(R.id.button_disable);
+ final BottomNavigationView bottom =
+ (BottomNavigationView) findViewById(R.id.bottom_navigation);
+ mOriginalTint = bottom.getItemIconTintList();
+ buttonDisable.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ bottom.getMenu().getItem(0).setEnabled(!bottom.getMenu().getItem(0).isEnabled());
+ }
+ });
+ Button buttonAdd = (Button) findViewById(R.id.button_add);
+ buttonAdd.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (bottom.getMenu().size() < 5) {
+ MenuItem item = bottom.getMenu().add("Bananas");
+ item.setIcon(android.R.drawable.ic_lock_power_off);
+ }
+ }
+ });
+ Button buttonRemove = (Button) findViewById(R.id.button_remove);
+ buttonRemove.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ bottom.getMenu().removeItem(0);
+ }
+ });
+ Button buttonTint = (Button) findViewById(R.id.button_tint);
+ buttonTint.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (bottom.getItemIconTintList() == null) {
+ bottom.setItemIconTintList(mOriginalTint);
+ } else {
+ bottom.setItemIconTintList(null);
+ }
+ }
+ });
+ }
+}
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
index ea8b4d6..12e1842 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutPreselectedUsage.java
@@ -20,6 +20,7 @@
import android.support.design.widget.TabLayout;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
+import android.support.v4.widget.TextViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
@@ -147,7 +148,7 @@
final TextView tv = new TextView(container.getContext());
tv.setText(getPageTitle(position));
tv.setGravity(Gravity.CENTER);
- tv.setTextAppearance(tv.getContext(), R.style.TextAppearance_AppCompat_Title);
+ TextViewCompat.setTextAppearance(tv, R.style.TextAppearance_AppCompat_Title);
container.addView(tv, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java
index 26b6108..387e1a0 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/TabLayoutUsage.java
@@ -23,6 +23,7 @@
import android.support.design.widget.TabLayout;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
+import android.support.v4.widget.TextViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
@@ -166,7 +167,7 @@
final TextView tv = new TextView(container.getContext());
tv.setText(getPageTitle(position));
tv.setGravity(Gravity.CENTER);
- tv.setTextAppearance(tv.getContext(), R.style.TextAppearance_AppCompat_Title);
+ TextViewCompat.setTextAppearance(tv, R.style.TextAppearance_AppCompat_Title);
container.addView(tv, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
diff --git a/samples/SupportPreferenceDemos/Android.mk b/samples/SupportPreferenceDemos/Android.mk
new file mode 100644
index 0000000..f131aa0
--- /dev/null
+++ b/samples/SupportPreferenceDemos/Android.mk
@@ -0,0 +1,61 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build the samples.
+# We need to add some special AAPT flags to generate R classes
+# for resources that are included from the libraries.
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := SupportPreferenceDemos
+LOCAL_MODULE_TAGS := samples
+
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 14
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES += \
+ android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-preference \
+ android-support-v7-recyclerview \
+ android-support-v14-preference \
+ android-support-v17-leanback \
+ android-support-v17-preference-leanback \
+
+LOCAL_RESOURCE_DIR = \
+ $(LOCAL_PATH)/res \
+ frameworks/support/v7/appcompat/res \
+ frameworks/support/v7/preference/res \
+ frameworks/support/v7/recyclerview/res \
+ frameworks/support/v14/preference/res \
+ frameworks/support/v17/leanback/res \
+ frameworks/support/v17/preference-leanback/res
+
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay \
+ --extra-packages android.support.v7.appcompat \
+ --extra-packages android.support.v7.preference \
+ --extra-packages android.support.v7.recyclerview \
+ --extra-packages android.support.v14.preference \
+ --extra-packages android.support.v17.leanback \
+ --extra-packages android.support.v17.preference \
+ --no-version-vectors
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
diff --git a/samples/SupportPreferenceDemos/proguard.flags b/samples/SupportPreferenceDemos/proguard.flags
new file mode 100644
index 0000000..9ebd737
--- /dev/null
+++ b/samples/SupportPreferenceDemos/proguard.flags
@@ -0,0 +1,7 @@
+-keep public class * extends android.support.design.widget.CoordinatorLayout$Behavior {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keep public class * extends android.support.v7.widget.LinearLayoutManager {
+ public <init>(android.content.Context, android.util.AttributeSet, int, int);
+}
diff --git a/samples/SupportTransitionDemos/Android.mk b/samples/SupportTransitionDemos/Android.mk
index 1d077a2..abc1ad9 100644
--- a/samples/SupportTransitionDemos/Android.mk
+++ b/samples/SupportTransitionDemos/Android.mk
@@ -21,6 +21,8 @@
LOCAL_PACKAGE_NAME := SupportTransitionDemos
LOCAL_MODULE_TAGS := samples
LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 14
+LOCAL_DEX_PREOPT := false
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v4 \
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index bfdb396..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
- android-support-v4 \
- mockito-target
-
-LOCAL_PACKAGE_NAME := AndroidSupportTests
-
-include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
deleted file mode 100644
index 35314ae..0000000
--- a/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.support.tests">
-
- <application>
- <uses-library android:name="android.test.runner" />
-
- <activity android:name="android.support.tests.GrantActivity" android:label="_GrantActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- </application>
-
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="android.support.tests" />
-
-</manifest>
diff --git a/transition/ics/android/support/transition/TransitionManagerPort.java b/transition/ics/android/support/transition/TransitionManagerPort.java
index 7857f57..d6ca154 100644
--- a/transition/ics/android/support/transition/TransitionManagerPort.java
+++ b/transition/ics/android/support/transition/TransitionManagerPort.java
@@ -132,7 +132,7 @@
if (runningTransitions != null && runningTransitions.size() > 0) {
for (TransitionPort runningTransition : runningTransitions) {
- runningTransition.pause();
+ runningTransition.pause(sceneRoot);
}
}
@@ -397,7 +397,7 @@
ArrayList<TransitionPort> runningTransitions = getRunningTransitions().get(mSceneRoot);
if (runningTransitions != null && runningTransitions.size() > 0) {
for (TransitionPort runningTransition : runningTransitions) {
- runningTransition.resume();
+ runningTransition.resume(mSceneRoot);
}
}
mTransition.clearValues(true);
@@ -430,7 +430,7 @@
mTransition.captureValues(mSceneRoot, false);
if (previousRunningTransitions != null) {
for (TransitionPort runningTransition : previousRunningTransitions) {
- runningTransition.resume();
+ runningTransition.resume(mSceneRoot);
}
}
mTransition.playTransition(mSceneRoot);
diff --git a/transition/ics/android/support/transition/TransitionPort.java b/transition/ics/android/support/transition/TransitionPort.java
index 31b4221..f6c3346 100644
--- a/transition/ics/android/support/transition/TransitionPort.java
+++ b/transition/ics/android/support/transition/TransitionPort.java
@@ -343,7 +343,8 @@
view = start.view;
}
if (animator != null) {
- AnimationInfo info = new AnimationInfo(view, getName(), infoValues);
+ AnimationInfo info = new AnimationInfo(view, getName(),
+ WindowIdPort.getWindowId(sceneRoot), infoValues);
runningAnimators.put(animator, info);
mAnimators.add(animator);
}
@@ -788,13 +789,17 @@
*
* @hide
*/
- public void pause() {
+ public void pause(View sceneRoot) {
if (!mEnded) {
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
int numOldAnims = runningAnimators.size();
+ WindowIdPort windowId = WindowIdPort.getWindowId(sceneRoot);
for (int i = numOldAnims - 1; i >= 0; i--) {
- Animator anim = runningAnimators.keyAt(i);
-// anim.pause();
+ AnimationInfo info = runningAnimators.valueAt(i);
+ if (info.view != null && windowId.equals(info.windowId)) {
+ Animator anim = runningAnimators.keyAt(i);
+ anim.cancel(); // pause() is API Level 19
+ }
}
if (mListeners != null && mListeners.size() > 0) {
ArrayList<TransitionListener> tmpListeners =
@@ -815,14 +820,18 @@
*
* @hide
*/
- public void resume() {
+ public void resume(View sceneRoot) {
if (mPaused) {
if (!mEnded) {
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
int numOldAnims = runningAnimators.size();
+ WindowIdPort windowId = WindowIdPort.getWindowId(sceneRoot);
for (int i = numOldAnims - 1; i >= 0; i--) {
- Animator anim = runningAnimators.keyAt(i);
-// anim.resume();
+ AnimationInfo info = runningAnimators.valueAt(i);
+ if (info.view != null && windowId.equals(info.windowId)) {
+ Animator anim = runningAnimators.keyAt(i);
+ anim.end(); // resume() is API Level 19
+ }
}
if (mListeners != null && mListeners.size() > 0) {
ArrayList<TransitionListener> tmpListeners =
@@ -1211,10 +1220,13 @@
TransitionValues values;
- AnimationInfo(View view, String name, TransitionValues values) {
+ WindowIdPort windowId;
+
+ AnimationInfo(View view, String name, WindowIdPort windowId, TransitionValues values) {
this.view = view;
this.name = name;
this.values = values;
+ this.windowId = windowId;
}
}
diff --git a/transition/ics/android/support/transition/TransitionSetPort.java b/transition/ics/android/support/transition/TransitionSetPort.java
index eab84c9..97985a5 100644
--- a/transition/ics/android/support/transition/TransitionSetPort.java
+++ b/transition/ics/android/support/transition/TransitionSetPort.java
@@ -232,21 +232,21 @@
/** @hide */
@Override
- public void pause() {
- super.pause();
+ public void pause(View sceneRoot) {
+ super.pause(sceneRoot);
int numTransitions = mTransitions.size();
for (int i = 0; i < numTransitions; ++i) {
- mTransitions.get(i).pause();
+ mTransitions.get(i).pause(sceneRoot);
}
}
/** @hide */
@Override
- public void resume() {
- super.resume();
+ public void resume(View sceneRoot) {
+ super.resume(sceneRoot);
int numTransitions = mTransitions.size();
for (int i = 0; i < numTransitions; ++i) {
- mTransitions.get(i).resume();
+ mTransitions.get(i).resume(sceneRoot);
}
}
diff --git a/transition/ics/android/support/transition/WindowIdPort.java b/transition/ics/android/support/transition/WindowIdPort.java
new file mode 100644
index 0000000..f768b2e
--- /dev/null
+++ b/transition/ics/android/support/transition/WindowIdPort.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package android.support.transition;
+
+import android.os.IBinder;
+import android.support.annotation.NonNull;
+import android.view.View;
+
+
+/**
+ * Backport of WindowId.
+ *
+ * <p>Since the use of WindowId in Transition API is limited to identifying windows, we can just
+ * wrap a window token and use it as an identifier.</p>
+ */
+class WindowIdPort {
+
+ private final IBinder mToken;
+
+ private WindowIdPort(IBinder token) {
+ mToken = token;
+ }
+
+ static WindowIdPort getWindowId(@NonNull View view) {
+ return new WindowIdPort(view.getWindowToken());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof WindowIdPort && ((WindowIdPort) obj).mToken.equals(this.mToken);
+ }
+
+}
diff --git a/transition/tests/src/android/support/transition/FadeTest.java b/transition/tests/src/android/support/transition/FadeTest.java
index f8760af..0ebd6cc 100644
--- a/transition/tests/src/android/support/transition/FadeTest.java
+++ b/transition/tests/src/android/support/transition/FadeTest.java
@@ -24,13 +24,14 @@
import android.animation.Animator;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
import android.view.ViewGroup;
import org.junit.Before;
import org.junit.Test;
-
+@MediumTest
public class FadeTest extends BaseTest {
private View mView;
diff --git a/transition/tests/src/android/support/transition/SceneTest.java b/transition/tests/src/android/support/transition/SceneTest.java
index 0ba0fb3..6333d59 100644
--- a/transition/tests/src/android/support/transition/SceneTest.java
+++ b/transition/tests/src/android/support/transition/SceneTest.java
@@ -20,6 +20,7 @@
import android.support.test.annotation.UiThreadTest;
import android.support.transition.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -28,6 +29,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.sameInstance;
+@MediumTest
public class SceneTest extends BaseTest {
@Test
diff --git a/transition/tests/src/android/support/transition/TransitionManagerTest.java b/transition/tests/src/android/support/transition/TransitionManagerTest.java
index a51450e..e07f333 100644
--- a/transition/tests/src/android/support/transition/TransitionManagerTest.java
+++ b/transition/tests/src/android/support/transition/TransitionManagerTest.java
@@ -24,6 +24,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.transition.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.ViewGroup;
import org.junit.Before;
@@ -32,6 +33,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+@MediumTest
public class TransitionManagerTest extends BaseTest {
private Scene[] mScenes = new Scene[2];
diff --git a/transition/tests/src/android/support/transition/TransitionTest.java b/transition/tests/src/android/support/transition/TransitionTest.java
index 9620837..1fe9474 100644
--- a/transition/tests/src/android/support/transition/TransitionTest.java
+++ b/transition/tests/src/android/support/transition/TransitionTest.java
@@ -26,6 +26,7 @@
import android.animation.TimeInterpolator;
import android.support.test.annotation.UiThreadTest;
import android.support.transition.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -35,6 +36,7 @@
import java.util.List;
+@MediumTest
public class TransitionTest extends BaseTest {
@Test
diff --git a/v13/Android.mk b/v13/Android.mk
index 6436768..e1e6062 100644
--- a/v13/Android.mk
+++ b/v13/Android.mk
@@ -52,6 +52,15 @@
LOCAL_JAVA_LANGUAGE_VERSION := 1.7
include $(BUILD_STATIC_JAVA_LIBRARY)
+# A helper sub-library that makes direct use of NYC MR-1 APIs.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v13-nyc-mr1
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, api25)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13-nyc
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
# -----------------------------------------------------------------------
include $(CLEAR_VARS)
@@ -61,7 +70,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, java)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 \
- android-support-v13-nyc
+ android-support-v13-nyc-mr1
LOCAL_JAVA_LANGUAGE_VERSION := 1.7
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.java
new file mode 100644
index 0000000..e5d20a5
--- /dev/null
+++ b/v13/api25/android/support/v13/view/inputmethod/EditorInfoCompatApi25.java
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.os.Bundle;
+import android.view.inputmethod.EditorInfo;
+
+final class EditorInfoCompatApi25 {
+ public static void setContentMimeTypes(EditorInfo editorInfo, String[] contentMimeTypes) {
+ editorInfo.contentMimeTypes = contentMimeTypes;
+ }
+
+ public static String[] getContentMimeTypes(EditorInfo editorInfo) {
+ return editorInfo.contentMimeTypes;
+ }
+}
diff --git a/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java
new file mode 100644
index 0000000..a29bedd
--- /dev/null
+++ b/v13/api25/android/support/v13/view/inputmethod/InputConnectionCompatApi25.java
@@ -0,0 +1,50 @@
+/**
+ * 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.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.os.Bundle;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
+import android.view.inputmethod.InputContentInfo;
+
+final class InputConnectionCompatApi25 {
+
+ public static boolean commitContent(InputConnection ic, Object inputContentInfo, int flags,
+ Bundle opts) {
+ return ic.commitContent((InputContentInfo)inputContentInfo, flags, opts);
+ }
+
+ public interface OnCommitContentListener {
+ boolean onCommitContent(Object inputContentInfo, int flags, Bundle opts);
+ }
+
+ public static InputConnection createWrapper(InputConnection ic,
+ final OnCommitContentListener onCommitContentListener) {
+ return new InputConnectionWrapper(ic, false /* mutable */) {
+ @Override
+ public boolean commitContent(InputContentInfo inputContentInfo, int flags,
+ Bundle opts) {
+ if (onCommitContentListener.onCommitContent(inputContentInfo, flags, opts)) {
+ return true;
+ }
+ return super.commitContent(inputContentInfo, flags, opts);
+ }
+ };
+ }
+
+}
diff --git a/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
new file mode 100644
index 0000000..c485ca6
--- /dev/null
+++ b/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Parcel;
+import android.view.inputmethod.InputContentInfo;
+
+final class InputContentInfoCompatApi25 {
+
+ public static Object create(Uri contentUri, ClipDescription description, Uri linkUri) {
+ return new InputContentInfo(contentUri, description, linkUri);
+ }
+
+ public static Uri getContentUri(Object inputContentInfo) {
+ return ((InputContentInfo) inputContentInfo).getContentUri();
+ }
+
+ public static ClipDescription getDescription(Object inputContentInfo) {
+ return ((InputContentInfo) inputContentInfo).getDescription();
+ }
+
+ public static Uri getLinkUri(Object inputContentInfo) {
+ return ((InputContentInfo) inputContentInfo).getLinkUri();
+ }
+
+ public static void requestPermission(Object inputContentInfo) {
+ ((InputContentInfo) inputContentInfo).requestPermission();
+ }
+
+ public static void releasePermission(Object inputContentInfo) {
+ ((InputContentInfo) inputContentInfo).requestPermission();
+ }
+}
diff --git a/v13/java/android/support/v13/app/ActivityCompat.java b/v13/java/android/support/v13/app/ActivityCompat.java
index e2a8a2c..8059a68 100644
--- a/v13/java/android/support/v13/app/ActivityCompat.java
+++ b/v13/java/android/support/v13/app/ActivityCompat.java
@@ -39,5 +39,7 @@
return DragAndDropPermissionsCompat.request(activity, dragEvent);
}
- private ActivityCompat() {}
+ protected ActivityCompat() {
+ // Not publicly instantiable, but may be extended.
+ }
}
diff --git a/v13/java/android/support/v13/app/FragmentTabHost.java b/v13/java/android/support/v13/app/FragmentTabHost.java
index c010b4f..6cfd0ad 100644
--- a/v13/java/android/support/v13/app/FragmentTabHost.java
+++ b/v13/java/android/support/v13/app/FragmentTabHost.java
@@ -51,10 +51,10 @@
private boolean mAttached;
static final class TabInfo {
- private final String tag;
- private final Class<?> clss;
- private final Bundle args;
- private Fragment fragment;
+ final String tag;
+ final Class<?> clss;
+ final Bundle args;
+ Fragment fragment;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
@@ -86,7 +86,7 @@
super(superState);
}
- private SavedState(Parcel in) {
+ SavedState(Parcel in) {
super(in);
curTab = in.readString();
}
diff --git a/v13/java/android/support/v13/view/ViewCompat.java b/v13/java/android/support/v13/view/ViewCompat.java
index 38db5fa..971d70d 100644
--- a/v13/java/android/support/v13/view/ViewCompat.java
+++ b/v13/java/android/support/v13/view/ViewCompat.java
@@ -33,6 +33,9 @@
}
private static class BaseViewCompatImpl implements ViewCompatImpl {
+ BaseViewCompatImpl() {
+ }
+
@Override
public boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
Object localState, int flags) {
@@ -51,6 +54,9 @@
}
private static class Api24ViewCompatImpl implements ViewCompatImpl {
+ Api24ViewCompatImpl() {
+ }
+
@Override
public boolean startDragAndDrop(View v, ClipData data, View.DragShadowBuilder shadowBuilder,
Object localState, int flags) {
diff --git a/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java b/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
new file mode 100644
index 0000000..c1bffd4
--- /dev/null
+++ b/v13/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
@@ -0,0 +1,116 @@
+/**
+ * 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.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+public final class EditorInfoCompat {
+
+ private interface EditorInfoCompatImpl {
+ void setContentMimeTypes(@NonNull EditorInfo editorInfo,
+ @Nullable String[] contentMimeTypes);
+ @NonNull
+ String[] getContentMimeTypes(@NonNull EditorInfo editorInfo);
+ }
+
+ private final static String[] EMPTY_STRING_ARRAY = new String[0];
+
+ private final static class BaseEditorInfoCompatImpl implements EditorInfoCompatImpl {
+ private static String CONTENT_MIME_TYPES_KEY =
+ "android.support.v13.view.inputmethod.EditorInfoCompat.CONTENT_MIME_TYPES";
+
+ @Override
+ public void setContentMimeTypes(@NonNull EditorInfo editorInfo,
+ @Nullable String[] contentMimeTypes) {
+ if (editorInfo.extras == null) {
+ editorInfo.extras = new Bundle();
+ }
+ editorInfo.extras.putStringArray(CONTENT_MIME_TYPES_KEY, contentMimeTypes);
+ }
+
+ @NonNull
+ @Override
+ public String[] getContentMimeTypes(@NonNull EditorInfo editorInfo) {
+ if (editorInfo.extras == null) {
+ return EMPTY_STRING_ARRAY;
+ }
+ String[] result = editorInfo.extras.getStringArray(CONTENT_MIME_TYPES_KEY);
+ return result != null ? result : EMPTY_STRING_ARRAY;
+ }
+ }
+
+ private final static class Api25EditorInfoCompatImpl implements EditorInfoCompatImpl {
+ @Override
+ public void setContentMimeTypes(@NonNull EditorInfo editorInfo,
+ @Nullable String[] contentMimeTypes) {
+ EditorInfoCompatApi25.setContentMimeTypes(editorInfo, contentMimeTypes);
+ }
+
+ @NonNull
+ @Override
+ public String[] getContentMimeTypes(@NonNull EditorInfo editorInfo) {
+ String[] result = EditorInfoCompatApi25.getContentMimeTypes(editorInfo);
+ return result != null ? result : EMPTY_STRING_ARRAY;
+ }
+ }
+
+ private static final EditorInfoCompatImpl IMPL;
+ static {
+ if (BuildCompat.isAtLeastNMR1()) {
+ IMPL = new Api25EditorInfoCompatImpl();
+ } else {
+ IMPL = new BaseEditorInfoCompatImpl();
+ }
+ }
+
+ /**
+ * Sets MIME types that can be accepted by the target editor if the IME calls
+ * {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo,
+ * InputContentInfoCompat, int, Bundle)}.
+ *
+ * @param editorInfo the editor with which we associate supported MIME types
+ * @param contentMimeTypes an array of MIME types. {@code null} and an empty array means that
+ * {@link InputConnectionCompat#commitContent(
+ * InputConnection, EditorInfo, InputContentInfoCompat, int, Bundle)
+ * is not supported on this Editor
+ */
+ public static void setContentMimeTypes(@NonNull EditorInfo editorInfo,
+ @Nullable String[] contentMimeTypes) {
+ IMPL.setContentMimeTypes(editorInfo, contentMimeTypes);
+ }
+
+ /**
+ * Gets MIME types that can be accepted by the target editor if the IME calls
+ * {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo,
+ * InputContentInfoCompat, int, Bundle)}
+ *
+ * @param editorInfo the editor from which we get the MIME types
+ * @return an array of MIME types. An empty array means that {@link
+ * InputConnectionCompat#commitContent(InputConnection, EditorInfo, InputContentInfoCompat,
+ * int, Bundle)} is not supported on this editor
+ */
+ @NonNull
+ public static String[] getContentMimeTypes(EditorInfo editorInfo) {
+ return IMPL.getContentMimeTypes(editorInfo);
+ }
+
+}
diff --git a/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java b/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
new file mode 100644
index 0000000..b740502
--- /dev/null
+++ b/v13/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
@@ -0,0 +1,281 @@
+/**
+ * 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.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
+import android.text.TextUtils;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
+
+/**
+ * Helper for accessing features in {@link InputConnection} introduced after API level 13 in a
+ * backwards compatible fashion.
+ */
+public final class InputConnectionCompat {
+
+ private interface InputConnectionCompatImpl {
+ boolean commitContent(@NonNull InputConnection inputConnection,
+ @NonNull InputContentInfoCompat inputContentInfo, int flags, @Nullable Bundle opts);
+
+ @NonNull
+ InputConnection createWrapper(@NonNull InputConnection ic,
+ @NonNull EditorInfo editorInfo, @NonNull OnCommitContentListener callback);
+ }
+
+ static final class BaseInputContentInfoCompatImpl implements InputConnectionCompatImpl {
+
+ private static String COMMIT_CONTENT_ACTION =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.COMMIT_CONTENT";
+ private static String COMMIT_CONTENT_CONTENT_URI_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_URI";
+ private static String COMMIT_CONTENT_DESCRIPTION_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_DESCRIPTION";
+ private static String COMMIT_CONTENT_LINK_URI_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_LINK_URI";
+ private static String COMMIT_CONTENT_OPTS_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_OPTS";
+ private static String COMMIT_CONTENT_FLAGS_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_FLAGS";
+ private static String COMMIT_CONTENT_RESULT_RECEIVER =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_RESULT_RECEIVER";
+
+ @Override
+ public boolean commitContent(@NonNull InputConnection inputConnection,
+ @NonNull InputContentInfoCompat inputContentInfo, int flags,
+ @Nullable Bundle opts) {
+ final Bundle params = new Bundle();
+ params.putParcelable(COMMIT_CONTENT_CONTENT_URI_KEY, inputContentInfo.getContentUri());
+ params.putParcelable(COMMIT_CONTENT_DESCRIPTION_KEY, inputContentInfo.getDescription());
+ params.putParcelable(COMMIT_CONTENT_LINK_URI_KEY, inputContentInfo.getLinkUri());
+ params.putInt(COMMIT_CONTENT_FLAGS_KEY, flags);
+ params.putParcelable(COMMIT_CONTENT_OPTS_KEY, opts);
+ // TODO: Support COMMIT_CONTENT_RESULT_RECEIVER.
+ return inputConnection.performPrivateCommand(COMMIT_CONTENT_ACTION, params);
+ }
+
+ @NonNull
+ @Override
+ public InputConnection createWrapper(@NonNull InputConnection ic,
+ @NonNull EditorInfo editorInfo,
+ @NonNull OnCommitContentListener onCommitContentListener) {
+ String[] contentMimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo);
+ if (contentMimeTypes.length == 0) {
+ return ic;
+ }
+ final OnCommitContentListener listener = onCommitContentListener;
+ return new InputConnectionWrapper(ic, false /* mutable */) {
+ @Override
+ public boolean performPrivateCommand(String action, Bundle data) {
+ if (BaseInputContentInfoCompatImpl.handlePerformPrivateCommand(action, data,
+ listener)) {
+ return true;
+ }
+ return super.performPrivateCommand(action, data);
+ }
+ };
+ }
+
+ static boolean handlePerformPrivateCommand(
+ @Nullable String action,
+ @NonNull Bundle data,
+ @NonNull OnCommitContentListener onCommitContentListener) {
+ if (!TextUtils.equals(COMMIT_CONTENT_ACTION, action)) {
+ return false;
+ }
+ if (data == null) {
+ return false;
+ }
+ ResultReceiver resultReceiver = null;
+ boolean result = false;
+ try {
+ resultReceiver = data.getParcelable(COMMIT_CONTENT_RESULT_RECEIVER);
+ final Uri contentUri = data.getParcelable(COMMIT_CONTENT_CONTENT_URI_KEY);
+ final ClipDescription description = data.getParcelable(
+ COMMIT_CONTENT_DESCRIPTION_KEY);
+ final Uri linkUri = data.getParcelable(COMMIT_CONTENT_LINK_URI_KEY);
+ final int flags = data.getInt(COMMIT_CONTENT_FLAGS_KEY);
+ final Bundle opts = data.getParcelable(COMMIT_CONTENT_OPTS_KEY);
+ final InputContentInfoCompat inputContentInfo =
+ new InputContentInfoCompat(contentUri, description, linkUri);
+ result = onCommitContentListener.onCommitContent(inputContentInfo, flags, opts);
+ } finally {
+ if (resultReceiver != null) {
+ resultReceiver.send(result ? 1 : 0, null);
+ }
+ }
+ return result;
+ }
+ }
+
+ private final static class Api25InputContentInfoCompatImpl
+ implements InputConnectionCompatImpl {
+ @Override
+ public boolean commitContent(@NonNull InputConnection inputConnection,
+ @NonNull InputContentInfoCompat inputContentInfo, int flags,
+ @Nullable Bundle opts) {
+ return InputConnectionCompatApi25.commitContent(inputConnection,
+ inputContentInfo.unwrap(), flags, opts);
+ }
+
+ @Nullable
+ @Override
+ public InputConnection createWrapper(
+ @Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo,
+ @Nullable OnCommitContentListener onCommitContentListener) {
+ final OnCommitContentListener listener = onCommitContentListener;
+ return InputConnectionCompatApi25.createWrapper(
+ inputConnection,
+ new InputConnectionCompatApi25.OnCommitContentListener() {
+ @Override
+ public boolean onCommitContent(Object inputContentInfo, int flags,
+ Bundle opts) {
+ InputContentInfoCompat inputContentInfoCompat =
+ InputContentInfoCompat.wrap(inputContentInfo);
+ return listener.onCommitContent(inputContentInfoCompat, flags, opts);
+ }
+ });
+ }
+ }
+
+ private static final InputConnectionCompatImpl IMPL;
+ static {
+ if (BuildCompat.isAtLeastNMR1()) {
+ IMPL = new Api25InputContentInfoCompatImpl();
+ } else {
+ IMPL = new BaseInputContentInfoCompatImpl();
+ }
+ }
+
+ /**
+ * Calls commitContent API, in a backwards compatible fashion.
+ *
+ * @param inputConnection {@link InputConnection} with which commitContent API will be called
+ * @param editorInfo {@link EditorInfo} associated with the given {@code inputConnection}
+ * @param inputContentInfo content information to be passed to the editor
+ * @param flags {@code 0} or {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION}
+ * @param opts optional bundle data. This can be {@code null}
+ * @return {@code true} if this request is accepted by the application, no matter if the request
+ * is already handled or still being handled in background
+ */
+ public static boolean commitContent(@NonNull InputConnection inputConnection,
+ @NonNull EditorInfo editorInfo, @NonNull InputContentInfoCompat inputContentInfo,
+ int flags, @Nullable Bundle opts) {
+ final ClipDescription description = inputContentInfo.getDescription();
+ boolean supported = false;
+ for (String mimeType : EditorInfoCompat.getContentMimeTypes(editorInfo)) {
+ if (description.hasMimeType(mimeType)) {
+ supported = true;
+ break;
+ }
+ }
+ if (!supported) {
+ return false;
+ }
+
+ return IMPL.commitContent(inputConnection, inputContentInfo, flags, opts);
+ }
+
+ /**
+ * When this flag is used, the editor will be able to request temporary access permissions to
+ * the content URI contained in the {@link InputContentInfoCompat} object, in a similar manner
+ * that has been recommended in
+ * <a href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.
+ *
+ * <p>Make sure that the content provider owning the Uri sets the
+ * {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
+ * grantUriPermissions} attribute in its manifest or included the
+ * {@link android.R.styleable#AndroidManifestGrantUriPermission
+ * <grant-uri-permissions>} tag.</p>
+ *
+ * <p>Supported only on API >= 25.</p>
+ *
+ * <p>On API <= 24 devices, IME developers need to ensure that the content URI is accessible
+ * only from the target application, for example, by generating a URL with a unique name that
+ * others cannot guess. IME developers can also rely on the following information of the target
+ * application to do additional access checks in their {@link android.content.ContentProvider}.
+ * </p>
+ * <ul>
+ * <li>On API >= 23 {@link EditorInfo#packageName} is guaranteed to not be spoofed, which
+ * can later be compared with {@link android.content.ContentProvider#getCallingPackage()} in
+ * the {@link android.content.ContentProvider}.
+ * </li>
+ * <li>{@link android.view.inputmethod.InputBinding#getUid()} is guaranteed to not be
+ * spoofed, which can later be compared with {@link android.os.Binder#getCallingUid()} in
+ * the {@link android.content.ContentProvider}.</li>
+ * </ul>
+ */
+ public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 0x00000001;
+
+ /**
+ * Listener for commitContent method call, in a backwards compatible fashion.
+ */
+ public interface OnCommitContentListener {
+ /**
+ * Intercepts InputConnection#commitContent API calls.
+ *
+ * @param inputContentInfo content to be committed
+ * @param flags {@code 0} or {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION}
+ * @param opts optional bundle data. This can be {@code null}
+ * @return {@code true} if this request is accepted by the application, no matter if the
+ * request is already handled or still being handled in background. {@code false} to use the
+ * default implementation
+ */
+ boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts);
+ }
+
+ /**
+ * Creates a wrapper {@link InputConnection} object from an existing {@link InputConnection}
+ * and {@link OnCommitContentListener} that can be returned to the system.
+ *
+ * <p>By returning the wrapper object to the IME, the editor can be notified by
+ * {@link OnCommitContentListener#onCommitContent(InputContentInfoCompat, int, Bundle)}
+ * when the IME calls
+ * {@link InputConnectionCompat#commitContent(InputConnection, EditorInfo,
+ * InputContentInfoCompat, int, Bundle)} and the corresponding Framework API that is available
+ * on API >= 25.</p>
+ *
+ * @param inputConnection {@link InputConnection} to be wrapped
+ * @param editorInfo {@link EditorInfo} associated with the given {@code inputConnection}
+ * @param onCommitContentListener the listener that the wrapper object will call
+ * @return a wrapper {@link InputConnection} object that can be returned to the IME
+ * @throws IllegalArgumentException when {@code inputConnection}, {@code editorInfo}, or
+ * {@code onCommitContentListener} is {@code null}
+ */
+ @NonNull
+ public static InputConnection createWrapper(@NonNull InputConnection inputConnection,
+ @NonNull EditorInfo editorInfo,
+ @NonNull OnCommitContentListener onCommitContentListener) {
+ if (inputConnection == null) {
+ throw new IllegalArgumentException("inputConnection must be non-null");
+ }
+ if (editorInfo == null) {
+ throw new IllegalArgumentException("editorInfo must be non-null");
+ }
+ if (onCommitContentListener == null) {
+ throw new IllegalArgumentException("onCommitContentListener must be non-null");
+ }
+ return IMPL.createWrapper(inputConnection, editorInfo, onCommitContentListener);
+ }
+
+}
diff --git a/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java b/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java
new file mode 100644
index 0000000..6f20594
--- /dev/null
+++ b/v13/java/android/support/v13/view/inputmethod/InputContentInfoCompat.java
@@ -0,0 +1,237 @@
+/**
+ * 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.
+ */
+
+package android.support.v13.view.inputmethod;
+
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
+
+public final class InputContentInfoCompat {
+
+ private interface InputContentInfoCompatImpl {
+ @NonNull
+ Uri getContentUri();
+
+ @NonNull
+ ClipDescription getDescription();
+
+ @Nullable
+ Uri getLinkUri();
+
+ @Nullable
+ Object getInputContentInfo();
+
+ void requestPermission();
+
+ void releasePermission();
+ }
+
+ private final static class BaseInputContentInfoCompatImpl
+ implements InputContentInfoCompatImpl {
+ @NonNull
+ private final Uri mContentUri;
+ @NonNull
+ private final ClipDescription mDescription;
+ @Nullable
+ private final Uri mLinkUri;
+
+ public BaseInputContentInfoCompatImpl(@NonNull Uri contentUri,
+ @NonNull ClipDescription description, @Nullable Uri linkUri) {
+ mContentUri = contentUri;
+ mDescription = description;
+ mLinkUri = linkUri;
+ }
+
+ @NonNull
+ @Override
+ public Uri getContentUri() {
+ return mContentUri;
+ }
+
+ @NonNull
+ @Override
+ public ClipDescription getDescription() {
+ return mDescription;
+ }
+
+ @Nullable
+ @Override
+ public Uri getLinkUri() {
+ return mLinkUri;
+ }
+
+ @Nullable
+ @Override
+ public Object getInputContentInfo() {
+ return null;
+ }
+
+ @Override
+ public void requestPermission() {
+ return;
+ }
+
+ @Override
+ public void releasePermission() {
+ return;
+ }
+ }
+
+ private final static class Api25InputContentInfoCompatImpl
+ implements InputContentInfoCompatImpl {
+ @NonNull
+ final Object mObject;
+
+ public Api25InputContentInfoCompatImpl(@NonNull Object inputContentInfo) {
+ mObject = inputContentInfo;
+ }
+
+ public Api25InputContentInfoCompatImpl(@NonNull Uri contentUri,
+ @NonNull ClipDescription description, @Nullable Uri linkUri) {
+ mObject = InputContentInfoCompatApi25.create(contentUri, description, linkUri);
+ }
+
+ @Override
+ @NonNull
+ public Uri getContentUri() {
+ return InputContentInfoCompatApi25.getContentUri(mObject);
+ }
+
+ @Override
+ @NonNull
+ public ClipDescription getDescription() {
+ return InputContentInfoCompatApi25.getDescription(mObject);
+ }
+
+ @Override
+ @Nullable
+ public Uri getLinkUri() {
+ return InputContentInfoCompatApi25.getLinkUri(mObject);
+ }
+
+ @Override
+ @Nullable
+ public Object getInputContentInfo() {
+ return mObject;
+ }
+
+ @Override
+ public void requestPermission() {
+ InputContentInfoCompatApi25.requestPermission(mObject);
+ }
+
+ @Override
+ public void releasePermission() {
+ InputContentInfoCompatApi25.releasePermission(mObject);
+ }
+ }
+
+ private final InputContentInfoCompatImpl mImpl;
+
+ public InputContentInfoCompat(@NonNull Uri contentUri,
+ @NonNull ClipDescription description, @Nullable Uri linkUri) {
+ if (BuildCompat.isAtLeastNMR1()) {
+ mImpl = new Api25InputContentInfoCompatImpl(contentUri, description, linkUri);
+ } else {
+ mImpl = new BaseInputContentInfoCompatImpl(contentUri, description, linkUri);
+ }
+ }
+
+ private InputContentInfoCompat(@NonNull InputContentInfoCompatImpl impl) {
+ mImpl = impl;
+ }
+
+ /**
+ * @return content URI with which the content can be obtained.
+ */
+ @NonNull
+ public Uri getContentUri() {
+ return mImpl.getContentUri();
+ }
+
+ /**
+ * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()}
+ * such as MIME type(s). {@link ClipDescription#getLabel()} can be used for accessibility
+ * purpose.
+ */
+ @NonNull
+ public ClipDescription getDescription() {
+ return mImpl.getDescription();
+ }
+
+ /**
+ * @return an optional {@code http} or {@code https} URI that is related to this content.
+ */
+ @Nullable
+ public Uri getLinkUri() {
+ return mImpl.getLinkUri();
+ }
+
+ /**
+ * Creates an instance from a framework android.view.inputmethod.InputContentInfo object.
+ *
+ * <p>This method always returns {@code null} on API <= 24.</p>
+ *
+ * @param inputContentInfo an android.view.inputmethod.InputContentInfo object, or {@code null}
+ * if none.
+ * @return an equivalent {@link InputContentInfoCompat} object, or {@code null} if not
+ * supported.
+ */
+ @Nullable
+ public static InputContentInfoCompat wrap(@Nullable Object inputContentInfo) {
+ if (inputContentInfo == null) {
+ return null;
+ }
+ if (!BuildCompat.isAtLeastNMR1()) {
+ return null;
+ }
+ return new InputContentInfoCompat(new Api25InputContentInfoCompatImpl(inputContentInfo));
+ }
+
+ /**
+ * Gets the underlying framework android.view.inputmethod.InputContentInfo object.
+ *
+ * <p>This method always returns {@code null} on API <= 24.</p>
+ *
+ * @return an equivalent android.view.inputmethod.InputContentInfo object, or {@code null} if
+ * not supported.
+ */
+ @Nullable
+ public Object unwrap() {
+ return mImpl.getInputContentInfo();
+ }
+
+ /**
+ * Requests a temporary read-only access permission for content URI associated with this object.
+ *
+ * <p>Does nothing if the temporary permission is already granted.</p>
+ */
+ public void requestPermission() {
+ mImpl.requestPermission();
+ }
+
+ /**
+ * Releases a temporary read-only access permission for content URI associated with this object.
+ *
+ * <p>Does nothing if the temporary permission is not granted.</p>
+ */
+ public void releasePermission() {
+ mImpl.releasePermission();
+ }
+}
diff --git a/v17/leanback/res/values-bs-rBA/strings.xml b/v17/leanback/res/values-bs-rBA/strings.xml
index cdfe434..63a76e2 100644
--- a/v17/leanback/res/values-bs-rBA/strings.xml
+++ b/v17/leanback/res/values-bs-rBA/strings.xml
@@ -53,5 +53,5 @@
<string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
<string name="lb_time_separator" msgid="2763247350845477227">":"</string>
<string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAPOČNITE"</string>
- <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Sljedeća"</string>
+ <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Naprijed"</string>
</resources>
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
index 6f76c0e..40040bb 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
@@ -48,7 +48,7 @@
final boolean isRtl = ViewCompat.getLayoutDirection(focused) ==
View.LAYOUT_DIRECTION_RTL;
final int forward = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
- if (mTitleView.hasFocus() && direction == View.FOCUS_DOWN || direction == forward) {
+ if (mTitleView.hasFocus() && (direction == View.FOCUS_DOWN || direction == forward)) {
return mSceneRoot;
}
return null;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
index b369b19..afeb175 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
@@ -16,6 +16,7 @@
package android.support.v17.leanback.app;
import android.support.v17.leanback.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.support.v17.leanback.widget.Presenter;
@@ -42,6 +43,7 @@
/**
* @hide from javadoc
*/
+@MediumTest
@RunWith(AndroidJUnit4.class)
public class BrowseFragmentTest {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
index ebfed89..bab554d 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
@@ -18,6 +18,7 @@
package android.support.v17.leanback.app;
import android.support.v17.leanback.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.support.v17.leanback.widget.Presenter;
@@ -44,6 +45,7 @@
/**
* @hide from javadoc
*/
+@MediumTest
@RunWith(AndroidJUnit4.class)
public class BrowseSupportFragmentTest {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
index 72f4f44..9cab5a1 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
@@ -25,6 +25,7 @@
import android.support.v17.leanback.widget.VerticalGridView;
import android.support.v17.leanback.widget.picker.DatePicker;
import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -37,6 +38,7 @@
import java.util.Date;
import java.util.List;
+@MediumTest
public class GuidedDatePickerTest extends
ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity> {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
index 72391d1..8387dbd 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
@@ -22,6 +22,7 @@
import android.support.v17.leanback.widget.GuidanceStylist;
import android.support.v17.leanback.widget.GuidedAction;
import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
import android.view.KeyEvent;
@@ -30,9 +31,9 @@
import java.util.Collections;
import java.util.List;
+@MediumTest
public class GuidedStepAttributesTest extends
- ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity>
-{
+ ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity> {
static final long TRANSITION_LENGTH = 1000;
static final String TAG = "GuidedStepAttributesTest";
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
index 5fbcb0e..e1739ff 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -27,6 +27,7 @@
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
import android.text.Selection;
import android.text.Spannable;
import android.util.SparseArray;
@@ -44,6 +45,7 @@
/**
* @hide from javadoc
*/
+@MediumTest
public class GridWidgetTest extends ActivityInstrumentationTestCase2<GridActivity> {
private static final boolean HUMAN_DELAY = false;
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
index ba5ddda..b9a230a 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
@@ -19,6 +19,7 @@
import android.support.v17.leanback.app.HeadersFragment;
import android.support.v17.leanback.R;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.ContextThemeWrapper;
import android.widget.FrameLayout;
import android.view.View;
@@ -28,6 +29,7 @@
import android.support.v17.leanback.widget.DividerPresenter;
import android.view.ContextThemeWrapper;
+@MediumTest
public class PresenterTest extends AndroidTestCase {
public void testZoomFactors() throws Throwable {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
index e7ec4bf..3b99486 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
@@ -16,12 +16,13 @@
package android.support.v17.leanback.widget;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.View.MeasureSpec;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.TextView;
-
+@MediumTest
public class ShadowOverlayContainerTest extends AndroidTestCase {
public void testWrapContent() {
diff --git a/v7/appcompat/res/drawable-hdpi/notification_bg_low_normal.9.png b/v7/appcompat/res/drawable-hdpi/notification_bg_low_normal.9.png
new file mode 100644
index 0000000..af91f5e
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notification_bg_low_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/notification_bg_low_pressed.9.png b/v7/appcompat/res/drawable-hdpi/notification_bg_low_pressed.9.png
new file mode 100644
index 0000000..1602ab8
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/notification_bg_normal.9.png b/v7/appcompat/res/drawable-hdpi/notification_bg_normal.9.png
new file mode 100644
index 0000000..6ebed8b
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notification_bg_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/notification_bg_normal_pressed.9.png b/v7/appcompat/res/drawable-hdpi/notification_bg_normal_pressed.9.png
new file mode 100644
index 0000000..6193822
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/v7/appcompat/res/drawable-hdpi/notify_panel_notification_icon_bg.png
new file mode 100644
index 0000000..6f37a22
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notification_bg_low_normal.9.png b/v7/appcompat/res/drawable-mdpi/notification_bg_low_normal.9.png
new file mode 100644
index 0000000..62de9d7
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notification_bg_low_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notification_bg_low_pressed.9.png b/v7/appcompat/res/drawable-mdpi/notification_bg_low_pressed.9.png
new file mode 100644
index 0000000..eaabd93
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notification_bg_normal.9.png b/v7/appcompat/res/drawable-mdpi/notification_bg_normal.9.png
new file mode 100644
index 0000000..aa239b3
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notification_bg_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notification_bg_normal_pressed.9.png b/v7/appcompat/res/drawable-mdpi/notification_bg_normal_pressed.9.png
new file mode 100644
index 0000000..62d8622
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/v7/appcompat/res/drawable-mdpi/notify_panel_notification_icon_bg.png
new file mode 100644
index 0000000..c286875
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-v21/notification_action_background.xml b/v7/appcompat/res/drawable-v21/notification_action_background.xml
new file mode 100644
index 0000000..852c3f0
--- /dev/null
+++ b/v7/appcompat/res/drawable-v21/notification_action_background.xml
@@ -0,0 +1,22 @@
+<?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
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_light">
+ <item android:id="@android:id/mask"
+ android:drawable="@drawable/abc_btn_default_mtrl_shape" />
+</ripple>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable-xhdpi/notification_bg_low_normal.9.png b/v7/appcompat/res/drawable-xhdpi/notification_bg_low_normal.9.png
new file mode 100644
index 0000000..8c884de
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notification_bg_low_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/notification_bg_low_pressed.9.png b/v7/appcompat/res/drawable-xhdpi/notification_bg_low_pressed.9.png
new file mode 100644
index 0000000..32e00be
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notification_bg_low_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/notification_bg_normal.9.png b/v7/appcompat/res/drawable-xhdpi/notification_bg_normal.9.png
new file mode 100644
index 0000000..bdf477b
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notification_bg_normal.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/notification_bg_normal_pressed.9.png b/v7/appcompat/res/drawable-xhdpi/notification_bg_normal_pressed.9.png
new file mode 100644
index 0000000..5c4da74
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notification_bg_normal_pressed.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/notify_panel_notification_icon_bg.png b/v7/appcompat/res/drawable-xhdpi/notify_panel_notification_icon_bg.png
new file mode 100644
index 0000000..9128e62
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/v7/appcompat/res/drawable/notification_bg.xml b/v7/appcompat/res/drawable/notification_bg.xml
new file mode 100644
index 0000000..1232b4c
--- /dev/null
+++ b/v7/appcompat/res/drawable/notification_bg.xml
@@ -0,0 +1,24 @@
+<?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
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+ <item android:state_pressed="true"
+ android:drawable="@drawable/notification_bg_normal_pressed" />
+ <item android:state_pressed="false" android:drawable="@drawable/notification_bg_normal" />
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/notification_bg_low.xml b/v7/appcompat/res/drawable/notification_bg_low.xml
new file mode 100644
index 0000000..72e58ae
--- /dev/null
+++ b/v7/appcompat/res/drawable/notification_bg_low.xml
@@ -0,0 +1,23 @@
+<?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
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+
+ <item android:state_pressed="true" android:drawable="@drawable/notification_bg_low_pressed" />
+ <item android:state_pressed="false" android:drawable="@drawable/notification_bg_low_normal" />
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/notification_icon_background.xml b/v7/appcompat/res/drawable/notification_icon_background.xml
new file mode 100644
index 0000000..490a797
--- /dev/null
+++ b/v7/appcompat/res/drawable/notification_icon_background.xml
@@ -0,0 +1,22 @@
+<?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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid
+ android:color="@color/notification_icon_bg_color"/>
+</shape>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/notification_tile_bg.xml b/v7/appcompat/res/drawable/notification_tile_bg.xml
new file mode 100644
index 0000000..8eee7ef
--- /dev/null
+++ b/v7/appcompat/res/drawable/notification_tile_bg.xml
@@ -0,0 +1,22 @@
+<?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
+ -->
+
+<bitmap
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:tileMode="repeat"
+ android:src="@drawable/notify_panel_notification_icon_bg"
+/>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v16/notification_template_custom_big.xml b/v7/appcompat/res/layout-v16/notification_template_custom_big.xml
new file mode 100644
index 0000000..24c3323
--- /dev/null
+++ b/v7/appcompat/res/layout-v16/notification_template_custom_big.xml
@@ -0,0 +1,117 @@
+<?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
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_background"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <ImageView android:id="@+id/icon"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:scaleType="center"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:id="@+id/notification_main_column_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/notification_large_icon_width"
+ android:layout_marginStart="@dimen/notification_large_icon_width"
+ android:paddingTop="@dimen/notification_main_column_padding_top"
+ android:minHeight="@dimen/notification_large_icon_height"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="@dimen/notification_content_margin_start"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginBottom="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp" />
+ <FrameLayout
+ android:id="@+id/right_side"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
+ android:paddingTop="@dimen/notification_right_side_padding_top">
+ <ViewStub android:id="@+id/time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ android:layout="@layout/notification_template_part_time" />
+ <ViewStub android:id="@+id/chronometer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ android:layout="@layout/notification_template_part_chronometer" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_gravity="end|bottom"
+ android:layout_marginTop="20dp">
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ />
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="16dp"
+ android:layout_height="16dp"
+ android:layout_gravity="center"
+ android:layout_marginLeft="8dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerInside"
+ android:visibility="gone"
+ android:alpha="0.6"
+ />
+ </LinearLayout>
+ </FrameLayout>
+ </LinearLayout>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:id="@+id/action_divider"
+ android:visibility="gone"
+ android:layout_marginLeft="@dimen/notification_large_icon_width"
+ android:layout_marginStart="@dimen/notification_large_icon_width"
+ android:background="?android:attr/dividerHorizontal" />
+ <LinearLayout
+ android:id="@+id/actions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ android:showDividers="middle"
+ android:divider="?android:attr/listDivider"
+ android:dividerPadding="12dp"
+ android:layout_marginLeft="@dimen/notification_large_icon_width"
+ android:layout_marginStart="@dimen/notification_large_icon_width" >
+ <!-- actions will be added here -->
+ </LinearLayout>
+ </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v21/notification_action.xml b/v7/appcompat/res/layout-v21/notification_action.xml
new file mode 100644
index 0000000..c60bf7d
--- /dev/null
+++ b/v7/appcompat/res/layout-v21/notification_action.xml
@@ -0,0 +1,41 @@
+<?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"
+ style="@style/Widget.AppCompat.NotificationActionContainer"
+ android:id="@+id/action_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="48dp"
+ android:paddingStart="4dp"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/action_image"
+ android:layout_width="@dimen/notification_action_icon_size"
+ android:layout_height="@dimen/notification_action_icon_size"
+ android:layout_gravity="center|start"
+ android:scaleType="centerInside"/>
+ <TextView
+ style="@style/Widget.AppCompat.NotificationActionText"
+ android:id="@+id/action_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center|start"
+ android:paddingStart="4dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:clickable="false"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v21/notification_action_tombstone.xml b/v7/appcompat/res/layout-v21/notification_action_tombstone.xml
new file mode 100644
index 0000000..1637c6f
--- /dev/null
+++ b/v7/appcompat/res/layout-v21/notification_action_tombstone.xml
@@ -0,0 +1,48 @@
+<?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"
+ style="@style/Widget.AppCompat.NotificationActionContainer"
+ android:id="@+id/action_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="48dp"
+ android:paddingStart="4dp"
+ android:orientation="horizontal"
+ android:enabled="false"
+ android:background="@null">
+ <ImageView
+ android:id="@+id/action_image"
+ android:layout_width="@dimen/notification_action_icon_size"
+ android:layout_height="@dimen/notification_action_icon_size"
+ android:layout_gravity="center|start"
+ android:scaleType="centerInside"
+ android:enabled="false"
+ android:alpha="0.5"/>
+ <TextView
+ style="@style/Widget.AppCompat.NotificationActionText"
+ android:id="@+id/action_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center|start"
+ android:paddingStart="4dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:clickable="false"
+ android:enabled="false"
+ android:alpha="0.5"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v21/notification_template_custom_big.xml b/v7/appcompat/res/layout-v21/notification_template_custom_big.xml
new file mode 100644
index 0000000..38332bd
--- /dev/null
+++ b/v7/appcompat/res/layout-v21/notification_template_custom_big.xml
@@ -0,0 +1,90 @@
+<?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
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_background"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <include layout="@layout/notification_template_icon_group"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:layout_marginStart="@dimen/notification_large_icon_width"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:id="@+id/notification_main_column_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_large_icon_height"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginEnd="8dp"
+ android:layout_marginBottom="8dp"/>
+ <FrameLayout
+ android:id="@+id/right_side"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:paddingTop="@dimen/notification_right_side_padding_top">
+ <ViewStub android:id="@+id/time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ android:layout="@layout/notification_template_part_time" />
+ <ViewStub android:id="@+id/chronometer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ android:layout="@layout/notification_template_part_chronometer" />
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_gravity="end|bottom"
+ android:singleLine="true"
+ />
+ </FrameLayout>
+ </LinearLayout>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:id="@+id/action_divider"
+ android:visibility="gone"
+ android:background="#29000000" />
+ <LinearLayout
+ android:id="@+id/actions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-8dp"
+ android:orientation="horizontal"
+ android:visibility="gone"
+ >
+ <!-- actions will be added here -->
+ </LinearLayout>
+ </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout-v21/notification_template_icon_group.xml b/v7/appcompat/res/layout-v21/notification_template_icon_group.xml
new file mode 100644
index 0000000..6c19022
--- /dev/null
+++ b/v7/appcompat/res/layout-v21/notification_template_icon_group.xml
@@ -0,0 +1,43 @@
+<?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
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:id="@+id/icon_group"
+>
+ <ImageView android:id="@+id/icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/notification_big_circle_margin"
+ android:layout_marginBottom="@dimen/notification_big_circle_margin"
+ android:layout_marginStart="@dimen/notification_big_circle_margin"
+ android:layout_marginEnd="@dimen/notification_big_circle_margin"
+ android:scaleType="centerInside"
+ />
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="@dimen/notification_right_icon_size"
+ android:layout_height="@dimen/notification_right_icon_size"
+ android:layout_gravity="end|bottom"
+ android:scaleType="centerInside"
+ android:visibility="gone"
+ android:layout_marginEnd="8dp"
+ android:layout_marginBottom="8dp"
+ />
+</FrameLayout>
+
diff --git a/v7/appcompat/res/layout/notification_action.xml b/v7/appcompat/res/layout/notification_action.xml
new file mode 100644
index 0000000..82e95a5
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_action.xml
@@ -0,0 +1,44 @@
+<?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"
+ style="@style/Widget.AppCompat.NotificationActionContainer"
+ android:id="@+id/action_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="48dp"
+ android:paddingLeft="4dp"
+ android:paddingStart="4dp"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/action_image"
+ android:layout_width="@dimen/notification_action_icon_size"
+ android:layout_height="@dimen/notification_action_icon_size"
+ android:layout_gravity="center|start"
+ android:scaleType="centerInside"/>
+ <TextView
+ style="@style/Widget.AppCompat.NotificationActionText"
+ android:id="@+id/action_text"
+ android:textColor="#ccc"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center|start"
+ android:paddingLeft="4dp"
+ android:paddingStart="4dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:clickable="false"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/notification_action_tombstone.xml b/v7/appcompat/res/layout/notification_action_tombstone.xml
new file mode 100644
index 0000000..d491c78
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_action_tombstone.xml
@@ -0,0 +1,51 @@
+<?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"
+ style="@style/Widget.AppCompat.NotificationActionContainer"
+ android:id="@+id/action_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="48dp"
+ android:paddingLeft="4dp"
+ android:paddingStart="4dp"
+ android:orientation="horizontal"
+ android:enabled="false"
+ android:background="@null">
+ <ImageView
+ android:id="@+id/action_image"
+ android:layout_width="@dimen/notification_action_icon_size"
+ android:layout_height="@dimen/notification_action_icon_size"
+ android:layout_gravity="center|start"
+ android:scaleType="centerInside"
+ android:enabled="false"
+ android:alpha="0.5"/>
+ <TextView
+ style="@style/Widget.AppCompat.NotificationActionText"
+ android:id="@+id/action_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center|start"
+ android:textColor="#ccc"
+ android:paddingLeft="4dp"
+ android:paddingStart="4dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:clickable="false"
+ android:enabled="false"
+ android:alpha="0.5"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/notification_template_big_media.xml b/v7/appcompat/res/layout/notification_template_big_media.xml
index 2e40b69..b72fd97 100644
--- a/v7/appcompat/res/layout/notification_template_big_media.xml
+++ b/v7/appcompat/res/layout/notification_template_big_media.xml
@@ -20,18 +20,18 @@
android:layout_width="match_parent"
android:layout_height="128dp"
>
- <ImageView android:id="@+id/icon"
+ <include layout="@layout/notification_template_icon_group"
android:layout_width="@dimen/notification_large_icon_width"
android:layout_height="@dimen/notification_large_icon_height"
- android:scaleType="centerCrop"
- />
+ />
<include layout="@layout/notification_media_cancel_action"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
- android:layout_alignParentRight="true"/>
- <include layout="@layout/notification_template_lines"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true" />
+ <include layout="@layout/notification_template_lines_media"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_vertical"
diff --git a/v7/appcompat/res/layout/notification_template_big_media_custom.xml b/v7/appcompat/res/layout/notification_template_big_media_custom.xml
new file mode 100644
index 0000000..c88d799
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_big_media_custom.xml
@@ -0,0 +1,107 @@
+<?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
+ -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="128dp"
+ >
+ <include layout="@layout/notification_template_icon_group"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ />
+ <include layout="@layout/notification_media_cancel_action"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginLeft="2dp"
+ android:layout_marginRight="2dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"/>
+ <LinearLayout
+ android:id="@+id/notification_main_column_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/notification_large_icon_height"
+ android:layout_marginStart="@dimen/notification_large_icon_height"
+ android:minHeight="@dimen/notification_large_icon_height"
+ android:paddingTop="@dimen/notification_main_column_padding_top"
+ android:orientation="horizontal"
+ android:layout_toLeftOf="@id/cancel_action"
+ android:layout_toStartOf="@id/cancel_action">
+ <FrameLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="@dimen/notification_content_margin_start"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginBottom="8dp"
+ />
+ <FrameLayout
+ android:id="@+id/right_side"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
+ android:paddingTop="@dimen/notification_right_side_padding_top">
+ <DateTimeView android:id="@+id/time"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ />
+ <Chronometer android:id="@+id/chronometer"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_gravity="end|bottom"
+ android:singleLine="true"
+ />
+ </FrameLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/media_actions"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_alignParentBottom="true"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ >
+ <!-- media buttons will be added here -->
+ </LinearLayout>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_above="@id/media_actions"
+ android:id="@+id/action_divider"
+ android:background="?android:attr/dividerHorizontal" />
+</RelativeLayout>
diff --git a/v7/appcompat/res/layout/notification_template_big_media_narrow.xml b/v7/appcompat/res/layout/notification_template_big_media_narrow.xml
index cf64061..979c8f4 100644
--- a/v7/appcompat/res/layout/notification_template_big_media_narrow.xml
+++ b/v7/appcompat/res/layout/notification_template_big_media_narrow.xml
@@ -35,7 +35,7 @@
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
- <include layout="@layout/notification_template_lines"
+ <include layout="@layout/notification_template_lines_media"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="128dp"
diff --git a/v7/appcompat/res/layout/notification_template_big_media_narrow_custom.xml b/v7/appcompat/res/layout/notification_template_big_media_narrow_custom.xml
new file mode 100644
index 0000000..b7fbff7
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_big_media_narrow_custom.xml
@@ -0,0 +1,115 @@
+<?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
+ -->
+
+<!-- Layout to be used with only max 3 actions. It has a much larger picture at the left side-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="128dp"
+ >
+ <ImageView android:id="@+id/icon"
+ android:layout_width="128dp"
+ android:layout_height="128dp"
+ android:scaleType="centerCrop"
+ />
+
+ <include layout="@layout/notification_media_cancel_action"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginLeft="2dp"
+ android:layout_marginRight="2dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"/>
+
+ <LinearLayout
+ android:id="@+id/notification_main_column_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="128dp"
+ android:layout_marginStart="128dp"
+ android:minHeight="@dimen/notification_large_icon_height"
+ android:paddingTop="@dimen/notification_main_column_padding_top"
+ android:orientation="horizontal"
+ android:layout_toLeftOf="@id/cancel_action"
+ android:layout_toStartOf="@id/cancel_action">
+ <FrameLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="@dimen/notification_media_narrow_margin"
+ android:layout_marginStart="@dimen/notification_media_narrow_margin"
+ android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginBottom="8dp"/>
+ <FrameLayout
+ android:id="@+id/right_side"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
+ android:paddingTop="@dimen/notification_right_side_padding_top">
+ <DateTimeView android:id="@+id/time"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ />
+ <Chronometer android:id="@+id/chronometer"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_gravity="end|bottom"
+ android:singleLine="true"
+ />
+ </FrameLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/media_actions"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_toRightOf="@id/icon"
+ android:layout_toEndOf="@id/icon"
+ android:layout_alignParentBottom="true"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ >
+ <!-- media buttons will be added here -->
+ </LinearLayout>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_toRightOf="@id/icon"
+ android:layout_toEndOf="@id/icon"
+ android:layout_above="@id/media_actions"
+ android:id="@+id/action_divider"
+ android:background="?android:attr/dividerHorizontal" />
+</RelativeLayout>
diff --git a/v7/appcompat/res/layout/notification_template_custom_big.xml b/v7/appcompat/res/layout/notification_template_custom_big.xml
new file mode 100644
index 0000000..c922629
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_custom_big.xml
@@ -0,0 +1,76 @@
+<?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 android:id="@+id/notification_main_column_container"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_large_icon_height"
+ android:orientation="horizontal"
+ android:paddingRight="12dp"
+ android:paddingEnd="12dp">
+ <ImageView android:id="@+id/icon"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:background="@drawable/notification_tile_bg"
+ android:scaleType="center"
+ />
+ <FrameLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="12dp"
+ android:paddingStart="12dp"
+ android:paddingTop="@dimen/notification_main_column_padding_top"
+ android:layout_weight="1"/>
+ <FrameLayout
+ android:id="@+id/right_side"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="12dp"
+ android:paddingLeft="12dp">
+ <include
+ layout="@layout/notification_template_part_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|top"
+ android:visibility="gone"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_marginTop="18dp"
+ android:orientation="horizontal">
+ <TextView android:id="@+id/info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info"
+ />
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="center"
+ android:layout_marginLeft="8dp"
+ android:alpha="0.7"
+ android:scaleType="center"
+ android:visibility="gone"
+ />
+ </LinearLayout>
+ </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/notification_template_icon_group.xml b/v7/appcompat/res/layout/notification_template_icon_group.xml
new file mode 100644
index 0000000..dd564f8
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_icon_group.xml
@@ -0,0 +1,25 @@
+<?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
+ -->
+
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/icon"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:scaleType="centerCrop"
+/>
+
diff --git a/v7/appcompat/res/layout/notification_template_lines.xml b/v7/appcompat/res/layout/notification_template_lines_media.xml
similarity index 70%
rename from v7/appcompat/res/layout/notification_template_lines.xml
rename to v7/appcompat/res/layout/notification_template_lines_media.xml
index 42ba776..9a7b788 100644
--- a/v7/appcompat/res/layout/notification_template_lines.xml
+++ b/v7/appcompat/res/layout/notification_template_lines_media.xml
@@ -29,12 +29,12 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp"
- android:layout_marginLeft="8dp"
- android:layout_marginStart="8dp"
+ android:layout_marginLeft="@dimen/notification_content_margin_start"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Title.Media"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -42,33 +42,37 @@
android:fadingEdge="horizontal"
android:layout_weight="1"
/>
- <include
- layout="@layout/notification_template_part_time"
- android:id="@+id/time"
+ <DateTimeView android:id="@+id/time"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:singleLine="true"
android:layout_gravity="center"
android:layout_weight="0"
android:visibility="gone"
- />
- <include
- layout="@layout/notification_template_part_chronometer"
- android:id="@+id/chronometer"
+ android:paddingLeft="8dp"
+ android:paddingStart="8dp"
+ />
+ <Chronometer android:id="@+id/chronometer"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:singleLine="true"
android:layout_gravity="center"
android:layout_weight="0"
android:visibility="gone"
- />
+ android:paddingLeft="8dp"
+ android:paddingStart="8dp"
+ />
</LinearLayout>
<TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Line2.Media"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
android:layout_marginBottom="-2dp"
- android:layout_marginLeft="8dp"
- android:layout_marginStart="8dp"
+ android:layout_marginLeft="@dimen/notification_content_margin_start"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
android:singleLine="true"
android:fadingEdge="horizontal"
android:ellipsize="marquee"
@@ -80,11 +84,11 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
- android:layout_marginLeft="8dp"
- android:layout_marginStart="8dp"
+ android:layout_marginLeft="@dimen/notification_content_margin_start"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
>
<TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Media"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@@ -94,7 +98,7 @@
android:fadingEdge="horizontal"
/>
<TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info.Media"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/v7/appcompat/res/layout/notification_template_media.xml b/v7/appcompat/res/layout/notification_template_media.xml
index 90daa88..6eac23b7 100644
--- a/v7/appcompat/res/layout/notification_template_media.xml
+++ b/v7/appcompat/res/layout/notification_template_media.xml
@@ -21,12 +21,11 @@
android:layout_height="64dp"
android:orientation="horizontal"
>
- <ImageView android:id="@+id/icon"
+ <include layout="@layout/notification_template_icon_group"
android:layout_width="@dimen/notification_large_icon_width"
- android:layout_height="@dimen/notification_large_icon_width"
- android:scaleType="centerCrop"
- />
- <include layout="@layout/notification_template_lines"
+ android:layout_height="@dimen/notification_large_icon_height"
+ />
+ <include layout="@layout/notification_template_lines_media"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
diff --git a/v7/appcompat/res/layout/notification_template_media_custom.xml b/v7/appcompat/res/layout/notification_template_media_custom.xml
new file mode 100644
index 0000000..62e07d4
--- /dev/null
+++ b/v7/appcompat/res/layout/notification_template_media_custom.xml
@@ -0,0 +1,100 @@
+<?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"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:orientation="horizontal"
+ >
+ <include layout="@layout/notification_template_icon_group"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ />
+ <LinearLayout
+ android:id="@+id/notification_main_column_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/notification_main_column_padding_top"
+ android:minHeight="@dimen/notification_large_icon_height"
+ android:orientation="horizontal"
+ android:layout_toLeftOf="@id/cancel_action"
+ android:layout_toStartOf="@id/cancel_action">
+ <FrameLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="@dimen/notification_content_margin_start"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginBottom="8dp"/>
+ <FrameLayout
+ android:id="@+id/right_side"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dp"
+ android:layout_marginEnd="8dp"
+ android:paddingTop="@dimen/notification_right_side_padding_top">
+ <DateTimeView android:id="@+id/time"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ />
+ <Chronometer android:id="@+id/chronometer"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:layout_gravity="end|top"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Info.Media"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_gravity="end|bottom"
+ android:singleLine="true"
+ />
+ </FrameLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/media_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical|end"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ >
+ <!-- media buttons will be added here -->
+ </LinearLayout>
+ <include layout="@layout/notification_media_cancel_action"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dp"
+ android:layout_marginEnd="6dp"/>
+ <ImageView android:id="@+id/end_padder"
+ android:layout_width="6dp"
+ android:layout_height="match_parent"
+ />
+</LinearLayout>
diff --git a/v7/appcompat/res/layout/notification_template_part_chronometer.xml b/v7/appcompat/res/layout/notification_template_part_chronometer.xml
index 6f5f3ac..9e58a38 100644
--- a/v7/appcompat/res/layout/notification_template_part_chronometer.xml
+++ b/v7/appcompat/res/layout/notification_template_part_chronometer.xml
@@ -16,13 +16,8 @@
-->
<Chronometer android:id="@+id/chronometer" xmlns:android="http://schemas.android.com/apk/res/android"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Time"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_weight="0"
android:singleLine="true"
- android:gravity="center"
- android:paddingLeft="8dp"
- android:paddingStart="8dp"
/>
diff --git a/v7/appcompat/res/layout/notification_template_part_time.xml b/v7/appcompat/res/layout/notification_template_part_time.xml
index 72d216e..810d1e3 100644
--- a/v7/appcompat/res/layout/notification_template_part_time.xml
+++ b/v7/appcompat/res/layout/notification_template_part_time.xml
@@ -16,13 +16,8 @@
-->
<DateTimeView android:id="@+id/time" xmlns:android="http://schemas.android.com/apk/res/android"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Time"
+ android:textAppearance="@style/TextAppearance.AppCompat.Notification.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_weight="0"
android:singleLine="true"
- android:gravity="center"
- android:paddingLeft="8dp"
- android:paddingStart="8dp"
/>
diff --git a/v7/appcompat/res/values-my-rMM/strings.xml b/v7/appcompat/res/values-my-rMM/strings.xml
index 93f779d..0248c15 100644
--- a/v7/appcompat/res/values-my-rMM/strings.xml
+++ b/v7/appcompat/res/values-my-rMM/strings.xml
@@ -27,7 +27,7 @@
<string name="abc_search_hint" msgid="7723749260725869598">"ရှာဖွေပါ..."</string>
<string name="abc_searchview_description_query" msgid="2550479030709304392">"ရှာစရာ အချက်အလက်နေရာ"</string>
<string name="abc_searchview_description_clear" msgid="3691816814315814921">"ရှာစရာ အချက်အလက်များ ဖယ်ရှားရန်"</string>
- <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ရှာဖွေစရာ အချက်အလက်ကို အတည်ပြုရန်"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ရှာဖွေစရာ အချက်အလက်ကို ပေးပို့ရန်"</string>
<string name="abc_searchview_description_voice" msgid="893419373245838918">"အသံဖြင့် ရှာဖွေခြင်း"</string>
<string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"အက်ပ်တစ်ခုခုကို ရွေးချယ်ပါ"</string>
<string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"အားလုံးကို ကြည့်ရန်"</string>
diff --git a/v7/appcompat/res/values-v14/styles.xml b/v7/appcompat/res/values-v14/styles.xml
index f54796d..39419d2 100644
--- a/v7/appcompat/res/values-v14/styles.xml
+++ b/v7/appcompat/res/values-v14/styles.xml
@@ -30,4 +30,9 @@
<style name="TextAppearance.StatusBar.EventContent.Info"/>
<style name="TextAppearance.StatusBar.EventContent.Time"/>
+ <style name="TextAppearance.AppCompat.Notification.Title"
+ parent="@android:style/TextAppearance.StatusBar.EventContent.Title"/>
+
+ <style name="TextAppearance.AppCompat.Notification"
+ parent="@android:style/TextAppearance.StatusBar.EventContent"/>
</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v16/dimens.xml b/v7/appcompat/res/values-v16/dimens.xml
new file mode 100644
index 0000000..3280f7b
--- /dev/null
+++ b/v7/appcompat/res/values-v16/dimens.xml
@@ -0,0 +1,21 @@
+<?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
+ -->
+
+<resources>
+ <!-- the paddingtop on the right side of the notification (for time etc.) -->
+ <dimen name="notification_right_side_padding_top">4dp</dimen>
+</resources>
diff --git a/v7/appcompat/res/values-v21/colors.xml b/v7/appcompat/res/values-v21/colors.xml
new file mode 100644
index 0000000..4a1b209
--- /dev/null
+++ b/v7/appcompat/res/values-v21/colors.xml
@@ -0,0 +1,19 @@
+<?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
+ -->
+<resources>
+ <color name="notification_action_color_filter">@color/secondary_text_default_material_light</color>
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v21/dimens.xml b/v7/appcompat/res/values-v21/dimens.xml
new file mode 100644
index 0000000..de665a6
--- /dev/null
+++ b/v7/appcompat/res/values-v21/dimens.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<resources>
+ <!-- the margin at the beginning of the notification content -->
+ <dimen name="notification_content_margin_start">0dp</dimen>
+ <!-- image margin on the large icon in the narrow media template -->
+ <dimen name="notification_media_narrow_margin">12dp</dimen>
+ <!-- the top padding of the notification content -->
+ <dimen name="notification_main_column_padding_top">0dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v21/styles.xml b/v7/appcompat/res/values-v21/styles.xml
new file mode 100644
index 0000000..1c435ae
--- /dev/null
+++ b/v7/appcompat/res/values-v21/styles.xml
@@ -0,0 +1,58 @@
+<!--
+ ~ 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
+ -->
+
+<resources>
+
+ <!-- Use platform styles -->
+ <style name="TextAppearance.AppCompat.Notification.Info"
+ parent="@android:style/TextAppearance.Material.Notification.Info"/>
+
+ <style name="TextAppearance.AppCompat.Notification.Time"
+ parent="@android:style/TextAppearance.Material.Notification.Time"/>
+
+ <style name="TextAppearance.AppCompat.Notification.Title"
+ parent="@android:style/TextAppearance.Material.Notification.Title"/>
+
+ <style name="TextAppearance.AppCompat.Notification"
+ parent="@android:style/TextAppearance.Material.Notification"/>
+
+ <style name="TextAppearance.AppCompat.Notification.Media" >
+ <item name="android:textColor">@color/secondary_text_default_material_dark</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Notification.Title.Media" >
+ <item name="android:textColor">@color/primary_text_default_material_dark</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Notification.Info.Media">
+ <item name="android:textColor">@color/secondary_text_default_material_dark</item>
+ </style>
+
+ <style name="TextAppearance.AppCompat.Notification.Time.Media">
+ <item name="android:textColor">@color/secondary_text_default_material_dark</item>
+ </style>
+
+ <style name="Widget.AppCompat.NotificationActionText" parent="">
+ <item name="android:textAppearance">?android:attr/textAppearanceButton</item>
+ <item name="android:textColor">@color/secondary_text_default_material_light</item>
+ <item name="android:textSize">@dimen/notification_action_text_size</item>
+ </style>
+
+ <style name="Widget.AppCompat.NotificationActionContainer" parent="">
+ <item name="android:background">@drawable/notification_action_background</item>
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v24/styles.xml b/v7/appcompat/res/values-v24/styles.xml
new file mode 100644
index 0000000..52bb3d4
--- /dev/null
+++ b/v7/appcompat/res/values-v24/styles.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ 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
+ -->
+
+<resources>
+
+ <!-- Use platform styles, Media is dark again -->
+ <style name="TextAppearance.AppCompat.Notification.Media" />
+
+ <style name="TextAppearance.AppCompat.Notification.Info.Media" />
+
+ <style name="TextAppearance.AppCompat.Notification.Time.Media" />
+
+ <style name="TextAppearance.AppCompat.Notification.Title.Media" />
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/colors.xml b/v7/appcompat/res/values/colors.xml
index 0ce01d2..92c91fd 100644
--- a/v7/appcompat/res/values/colors.xml
+++ b/v7/appcompat/res/values/colors.xml
@@ -21,4 +21,11 @@
<color name="abc_input_method_navigation_guard">@android:color/black</color>
<drawable name="notification_template_icon_bg">#3333B5E5</drawable>
+ <drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
+ <color name="notification_action_color_filter">#ffffffff</color>
+ <color name="notification_icon_bg_color">#ff9e9e9e</color>
+
+ <!-- The color of the material notification background for media notifications when no custom
+ color is specified -->
+ <color name="notification_material_background_media_default_color">#ff424242</color>
</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/dimens.xml b/v7/appcompat/res/values/dimens.xml
index 69928ae..7467beb 100644
--- a/v7/appcompat/res/values/dimens.xml
+++ b/v7/appcompat/res/values/dimens.xml
@@ -103,5 +103,41 @@
<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info,
Time) -->
- <dimen name="notification_subtext_size">12dp</dimen>
+ <dimen name="notification_subtext_size">13sp</dimen>
+
+ <!-- Size of notification action text -->
+ <dimen name="notification_action_text_size">13sp</dimen>
+
+ <!-- Top padding for notifications in the standard layout. -->
+ <dimen name="notification_top_pad">10dp</dimen>
+
+ <!-- Top padding for notification when text is large -->
+ <dimen name="notification_top_pad_large_text">5dp</dimen>
+
+ <!-- The size of the action icons -->
+ <dimen name="notification_action_icon_size">32dp</dimen>
+
+ <!-- the size of the small icon on the right of the largeIcon -->
+ <dimen name="notification_right_icon_size">16dp</dimen>
+
+ <!-- the padding of the small icon to the circle -->
+ <dimen name="notification_small_icon_background_padding">3dp</dimen>
+
+ <!-- the side margin of the big notification circle -->
+ <dimen name="notification_big_circle_margin">12dp</dimen>
+
+ <!-- small icon size when placed as large icon -->
+ <dimen name="notification_small_icon_size_as_large">24dp</dimen>
+
+ <!-- the margin at the beginning of the notification content -->
+ <dimen name="notification_content_margin_start">8dp</dimen>
+
+ <!-- image margin on the large icon in the narrow media template -->
+ <dimen name="notification_media_narrow_margin">@dimen/notification_content_margin_start</dimen>
+
+ <!-- the top padding of the notification content -->
+ <dimen name="notification_main_column_padding_top">10dp</dimen>
+
+ <!-- the paddingtop on the right side of the notification (for time etc.) -->
+ <dimen name="notification_right_side_padding_top">2dp</dimen>
</resources>
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index ad86cbd..ec8bbe1 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -329,4 +329,35 @@
<style name="TextAppearance.StatusBar.EventContent.Line2" parent=""/>
<style name="TextAppearance.StatusBar.EventContent.Info" parent=""/>
<style name="TextAppearance.StatusBar.EventContent.Time" parent=""/>
+
+ <style name="TextAppearance.AppCompat.Notification">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+ <style name="TextAppearance.AppCompat.Notification.Title">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+ <style name="TextAppearance.AppCompat.Notification.Info">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+ <style name="TextAppearance.AppCompat.Notification.Time">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+ <style name="TextAppearance.AppCompat.Notification.Line2" parent="TextAppearance.AppCompat.Notification.Info" />
+
+ <style name="TextAppearance.AppCompat.Notification.Title.Media" />
+
+ <style name="TextAppearance.AppCompat.Notification.Media" />
+
+ <style name="TextAppearance.AppCompat.Notification.Info.Media"/>
+
+ <style name="TextAppearance.AppCompat.Notification.Time.Media"/>
+
+ <style name="TextAppearance.AppCompat.Notification.Line2.Media" parent="TextAppearance.AppCompat.Notification.Info.Media"/>
+
+ <style name="Widget.AppCompat.NotificationActionText" parent=""/>
+ <style name="Widget.AppCompat.NotificationActionContainer" parent=""/>
</resources>
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index 581385d..a421ae4 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -584,6 +584,7 @@
<item name="android:colorForegroundInverse">@color/foreground_material_dark</item>
<item name="android:colorBackground">@color/background_material_light</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_light</item>
+ <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
<item name="android:textColorPrimary">@color/abc_primary_text_material_light</item>
<item name="android:textColorPrimaryInverse">@color/abc_primary_text_material_dark</item>
@@ -612,6 +613,7 @@
<item name="android:colorForegroundInverse">@color/foreground_material_light</item>
<item name="android:colorBackground">@color/background_material_dark</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
<item name="android:textColorPrimary">@color/abc_primary_text_material_dark</item>
<item name="android:textColorPrimaryInverse">@color/abc_primary_text_material_light</item>
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
index d1c938f..6a3c91f 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
@@ -19,6 +19,8 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
@@ -26,11 +28,22 @@
import android.support.v4.app.BundleCompat;
import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.text.BidiFormatter;
+import android.support.v7.appcompat.R;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
+import android.widget.RemoteViews;
+
+import java.util.List;
/**
* An extension of {@link android.support.v4.app.NotificationCompat} which supports
- * {@link android.support.v7.app.NotificationCompat.MediaStyle}. You should start using this variant
- * if you need support for media styled notifications.
+ * {@link android.support.v7.app.NotificationCompat.MediaStyle},
+ * {@link android.support.v7.app.NotificationCompat.DecoratedCustomViewStyle},
+ * and {@link android.support.v7.app.NotificationCompat.DecoratedMediaCustomViewStyle}.
+ * You should start using this variant if you need support any of these styles.
*/
public class NotificationCompat extends android.support.v4.app.NotificationCompat {
@@ -66,46 +79,288 @@
return null;
}
- private static void addMediaStyleToBuilderLollipop(
- NotificationBuilderWithBuilderAccessor builder, android.support.v4.app.NotificationCompat.Style style) {
- if (style instanceof MediaStyle) {
- MediaStyle mediaStyle = (MediaStyle) style;
+ private static void addStyleToBuilderApi24(NotificationBuilderWithBuilderAccessor builder,
+ android.support.v4.app.NotificationCompat.Builder b) {
+ if (b.mStyle instanceof DecoratedCustomViewStyle) {
+ NotificationCompatImpl24.addDecoratedCustomViewStyle(builder);
+ } else if (b.mStyle instanceof DecoratedMediaCustomViewStyle) {
+ NotificationCompatImpl24.addDecoratedMediaCustomViewStyle(builder);
+ } else if (!(b.mStyle instanceof MessagingStyle)) {
+ addStyleGetContentViewLollipop(builder, b);
+ }
+ }
+
+ private static RemoteViews addStyleGetContentViewLollipop(
+ NotificationBuilderWithBuilderAccessor builder,
+ android.support.v4.app.NotificationCompat.Builder b) {
+ if (b.mStyle instanceof MediaStyle) {
+ MediaStyle mediaStyle = (MediaStyle) b.mStyle;
NotificationCompatImpl21.addMediaStyle(builder,
mediaStyle.mActionsToShowInCompact,
mediaStyle.mToken != null ? mediaStyle.mToken.getToken() : null);
+
+ boolean hasContentView = b.getContentView() != null;
+ // If we are on L/M the media notification will only be colored if the expanded version
+ // is of media style, so we have to create a custom view for the collapsed version as
+ // well in that case.
+ boolean isMorL = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+ && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M;
+ boolean createCustomContent = hasContentView
+ || (isMorL && b.getBigContentView() != null);
+ if (b.mStyle instanceof DecoratedMediaCustomViewStyle && createCustomContent) {
+ RemoteViews contentViewMedia = NotificationCompatImplBase.overrideContentViewMedia(
+ builder, b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo,
+ b.mNumber, b.mLargeIcon, b.mSubText, b.mUseChronometer,
+ b.getWhenIfShowing(), b.getPriority(), b.mActions,
+ mediaStyle.mActionsToShowInCompact, false /* no cancel button on L */,
+ null /* cancelButtonIntent */, hasContentView /* isDecoratedCustomView */);
+ if (hasContentView) {
+ NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, contentViewMedia,
+ b.getContentView());
+ }
+ setBackgroundColor(b.mContext, contentViewMedia, b.getColor());
+ return contentViewMedia;
+ }
+ return null;
+ } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+ return getDecoratedContentView(b);
}
+ return addStyleGetContentViewJellybean(builder, b);
}
- private static void addMediaStyleToBuilderIcs(NotificationBuilderWithBuilderAccessor builder,
+ private static RemoteViews addStyleGetContentViewJellybean(
+ NotificationBuilderWithBuilderAccessor builder,
+ android.support.v4.app.NotificationCompat.Builder b) {
+ if (b.mStyle instanceof MessagingStyle) {
+ addMessagingFallBackStyle((MessagingStyle) b.mStyle, builder, b);
+ }
+ return addStyleGetContentViewIcs(builder, b);
+ }
+
+ private static MessagingStyle.Message findLatestIncomingMessage(MessagingStyle style) {
+ List<MessagingStyle.Message> messages = style.getMessages();
+ for (int i = messages.size() - 1; i >= 0; i--) {
+ MessagingStyle.Message m = messages.get(i);
+ // Incoming messages have a non-empty sender.
+ if (!TextUtils.isEmpty(m.getSender())) {
+ return m;
+ }
+ }
+ if (!messages.isEmpty()) {
+ // No incoming messages, fall back to outgoing message
+ return messages.get(messages.size() - 1);
+ }
+ return null;
+ }
+
+ private static CharSequence makeMessageLine(android.support.v4.app.NotificationCompat.Builder b,
+ MessagingStyle style,
+ MessagingStyle.Message m) {
+ BidiFormatter bidi = BidiFormatter.getInstance();
+ SpannableStringBuilder sb = new SpannableStringBuilder();
+ boolean afterLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
+ int color = afterLollipop || Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1
+ ? Color.BLACK : Color.WHITE;
+ CharSequence replyName = m.getSender();
+ if (TextUtils.isEmpty(m.getSender())) {
+ replyName = style.getUserDisplayName() == null
+ ? "" : style.getUserDisplayName();
+ color = afterLollipop && b.getColor() != NotificationCompat.COLOR_DEFAULT
+ ? b.getColor()
+ : color;
+ }
+ CharSequence senderText = bidiWrapIfNotSpanned(bidi, replyName);
+ sb.append(senderText);
+ sb.setSpan(makeFontColorSpan(color),
+ sb.length() - senderText.length(),
+ sb.length(),
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE /* flags */);
+ CharSequence text = m.getText() == null ? "" : m.getText();
+ sb.append(" ").append(bidiWrapIfNotSpanned(bidi, text));
+ return sb;
+ }
+
+ private static CharSequence bidiWrapIfNotSpanned(BidiFormatter bidi, CharSequence replyName) {
+ // Unfortunately bidiFormatter doesn't support CharSequences in support
+ if (replyName instanceof Spanned) {
+ return replyName;
+ }
+ return bidi.unicodeWrap(replyName.toString());
+ }
+
+ private static TextAppearanceSpan makeFontColorSpan(int color) {
+ return new TextAppearanceSpan(null, 0, 0, ColorStateList.valueOf(color), null);
+ }
+
+ private static void addMessagingFallBackStyle(MessagingStyle style,
+ NotificationBuilderWithBuilderAccessor builder,
+ android.support.v4.app.NotificationCompat.Builder b) {
+ SpannableStringBuilder completeMessage = new SpannableStringBuilder();
+ List<MessagingStyle.Message> messages = style.getMessages();
+ boolean showNames = style.getConversationTitle() != null
+ || hasMessagesWithoutSender(style.getMessages());
+ for (int i = messages.size() - 1; i >= 0; i--) {
+ MessagingStyle.Message m = messages.get(i);
+ CharSequence line;
+ line = showNames ? makeMessageLine(b, style, m) : m.getText();
+ if (i != messages.size() - 1) {
+ completeMessage.insert(0, "\n");
+ }
+ completeMessage.insert(0, line);
+ }
+ NotificationCompatImplJellybean.addBigTextStyle(builder, completeMessage);
+ }
+
+ private static boolean hasMessagesWithoutSender(
+ List<MessagingStyle.Message> messages) {
+ for (int i = messages.size() - 1; i >= 0; i--) {
+ MessagingStyle.Message m = messages.get(i);
+ if (m.getSender() == null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static RemoteViews addStyleGetContentViewIcs(
+ NotificationBuilderWithBuilderAccessor builder,
android.support.v4.app.NotificationCompat.Builder b) {
if (b.mStyle instanceof MediaStyle) {
MediaStyle mediaStyle = (MediaStyle) b.mStyle;
- NotificationCompatImplBase.overrideContentView(builder, b.mContext,
- b.mContentTitle,
- b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon, b.mSubText,
- b.mUseChronometer, b.mNotification.when, b.mActions,
- mediaStyle.mActionsToShowInCompact, mediaStyle.mShowCancelButton,
- mediaStyle.mCancelButtonIntent);
+ boolean isDecorated = b.mStyle instanceof DecoratedMediaCustomViewStyle
+ && b.getContentView() != null;
+ RemoteViews contentViewMedia = NotificationCompatImplBase.overrideContentViewMedia(
+ builder, b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber,
+ b.mLargeIcon, b.mSubText, b.mUseChronometer, b.getWhenIfShowing(),
+ b.getPriority(), b.mActions, mediaStyle.mActionsToShowInCompact,
+ mediaStyle.mShowCancelButton, mediaStyle.mCancelButtonIntent, isDecorated);
+ if (isDecorated) {
+ NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, contentViewMedia,
+ b.getContentView());
+ return contentViewMedia;
+ }
+ } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+ return getDecoratedContentView(b);
}
+ return null;
}
- private static void addBigMediaStyleToBuilderJellybean(Notification n,
+ private static void addBigStyleToBuilderJellybean(Notification n,
android.support.v4.app.NotificationCompat.Builder b) {
if (b.mStyle instanceof MediaStyle) {
MediaStyle mediaStyle = (MediaStyle) b.mStyle;
- NotificationCompatImplBase.overrideBigContentView(n, b.mContext,
- b.mContentTitle,
- b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon, b.mSubText,
- b.mUseChronometer, b.mNotification.when, b.mActions,
- mediaStyle.mShowCancelButton, mediaStyle.mCancelButtonIntent);
- Bundle extras = getExtras(n);
- if (mediaStyle.mToken != null) {
- BundleCompat.putBinder(extras, EXTRA_MEDIA_SESSION,
- (IBinder) mediaStyle.mToken.getToken());
+ RemoteViews innerView = b.getBigContentView() != null
+ ? b.getBigContentView()
+ : b.getContentView();
+ boolean isDecorated = b.mStyle instanceof DecoratedMediaCustomViewStyle
+ && innerView != null;
+ NotificationCompatImplBase.overrideMediaBigContentView(n, b.mContext,
+ b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon,
+ b.mSubText, b.mUseChronometer, b.getWhenIfShowing(), b.getPriority(), 0,
+ b.mActions, mediaStyle.mShowCancelButton, mediaStyle.mCancelButtonIntent,
+ isDecorated);
+ if (isDecorated) {
+ NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, n.bigContentView,
+ innerView);
}
- if (mediaStyle.mActionsToShowInCompact != null) {
- extras.putIntArray(EXTRA_COMPACT_ACTIONS, mediaStyle.mActionsToShowInCompact);
- }
+ } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+ addDecoratedBigStyleToBuilder(n, b);
+ }
+ }
+
+ private static RemoteViews getDecoratedContentView(
+ android.support.v4.app.NotificationCompat.Builder b) {
+ if (b.getContentView() == null) {
+ // No special content view
+ return null;
+ }
+ RemoteViews remoteViews = NotificationCompatImplBase.applyStandardTemplateWithActions(
+ b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber,
+ b.mNotification.icon, b.mLargeIcon, b.mSubText, b.mUseChronometer,
+ b.getWhenIfShowing(), b.getPriority(), b.getColor(),
+ R.layout.notification_template_custom_big, false /* fitIn1U */, null /* actions */);
+ NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, remoteViews,
+ b.getContentView());
+ return remoteViews;
+ }
+
+ private static void addDecoratedBigStyleToBuilder(Notification n,
+ android.support.v4.app.NotificationCompat.Builder b) {
+ RemoteViews bigContentView = b.getBigContentView();
+ RemoteViews innerView = bigContentView != null ? bigContentView : b.getContentView();
+ if (innerView == null) {
+ // No expandable notification
+ return;
+ }
+ RemoteViews remoteViews = NotificationCompatImplBase.applyStandardTemplateWithActions(
+ b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber,
+ n.icon ,b.mLargeIcon, b.mSubText, b.mUseChronometer, b.getWhenIfShowing(),
+ b.getPriority(), b.getColor(), R.layout.notification_template_custom_big,
+ false /* fitIn1U */, b.mActions);
+ NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, remoteViews, innerView);
+ n.bigContentView = remoteViews;
+ }
+
+ private static void addDecoratedHeadsUpToBuilder(Notification n,
+ android.support.v4.app.NotificationCompat.Builder b) {
+ RemoteViews headsUp = b.getHeadsUpContentView();
+ RemoteViews innerView = headsUp != null ? headsUp : b.getContentView();
+ if (headsUp == null) {
+ // No expandable notification
+ return;
+ }
+ RemoteViews remoteViews = NotificationCompatImplBase.applyStandardTemplateWithActions(
+ b.mContext, b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber, n.icon,
+ b.mLargeIcon, b.mSubText, b.mUseChronometer, b.getWhenIfShowing(), b.getPriority(),
+ b.getColor(), R.layout.notification_template_custom_big, false /* fitIn1U */,
+ b.mActions);
+ NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, remoteViews, innerView);
+ n.headsUpContentView = remoteViews;
+ }
+
+ private static void addBigStyleToBuilderLollipop(Notification n,
+ android.support.v4.app.NotificationCompat.Builder b) {
+ RemoteViews innerView = b.getBigContentView() != null
+ ? b.getBigContentView()
+ : b.getContentView();
+ if (b.mStyle instanceof DecoratedMediaCustomViewStyle && innerView != null) {
+ NotificationCompatImplBase.overrideMediaBigContentView(n, b.mContext,
+ b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon,
+ b.mSubText, b.mUseChronometer, b.getWhenIfShowing(), b.getPriority(), 0,
+ b.mActions, false /* showCancelButton */, null /* cancelButtonIntent */,
+ true /* decoratedCustomView */);
+ NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, n.bigContentView,
+ innerView);
+ setBackgroundColor(b.mContext, n.bigContentView, b.getColor());
+ } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+ addDecoratedBigStyleToBuilder(n, b);
+ }
+ }
+
+ private static void setBackgroundColor(Context context, RemoteViews views, int color) {
+ if (color == COLOR_DEFAULT) {
+ color = context.getResources().getColor(
+ R.color.notification_material_background_media_default_color);
+ }
+ views.setInt(R.id.status_bar_latest_event_content, "setBackgroundColor", color);
+ }
+
+ private static void addHeadsUpToBuilderLollipop(Notification n,
+ android.support.v4.app.NotificationCompat.Builder b) {
+ RemoteViews innerView = b.getHeadsUpContentView() != null
+ ? b.getHeadsUpContentView()
+ : b.getContentView();
+ if (b.mStyle instanceof DecoratedMediaCustomViewStyle && innerView != null) {
+ n.headsUpContentView = NotificationCompatImplBase.generateMediaBigView(b.mContext,
+ b.mContentTitle, b.mContentText, b.mContentInfo, b.mNumber,
+ b.mLargeIcon, b.mSubText, b.mUseChronometer, b.getWhenIfShowing(),
+ b.getPriority(), 0, b.mActions, false /* showCancelButton */,
+ null /* cancelButtonIntent */, true /* decoratedCustomView */);
+ NotificationCompatImplBase.buildIntoRemoteViews(b.mContext, n.headsUpContentView,
+ innerView);
+ setBackgroundColor(b.mContext, n.headsUpContentView, b.getColor());
+ } else if (b.mStyle instanceof DecoratedCustomViewStyle) {
+ addDecoratedHeadsUpToBuilder(n, b);
}
}
@@ -123,11 +378,50 @@
}
/**
+ * @return the text of the notification
+ *
+ * @hide
+ */
+ @Override
+ protected CharSequence resolveText() {
+ if (mStyle instanceof MessagingStyle) {
+ MessagingStyle style = (MessagingStyle) mStyle;
+ MessagingStyle.Message m = findLatestIncomingMessage(style);
+ CharSequence conversationTitle = style.getConversationTitle();
+ if (m != null) {
+ return conversationTitle != null ? makeMessageLine(this, style, m)
+ : m.getText();
+ }
+ }
+ return super.resolveText();
+ }
+
+ /**
+ * @return the title of the notification
+ *
+ * @hide
+ */
+ @Override
+ protected CharSequence resolveTitle() {
+ if (mStyle instanceof MessagingStyle) {
+ MessagingStyle style = (MessagingStyle) mStyle;
+ MessagingStyle.Message m = findLatestIncomingMessage(style);
+ CharSequence conversationTitle = style.getConversationTitle();
+ if (conversationTitle != null || m != null) {
+ return conversationTitle != null ? conversationTitle : m.getSender();
+ }
+ }
+ return super.resolveTitle();
+ }
+
+ /**
* @hide
*/
@Override
protected BuilderExtender getExtender() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return new Api24Extender();
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new LollipopExtender();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return new JellybeanExtender();
@@ -144,8 +438,16 @@
@Override
public Notification build(android.support.v4.app.NotificationCompat.Builder b,
NotificationBuilderWithBuilderAccessor builder) {
- addMediaStyleToBuilderIcs(builder, b);
- return builder.build();
+ RemoteViews contentView = addStyleGetContentViewIcs(builder, b);
+ Notification n = builder.build();
+ // The above call might override decorated content views again, let's make sure it
+ // sticks.
+ if (contentView != null) {
+ n.contentView = contentView;
+ } else if (b.getContentView() != null) {
+ n.contentView = b.getContentView();
+ }
+ return n;
}
}
@@ -154,9 +456,14 @@
@Override
public Notification build(android.support.v4.app.NotificationCompat.Builder b,
NotificationBuilderWithBuilderAccessor builder) {
- addMediaStyleToBuilderIcs(builder, b);
+ RemoteViews contentView = addStyleGetContentViewJellybean(builder, b);
Notification n = builder.build();
- addBigMediaStyleToBuilderJellybean(n, b);
+ // The above call might override decorated content views again, let's make sure it
+ // sticks.
+ if (contentView != null) {
+ n.contentView = contentView;
+ }
+ addBigStyleToBuilderJellybean(n, b);
return n;
}
}
@@ -166,7 +473,25 @@
@Override
public Notification build(android.support.v4.app.NotificationCompat.Builder b,
NotificationBuilderWithBuilderAccessor builder) {
- addMediaStyleToBuilderLollipop(builder, b.mStyle);
+ RemoteViews contentView = addStyleGetContentViewLollipop(builder, b);
+ Notification n = builder.build();
+ // The above call might override decorated content views again, let's make sure it
+ // sticks.
+ if (contentView != null) {
+ n.contentView = contentView;
+ }
+ addBigStyleToBuilderLollipop(n, b);
+ addHeadsUpToBuilderLollipop(n, b);
+ return n;
+ }
+ }
+
+ private static class Api24Extender extends BuilderExtender {
+
+ @Override
+ public Notification build(android.support.v4.app.NotificationCompat.Builder b,
+ NotificationBuilderWithBuilderAccessor builder) {
+ addStyleToBuilderApi24(builder, b);
return builder.build();
}
}
@@ -284,4 +609,78 @@
return this;
}
}
+
+
+ /**
+ * Notification style for custom views that are decorated by the system.
+ *
+ * <p>Instead of providing a notification that is completely custom, a developer can set this
+ * style and still obtain system decorations like the notification header with the expand
+ * affordance and actions.
+ *
+ * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+ * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+ * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+ * corresponding custom views to display.
+ *
+ * <p>To use this style with your Notification, feed it to
+ * {@link NotificationCompat.Builder#setStyle(Style)} like so:
+ * <pre class="prettyprint">
+ * Notification noti = new NotificationCompat.Builder()
+ * .setSmallIcon(R.drawable.ic_stat_player)
+ * .setLargeIcon(albumArtBitmap))
+ * .setCustomContentView(contentView);
+ * .setStyle(<b>new NotificationCompat.DecoratedCustomViewStyle()</b>)
+ * .build();
+ * </pre>
+ *
+ * <p>If you are using this style, consider using the corresponding styles like
+ * {@link android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Notification} or
+ * {@link android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Notification_Title} in
+ * your custom views in order to get the correct styling on each platform version.
+ */
+ public static class DecoratedCustomViewStyle extends Style {
+
+ public DecoratedCustomViewStyle() {
+ }
+ }
+
+ /**
+ * Notification style for media custom views that are decorated by the system.
+ *
+ * <p>Instead of providing a media notification that is completely custom, a developer can set
+ * this style and still obtain system decorations like the notification header with the expand
+ * affordance and actions.
+ *
+ * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+ * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+ * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+ * corresponding custom views to display.
+ *
+ * <p>To use this style with your Notification, feed it to
+ * {@link NotificationCompat.Builder#setStyle(Style)} like so:
+ * <pre class="prettyprint">
+ * Notification noti = new Notification.Builder()
+ * .setSmallIcon(R.drawable.ic_stat_player)
+ * .setLargeIcon(albumArtBitmap))
+ * .setCustomContentView(contentView);
+ * .setStyle(<b>new NotificationCompat.DecoratedMediaCustomViewStyle()</b>
+ * .setMediaSession(mySession))
+ * .build();
+ * </pre>
+ *
+ * <p>If you are using this style, consider using the corresponding styles like
+ * {@link android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Notification_Media} or
+ * {@link
+ * android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Notification_Title_Media} in
+ * your custom views in order to get the correct styling on each platform version.
+ *
+ * @see DecoratedCustomViewStyle
+ * @see MediaStyle
+ */
+ public static class DecoratedMediaCustomViewStyle extends MediaStyle {
+
+ public DecoratedMediaCustomViewStyle() {
+ }
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java
new file mode 100644
index 0000000..0547ad4
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl24.java
@@ -0,0 +1,33 @@
+/*
+ * 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
+ */
+
+package android.support.v7.app;
+
+import android.app.Notification;
+import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
+
+class NotificationCompatImpl24 {
+
+ public static void addDecoratedCustomViewStyle(NotificationBuilderWithBuilderAccessor b) {
+ Notification.Builder builder = b.getBuilder();
+ builder.setStyle(new Notification.DecoratedCustomViewStyle());
+ }
+
+ public static void addDecoratedMediaCustomViewStyle(NotificationBuilderWithBuilderAccessor b) {
+ Notification.Builder builder = b.getBuilder();
+ builder.setStyle(new Notification.DecoratedMediaCustomViewStyle());
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
index 2bd772c..a37c921 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
@@ -21,9 +21,15 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.SystemClock;
import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
+import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompatBase;
import android.support.v7.appcompat.R;
import android.util.TypedValue;
@@ -31,6 +37,7 @@
import android.widget.RemoteViews;
import java.text.NumberFormat;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -41,30 +48,38 @@
static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
static final int MAX_MEDIA_BUTTONS = 5;
+ private static final int MAX_ACTION_BUTTONS = 3;
- public static <T extends NotificationCompatBase.Action> void overrideContentView(
+ public static <T extends NotificationCompatBase.Action> RemoteViews overrideContentViewMedia(
NotificationBuilderWithBuilderAccessor builder,
Context context, CharSequence contentTitle, CharSequence contentText,
CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
- boolean useChronometer, long when, List<T> actions, int[] actionsToShowInCompact,
- boolean showCancelButton, PendingIntent cancelButtonIntent) {
- RemoteViews views = generateContentView(context, contentTitle, contentText, contentInfo,
- number, largeIcon, subText, useChronometer, when, actions, actionsToShowInCompact,
- showCancelButton, cancelButtonIntent);
+ boolean useChronometer, long when, int priority, List<T> actions,
+ int[] actionsToShowInCompact, boolean showCancelButton,
+ PendingIntent cancelButtonIntent, boolean isDecoratedCustomView) {
+ RemoteViews views = generateContentViewMedia(context, contentTitle, contentText, contentInfo,
+ number, largeIcon, subText, useChronometer, when, priority, actions,
+ actionsToShowInCompact, showCancelButton, cancelButtonIntent,
+ isDecoratedCustomView);
builder.getBuilder().setContent(views);
if (showCancelButton) {
builder.getBuilder().setOngoing(true);
}
+ return views;
}
- private static <T extends NotificationCompatBase.Action> RemoteViews generateContentView(
+ private static <T extends NotificationCompatBase.Action> RemoteViews generateContentViewMedia(
Context context, CharSequence contentTitle, CharSequence contentText,
CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
- boolean useChronometer, long when, List<T> actions, int[] actionsToShowInCompact,
- boolean showCancelButton, PendingIntent cancelButtonIntent) {
+ boolean useChronometer, long when, int priority, List<T> actions,
+ int[] actionsToShowInCompact, boolean showCancelButton,
+ PendingIntent cancelButtonIntent, boolean isDecoratedCustomView) {
RemoteViews view = applyStandardTemplate(context, contentTitle, contentText, contentInfo,
- number, largeIcon, subText, useChronometer, when,
- R.layout.notification_template_media, true /* fitIn1U */);
+ number, 0 /* smallIcon */, largeIcon, subText, useChronometer, when, priority,
+ 0 /* color is unused on media */,
+ isDecoratedCustomView ? R.layout.notification_template_media_custom
+ : R.layout.notification_template_media,
+ true /* fitIn1U */);
final int numActions = actions.size();
final int N = actionsToShowInCompact == null
@@ -97,28 +112,31 @@
return view;
}
- public static <T extends NotificationCompatBase.Action> void overrideBigContentView(
+ public static <T extends NotificationCompatBase.Action> void overrideMediaBigContentView(
Notification n, Context context, CharSequence contentTitle, CharSequence contentText,
CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
- boolean useChronometer, long when, List<T> actions, boolean showCancelButton,
- PendingIntent cancelButtonIntent) {
- n.bigContentView = generateBigContentView(context, contentTitle, contentText, contentInfo,
- number, largeIcon, subText, useChronometer, when, actions, showCancelButton,
- cancelButtonIntent);
+ boolean useChronometer, long when, int priority, int color, List<T> actions,
+ boolean showCancelButton, PendingIntent cancelButtonIntent,
+ boolean decoratedCustomView) {
+ n.bigContentView = generateMediaBigView(context, contentTitle, contentText, contentInfo,
+ number, largeIcon, subText, useChronometer, when, priority, color,
+ actions, showCancelButton, cancelButtonIntent, decoratedCustomView);
if (showCancelButton) {
n.flags |= Notification.FLAG_ONGOING_EVENT;
}
}
- private static <T extends NotificationCompatBase.Action> RemoteViews generateBigContentView(
+ public static <T extends NotificationCompatBase.Action> RemoteViews generateMediaBigView(
Context context, CharSequence contentTitle, CharSequence contentText,
CharSequence contentInfo, int number, Bitmap largeIcon, CharSequence subText,
- boolean useChronometer, long when, List<T> actions, boolean showCancelButton,
- PendingIntent cancelButtonIntent) {
+ boolean useChronometer, long when, int priority, int color, List<T> actions,
+ boolean showCancelButton, PendingIntent cancelButtonIntent,
+ boolean decoratedCustomView) {
final int actionCount = Math.min(actions.size(), MAX_MEDIA_BUTTONS);
RemoteViews big = applyStandardTemplate(context, contentTitle, contentText, contentInfo,
- number, largeIcon, subText, useChronometer, when,
- getBigLayoutResource(actionCount), false /* fitIn1U */);
+ number, 0 /* smallIcon */, largeIcon, subText, useChronometer, when, priority,
+ color, /* fitIn1U */getBigMediaLayoutResource(decoratedCustomView, actionCount),
+ false);
big.removeAllViews(R.id.media_actions);
if (actionCount > 0) {
@@ -153,29 +171,162 @@
return button;
}
- private static int getBigLayoutResource(int actionCount) {
+ private static int getBigMediaLayoutResource(boolean decoratedCustomView, int actionCount) {
if (actionCount <= 3) {
- return R.layout.notification_template_big_media_narrow;
+ return decoratedCustomView
+ ? R.layout.notification_template_big_media_narrow_custom
+ : R.layout.notification_template_big_media_narrow;
} else {
- return R.layout.notification_template_big_media;
+ return decoratedCustomView
+ ? R.layout.notification_template_big_media_custom
+ : R.layout.notification_template_big_media;
}
}
- private static RemoteViews applyStandardTemplate(Context context,
+ public static RemoteViews applyStandardTemplateWithActions(Context context,
CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
- int number, Bitmap largeIcon, CharSequence subText, boolean useChronometer, long when,
- int resId, boolean fitIn1U) {
+ int number, int smallIcon, Bitmap largeIcon, CharSequence subText,
+ boolean useChronometer, long when, int priority, int color, int resId, boolean fitIn1U,
+ ArrayList<NotificationCompat.Action> actions) {
+ RemoteViews remoteViews = applyStandardTemplate(context, contentTitle, contentText,
+ contentInfo, number, smallIcon, largeIcon, subText, useChronometer, when, priority,
+ color, resId, fitIn1U);
+ remoteViews.removeAllViews(R.id.actions);
+ boolean actionsVisible = false;
+ if (actions != null) {
+ int N = actions.size();
+ if (N > 0) {
+ actionsVisible = true;
+ if (N > MAX_ACTION_BUTTONS) N = MAX_ACTION_BUTTONS;
+ for (int i = 0; i < N; i++) {
+ final RemoteViews button = generateActionButton(context, actions.get(i));
+ remoteViews.addView(R.id.actions, button);
+ }
+ }
+ }
+ int actionVisibility = actionsVisible ? View.VISIBLE : View.GONE;
+ remoteViews.setViewVisibility(R.id.actions, actionVisibility);
+ remoteViews.setViewVisibility(R.id.action_divider, actionVisibility);
+ return remoteViews;
+ }
+
+ private static RemoteViews generateActionButton(Context context,
+ NotificationCompat.Action action) {
+ final boolean tombstone = (action.actionIntent == null);
+ RemoteViews button = new RemoteViews(context.getPackageName(),
+ tombstone ? getActionTombstoneLayoutResource()
+ : getActionLayoutResource());
+ button.setImageViewBitmap(R.id.action_image,
+ createColoredBitmap(context, action.getIcon(),
+ context.getResources().getColor(R.color.notification_action_color_filter)));
+ button.setTextViewText(R.id.action_text, action.title);
+ if (!tombstone) {
+ button.setOnClickPendingIntent(R.id.action_container, action.actionIntent);
+ }
+ button.setContentDescription(R.id.action_container, action.title);
+ return button;
+ }
+
+ private static Bitmap createColoredBitmap(Context context, int iconId, int color) {
+ return createColoredBitmap(context, iconId, color, 0);
+ }
+
+ private static Bitmap createColoredBitmap(Context context, int iconId, int color, int size) {
+ Drawable drawable = context.getResources().getDrawable(iconId);
+ int width = size == 0 ? drawable.getIntrinsicWidth() : size;
+ int height = size == 0 ? drawable.getIntrinsicHeight() : size;
+ Bitmap resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ drawable.setBounds(0, 0, width, height);
+ if (color != 0) {
+ drawable.mutate().setColorFilter(
+ new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
+ }
+ Canvas canvas = new Canvas(resultBitmap);
+ drawable.draw(canvas);
+ return resultBitmap;
+ }
+
+ private static int getActionLayoutResource() {
+ return R.layout.notification_action;
+ }
+
+ private static int getActionTombstoneLayoutResource() {
+ return R.layout.notification_action_tombstone;
+ }
+
+ public static RemoteViews applyStandardTemplate(Context context,
+ CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
+ int number, int smallIcon, Bitmap largeIcon, CharSequence subText,
+ boolean useChronometer, long when, int priority, int color, int resId,
+ boolean fitIn1U) {
+ Resources res = context.getResources();
RemoteViews contentView = new RemoteViews(context.getPackageName(), resId);
boolean showLine3 = false;
boolean showLine2 = false;
- // On versions before Jellybean, the large icon was shown by SystemUI, so we need to hide
- // it here.
- if (largeIcon != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ boolean minPriority = priority < NotificationCompat.PRIORITY_LOW;
+ boolean afterJellyBean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+ boolean afterLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
+ if (afterJellyBean && !afterLollipop) {
+ // lets color the backgrounds
+ if (minPriority) {
+ contentView.setInt(R.id.notification_background,
+ "setBackgroundResource", R.drawable.notification_bg_low);
+ contentView.setInt(R.id.icon,
+ "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
+ } else {
+ contentView.setInt(R.id.notification_background,
+ "setBackgroundResource", R.drawable.notification_bg);
+ contentView.setInt(R.id.icon,
+ "setBackgroundResource", R.drawable.notification_template_icon_bg);
+ }
+ }
+
+ if (largeIcon != null) {
+ // On versions before Jellybean, the large icon was shown by SystemUI, so we need to hide
+ // it here.
+ if (afterJellyBean) {
+ contentView.setViewVisibility(R.id.icon, View.VISIBLE);
+ contentView.setImageViewBitmap(R.id.icon, largeIcon);
+ } else {
+ contentView.setViewVisibility(R.id.icon, View.GONE);
+ }
+ if (smallIcon != 0) {
+ int backgroundSize = res.getDimensionPixelSize(
+ R.dimen.notification_right_icon_size);
+ int iconSize = backgroundSize - res.getDimensionPixelSize(
+ R.dimen.notification_small_icon_background_padding) * 2;
+ if (afterLollipop) {
+ Bitmap smallBit = createIconWithBackground(context,
+ smallIcon,
+ backgroundSize,
+ iconSize,
+ color);
+ contentView.setImageViewBitmap(R.id.right_icon, smallBit);
+ } else {
+ contentView.setImageViewBitmap(R.id.right_icon,
+ createColoredBitmap(context, smallIcon, Color.WHITE));
+ }
+ contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
+ }
+ } else if (smallIcon != 0) { // small icon at left
contentView.setViewVisibility(R.id.icon, View.VISIBLE);
- contentView.setImageViewBitmap(R.id.icon, largeIcon);
- } else {
- contentView.setViewVisibility(R.id.icon, View.GONE);
+ if (afterLollipop) {
+ int backgroundSize = res.getDimensionPixelSize(
+ R.dimen.notification_large_icon_width)
+ - res.getDimensionPixelSize(R.dimen.notification_big_circle_margin);
+ int iconSize = res.getDimensionPixelSize(
+ R.dimen.notification_small_icon_size_as_large);
+ Bitmap smallBit = createIconWithBackground(context,
+ smallIcon,
+ backgroundSize,
+ iconSize,
+ color);
+ contentView.setImageViewBitmap(R.id.icon, smallBit);
+ } else {
+ contentView.setImageViewBitmap(R.id.icon,
+ createColoredBitmap(context, smallIcon, Color.WHITE));
+ }
}
if (contentTitle != null) {
contentView.setTextViewText(R.id.title, contentTitle);
@@ -184,15 +335,18 @@
contentView.setTextViewText(R.id.text, contentText);
showLine3 = true;
}
+ // If there is a large icon we have a right side
+ boolean hasRightSide = !afterLollipop && largeIcon != null;
if (contentInfo != null) {
contentView.setTextViewText(R.id.info, contentInfo);
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
+ hasRightSide = true;
} else if (number > 0) {
- final int tooBig = context.getResources().getInteger(
+ final int tooBig = res.getInteger(
R.integer.status_bar_notification_info_maxnum);
if (number > tooBig) {
- contentView.setTextViewText(R.id.info, context.getResources().getString(
+ contentView.setTextViewText(R.id.info, ((Resources) res).getString(
R.string.status_bar_notification_info_overflow));
} else {
NumberFormat f = NumberFormat.getIntegerInstance();
@@ -200,12 +354,13 @@
}
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
+ hasRightSide = true;
} else {
contentView.setViewVisibility(R.id.info, View.GONE);
}
// Need to show three lines? Only allow on Jellybean+
- if (subText != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ if (subText != null && afterJellyBean) {
contentView.setTextViewText(R.id.text, subText);
if (contentText != null) {
contentView.setTextViewText(R.id.text2, contentText);
@@ -217,10 +372,9 @@
}
// RemoteViews.setViewPadding and RemoteViews.setTextViewTextSize is not available on ICS-
- if (showLine2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ if (showLine2 && afterJellyBean) {
if (fitIn1U) {
// need to shrink all the type to make sure everything fits
- final Resources res = context.getResources();
final float subTextSize = res.getDimensionPixelSize(
R.dimen.notification_subtext_size);
contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
@@ -230,7 +384,7 @@
}
if (when != 0) {
- if (useChronometer) {
+ if (useChronometer && afterJellyBean) {
contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
contentView.setLong(R.id.chronometer, "setBase",
when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
@@ -239,8 +393,61 @@
contentView.setViewVisibility(R.id.time, View.VISIBLE);
contentView.setLong(R.id.time, "setTime", when);
}
+ hasRightSide = true;
}
+ contentView.setViewVisibility(R.id.right_side, hasRightSide ? View.VISIBLE : View.GONE);
contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
return contentView;
}
+
+ public static Bitmap createIconWithBackground(Context ctx, int iconId, int size, int iconSize,
+ int color) {
+ Bitmap coloredBitmap = createColoredBitmap(ctx, R.drawable.notification_icon_background,
+ color == NotificationCompat.COLOR_DEFAULT ? 0 : color, size);
+ Canvas canvas = new Canvas(coloredBitmap);
+ Drawable icon = ctx.getResources().getDrawable(iconId).mutate();
+ icon.setFilterBitmap(true);
+ int inset = (size - iconSize) / 2;
+ icon.setBounds(inset, inset, iconSize + inset, iconSize + inset);
+ icon.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP));
+ icon.draw(canvas);
+ return coloredBitmap;
+ }
+
+ public static void buildIntoRemoteViews(Context ctx, RemoteViews outerView,
+ RemoteViews innerView) {
+ // this needs to be done fore the other calls, since otherwise we might hide the wrong
+ // things if our ids collide.
+ hideNormalContent(outerView);
+ outerView.removeAllViews(R.id.notification_main_column);
+ outerView.addView(R.id.notification_main_column, innerView.clone());
+ outerView.setViewVisibility(R.id.notification_main_column, View.VISIBLE);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ // Adjust padding depending on font size.
+ outerView.setViewPadding(R.id.notification_main_column_container,
+ 0, calculateTopPadding(ctx), 0, 0);
+ }
+ }
+
+ private static void hideNormalContent(RemoteViews outerView) {
+ outerView.setViewVisibility(R.id.title, View.GONE);
+ outerView.setViewVisibility(R.id.text2, View.GONE);
+ outerView.setViewVisibility(R.id.text, View.GONE);
+ }
+
+ public static int calculateTopPadding(Context ctx) {
+ int padding = ctx.getResources().getDimensionPixelSize(R.dimen.notification_top_pad);
+ int largePadding = ctx.getResources().getDimensionPixelSize(
+ R.dimen.notification_top_pad_large_text);
+ float fontScale = ctx.getResources().getConfiguration().fontScale;
+ float largeFactor = (constrain(fontScale, 1.0f, 1.3f) - 1f) / (1.3f - 1f);
+
+ // Linearly interpolate the padding between large and normal with the font scale ranging
+ // from 1f to LARGE_TEXT_SCALE
+ return Math.round((1 - largeFactor) * padding + largeFactor * largePadding);
+ }
+
+ public static float constrain(float amount, float low, float high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java
new file mode 100644
index 0000000..cf8d128
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplJellybean.java
@@ -0,0 +1,29 @@
+/*
+ * 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
+ */
+
+package android.support.v7.app;
+
+import android.app.Notification;
+import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
+
+class NotificationCompatImplJellybean {
+
+ public static void addBigTextStyle(NotificationBuilderWithBuilderAccessor b,
+ CharSequence bigText) {
+ Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle(b.getBuilder());
+ bigTextStyle.bigText(bigText);
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
index 2d6def1..48bbbdc 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
import android.support.v7.widget.TintTypedArray;
import android.util.AttributeSet;
@@ -84,7 +85,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
- setBackgroundDrawable(mBackground);
+ ViewCompat.setBackground(this, mBackground);
mTitleView = (TextView) findViewById(R.id.title);
if (mTextAppearance != -1) {
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
index 00e7d4c..bb94460 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
@@ -20,6 +20,7 @@
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
import android.support.v7.view.ActionMode;
import android.util.AttributeSet;
@@ -57,7 +58,7 @@
final Drawable bg = Build.VERSION.SDK_INT >= 21
? new ActionBarBackgroundDrawableV21(this)
: new ActionBarBackgroundDrawable(this);
- setBackgroundDrawable(bg);
+ ViewCompat.setBackground(this, bg);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ActionBar);
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
index 4f45c2a..52391d1 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.Build;
+import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
import android.support.v7.view.ActionMode;
import android.support.v7.view.menu.MenuBuilder;
@@ -62,8 +63,7 @@
final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.ActionMode, defStyle, 0);
- setBackgroundDrawable(a.getDrawable(
- R.styleable.ActionMode_background));
+ ViewCompat.setBackground(this, a.getDrawable(R.styleable.ActionMode_background));
mTitleStyleRes = a.getResourceId(
R.styleable.ActionMode_titleTextStyle, 0);
mSubtitleStyleRes = a.getResourceId(
@@ -179,7 +179,7 @@
LayoutParams.MATCH_PARENT);
menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
- mMenuView.setBackgroundDrawable(null);
+ ViewCompat.setBackground(mMenuView, null);
addView(mMenuView, layoutParams);
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
index fe4b0f6..fb94cd9 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
@@ -85,7 +85,8 @@
private static void installDefaultInflateDelegates(@NonNull AppCompatDrawableManager manager) {
final int sdk = Build.VERSION.SDK_INT;
- if (sdk < 23) {
+ // This sdk version check will affect src:appCompat code path.
+ if (sdk < 24) {
// We only want to use the automatic VectorDrawableCompat handling where it's
// needed: on devices running before Lollipop
manager.addDelegate("vector", new VdcInflateDelegate());
diff --git a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java b/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
index 7d53b93..3e4d063 100644
--- a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
+++ b/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
@@ -16,13 +16,16 @@
package android.support.v7.widget;
+import android.os.Build;
import android.os.SystemClock;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.view.menu.ShowableListMenu;
import android.view.MotionEvent;
import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
import android.view.ViewConfiguration;
import android.view.ViewParent;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
/**
@@ -31,6 +34,7 @@
* @hide
*/
public abstract class ForwardingListener implements View.OnTouchListener {
+
/** Scaled touch slop, used for detecting movement outside bounds. */
private final float mScaledTouchSlop;
@@ -62,12 +66,48 @@
public ForwardingListener(View src) {
mSrc = src;
+ src.setLongClickable(true);
+
+ if (Build.VERSION.SDK_INT >= 12) {
+ addDetachListenerApi12(src);
+ } else {
+ addDetachListenerBase(src);
+ }
+
mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
mTapTimeout = ViewConfiguration.getTapTimeout();
+
// Use a medium-press timeout. Halfway between tap and long-press.
mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
}
+ private void addDetachListenerApi12(View src) {
+ src.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {}
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ onDetachedFromWindow();
+ }
+ });
+ }
+
+ private void addDetachListenerBase(View src) {
+ src.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+ boolean mIsAttached = mSrc.isAttachedToWindow();
+
+ @Override
+ public void onGlobalLayout() {
+ final boolean wasAttached = mIsAttached;
+ mIsAttached = mSrc.isAttachedToWindow();
+ if (wasAttached && !mIsAttached) {
+ onDetachedFromWindow();
+ }
+ }
+ });
+ }
+
/**
* Returns the popup to which this listener is forwarding events.
* <p>
@@ -103,6 +143,15 @@
return forwarding || wasForwarding;
}
+ private void onDetachedFromWindow() {
+ mForwarding = false;
+ mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+
+ if (mDisallowIntercept != null) {
+ mSrc.removeCallbacks(mDisallowIntercept);
+ }
+ }
+
/**
* Called when forwarding would like to start.
* <p>
diff --git a/v7/appcompat/src/android/support/v7/widget/SearchView.java b/v7/appcompat/src/android/support/v7/widget/SearchView.java
index bb703cc..d823324 100644
--- a/v7/appcompat/src/android/support/v7/widget/SearchView.java
+++ b/v7/appcompat/src/android/support/v7/widget/SearchView.java
@@ -46,6 +46,7 @@
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.AbsSavedState;
import android.support.v4.view.KeyEventCompat;
+import android.support.v4.view.ViewCompat;
import android.support.v4.widget.CursorAdapter;
import android.support.v7.appcompat.R;
import android.support.v7.view.CollapsibleActionView;
@@ -313,8 +314,10 @@
mCollapsedIcon = (ImageView) findViewById(R.id.search_mag_icon);
// Set up icons and backgrounds.
- mSearchPlate.setBackgroundDrawable(a.getDrawable(R.styleable.SearchView_queryBackground));
- mSubmitArea.setBackgroundDrawable(a.getDrawable(R.styleable.SearchView_submitBackground));
+ ViewCompat.setBackground(mSearchPlate,
+ a.getDrawable(R.styleable.SearchView_queryBackground));
+ ViewCompat.setBackground(mSubmitArea,
+ a.getDrawable(R.styleable.SearchView_submitBackground));
mSearchButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_searchIcon));
mGoButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_goIcon));
mCloseButton.setImageDrawable(a.getDrawable(R.styleable.SearchView_closeIcon));
diff --git a/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java b/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
index 283151b..040fc90 100644
--- a/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
@@ -643,8 +643,7 @@
@Override
public void setBackgroundDrawable(Drawable d) {
- //noinspection deprecation
- mToolbar.setBackgroundDrawable(d);
+ ViewCompat.setBackground(mToolbar, d);
}
@Override
diff --git a/v7/appcompat/tests/res/layout/toolbar_decor_content.xml b/v7/appcompat/tests/res/layout/toolbar_decor_content.xml
index 91d93ca..db9935d 100644
--- a/v7/appcompat/tests/res/layout/toolbar_decor_content.xml
+++ b/v7/appcompat/tests/res/layout/toolbar_decor_content.xml
@@ -32,7 +32,8 @@
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content"
+ android:imeOptions="flagNoExtractUi"/>
</android.support.v7.custom.FitWindowsContentLayout>
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
index 97383c3..9c50144 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
@@ -16,7 +16,10 @@
package android.support.v7.app;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import android.os.SystemClock;
import android.support.v7.appcompat.test.R;
@@ -27,10 +30,7 @@
import android.view.MenuItem;
import android.view.View;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import org.junit.Test;
public abstract class BaseKeyboardShortcutsTestCase<A extends BaseTestActivity>
extends BaseInstrumentationTestCase<A> {
@@ -63,66 +63,4 @@
assertNotNull("Options item selected", selectedItem);
assertEquals("Correct options item selected", selectedItem.getItemId(), expectedId);
}
-
- @Test
- @SmallTest
- public void testAccessActionBar() throws Throwable {
- final BaseTestActivity activity = getActivity();
-
- final View editText = activity.findViewById(R.id.editText);
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- editText.requestFocus();
- }
- });
-
- getInstrumentation().waitForIdleSync();
- sendControlChar('<');
- getInstrumentation().waitForIdleSync();
-
- // Should jump to the action bar after control-<
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- assertFalse(editText.hasFocus());
- final View toolbar = activity.findViewById(R.id.toolbar);
- assertTrue(toolbar.hasFocus());
- }
- });
- getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- getInstrumentation().waitForIdleSync();
-
- // Should jump to the first view again.
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- assertTrue(editText.hasFocus());
- }
- });
- getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
- getInstrumentation().waitForIdleSync();
-
- // Now it shouldn't go up to action bar -- it doesn't allow taking focus once left
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- assertTrue(editText.hasFocus());
- }
- });
- }
-
- private void sendControlChar(char key) throws Throwable {
- KeyEvent tempEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
- KeyCharacterMap map = tempEvent.getKeyCharacterMap();
- KeyEvent[] events = map.getEvents(new char[] {key});
- for (int i = 0; i < events.length; i++) {
- long time = SystemClock.uptimeMillis();
- KeyEvent event = events[i];
- KeyEvent controlKey = new KeyEvent(time, time, event.getAction(), event.getKeyCode(),
- event.getRepeatCount(), event.getMetaState() | KeyEvent.META_CTRL_ON);
- getInstrumentation().sendKeySync(controlKey);
- }
- }
-
}
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
index 2381821..a165d53 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
@@ -20,10 +20,12 @@
import android.app.Dialog;
import android.os.Bundle;
+import android.test.suitebuilder.annotation.MediumTest;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+@MediumTest
public class DialogTestCase extends BaseInstrumentationTestCase<WindowDecorActionBarActivity> {
public DialogTestCase() {
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
index 16c37a2..a27b20b 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
@@ -16,9 +16,74 @@
package android.support.v7.app;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+import android.support.v7.testutils.BaseTestActivity;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+
+import org.junit.Test;
+
public class KeyboardShortcutsTestCaseWithToolbar
extends BaseKeyboardShortcutsTestCase<ToolbarActionBarActivity> {
public KeyboardShortcutsTestCaseWithToolbar() {
super(ToolbarActionBarActivity.class);
}
+
+ @Test
+ @SmallTest
+ public void testAccessActionBar() throws Throwable {
+ final BaseTestActivity activity = getActivity();
+
+ final View editText = activity.findViewById(android.support.v7.appcompat.test.R.id.editText);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ editText.requestFocus();
+ }
+ });
+
+ getInstrumentation().waitForIdleSync();
+ sendControlChar('<');
+ getInstrumentation().waitForIdleSync();
+
+ // Should jump to the action bar after control-<
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(editText.hasFocus());
+ final View toolbar = activity.findViewById(android.support.v7.appcompat.test.R.id.toolbar);
+ assertTrue(toolbar.hasFocus());
+ }
+ });
+ getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+
+ // Should jump to the first view again.
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(editText.hasFocus());
+ }
+ });
+ getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
+ getInstrumentation().waitForIdleSync();
+ }
+
+ private void sendControlChar(char key) throws Throwable {
+ KeyEvent tempEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
+ KeyCharacterMap map = tempEvent.getKeyCharacterMap();
+ KeyEvent[] events = map.getEvents(new char[] {key});
+ for (int i = 0; i < events.length; i++) {
+ long time = SystemClock.uptimeMillis();
+ KeyEvent event = events[i];
+ KeyEvent controlKey = new KeyEvent(time, time, event.getAction(), event.getKeyCode(),
+ event.getRepeatCount(), event.getMetaState() | KeyEvent.META_CTRL_ON);
+ getInstrumentation().sendKeySync(controlKey);
+ }
+ }
}
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
index 55d0d39..bb712d1 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
@@ -23,6 +23,8 @@
import android.support.test.espresso.ViewInteraction;
import android.support.v7.appcompat.test.R;
import android.support.v7.testutils.TestUtilsMatchers;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
import android.widget.ImageView;
import org.junit.Test;
@@ -31,6 +33,7 @@
* In addition to all tinting-related tests done by the base class, this class provides
* tests specific to {@link AppCompatImageView} class.
*/
+@SmallTest
public class AppCompatImageViewTest
extends AppCompatBaseViewTest<AppCompatImageViewActivity, AppCompatImageView> {
public AppCompatImageViewTest() {
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java b/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
index 09590bd..ba27a88 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
@@ -278,7 +278,8 @@
// Allow for off-by-one mismatch in anchoring
assertEquals("Anchoring X", anchorOnScreenXY[0] + popupInWindowXY[0],
popupOnScreenXY[0], 1);
- assertEquals("Anchoring Y", anchorOnScreenXY[1] + popupInWindowXY[1] + mButton.getHeight(),
+ assertEquals("Anchoring Y",
+ anchorOnScreenXY[1] + popupInWindowXY[1] + mButton.getHeight() - popupPadding.top,
popupOnScreenXY[1], 1);
}
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java b/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java
index 81cac57..673a6aa 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java
@@ -23,9 +23,11 @@
import android.graphics.drawable.Drawable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.BaseInstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Test;
+@SmallTest
public class TintResourcesTest extends BaseInstrumentationTestCase<AppCompatActivity> {
public TintResourcesTest() {
diff --git a/v7/mediarouter/res/values-af/strings.xml b/v7/mediarouter/res/values-af/strings.xml
index 9811194..444ffc2 100644
--- a/v7/mediarouter/res/values-af/strings.xml
+++ b/v7/mediarouter/res/values-af/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Stelsel"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Toestelle"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knoppie"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Uitsaai-knoppie. Ontkoppel"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Uitsaai-knoppie. Koppel tans"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Uitsaai-knoppie. Gekoppel"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Saai uit na"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Vind tans toestelle"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Ontkoppel"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Vou uit"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Vou in"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumkunswerk"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volumeglyer"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Geen media is gekies nie"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Geen inligting beskikbaar nie"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Saai tans skerm uit"</string>
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/res/values-am/strings.xml
index 6f7931d..96a2c09 100644
--- a/v7/mediarouter/res/values-am/strings.xml
+++ b/v7/mediarouter/res/values-am/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"ስርዓት"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"መሣሪያዎች"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"የCast አዝራር"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast አዝራር። ግንኙነት ተቋርጧል"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast አዝራር በማገናኘት ላይ"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast አዝራር። ተገናኝቷል"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Cast አድርግ ወደ"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"መሣሪያዎችን በማግኘት ላይ"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ግንኙነት አቋርጥ"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"አስፋ"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"ሰብስብ"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"የአልበም ስነ-ጥበብ"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ተንሸራታች የድምፅ መቆጣጠሪያ"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ምንም ማህደረመረጃ አልተመረጠም"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"ምንም መረጃ አይገኝም"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"ማያ ገጽን በመውሰድ ላይ"</string>
diff --git a/v7/mediarouter/res/values-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
index 29cab47..3caf4b6 100644
--- a/v7/mediarouter/res/values-ar/strings.xml
+++ b/v7/mediarouter/res/values-ar/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"النظام"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"الأجهزة"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"زر الإرسال"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"زر الإرسال. تم قطع الاتصال"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"زر الإرسال. جارٍ الاتصال"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"زر الإرسال. تم الاتصال"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"إرسال إلى"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"جارٍ البحث عن أجهزة"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"قطع الاتصال"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"توسيع"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"تصغير"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"صورة الألبوم"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"شريط تمرير مستوى الصوت"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"لم يتم اختيار أية وسائط"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"لا تتوفر أية معلومات"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"جارٍ إرسال الشاشة"</string>
diff --git a/v7/mediarouter/res/values-az-rAZ/strings.xml b/v7/mediarouter/res/values-az-rAZ/strings.xml
index 765520e..31574c3 100644
--- a/v7/mediarouter/res/values-az-rAZ/strings.xml
+++ b/v7/mediarouter/res/values-az-rAZ/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Yayım düyməsi"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayım düyməsi. Bağlantı kəsildi"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayım düyməsi. Qoşulur"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayım düyməsi. Qoşuldu"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Bura yayımlayın"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar axtarılır"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantını kəsin"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişləndirin"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Yığcamlaşdırın"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albom incəsənəti"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Səs hərmi diyircəyi"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Heç bir media seçilməyib"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Əlçatan məlumat yoxdur"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayımlanır"</string>
diff --git a/v7/mediarouter/res/values-b+sr+Latn/strings.xml b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
index 6c32754..8075d2e 100644
--- a/v7/mediarouter/res/values-b+sr+Latn/strings.xml
+++ b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Dugme Prebaci"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme Prebaci. Veza je prekinuta"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme Prebaci. Povezuje se"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme Prebaci. Povezan je"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Prebacujte na"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Pronalaženje uređaja"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširi"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skupi"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Omot albuma"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za jačinu zvuka"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nema izabranih medija"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nisu dostupne nikakve informacije"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prebacuje se ekran"</string>
diff --git a/v7/mediarouter/res/values-be-rBY/strings.xml b/v7/mediarouter/res/values-be-rBY/strings.xml
index de52c06..75c24d5 100644
--- a/v7/mediarouter/res/values-be-rBY/strings.xml
+++ b/v7/mediarouter/res/values-be-rBY/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Сістэма"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Прылады"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляцыі"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляцыі. Адключана"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляцыі. Ідзе падключэнне"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляцыі. Падключана"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Трансляваць на"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Пошук прылад"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Адлучыць"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Разгарнуць"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Згарнуць"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Вокладка альбома"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Паўзунок гучнасці"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медыяфайл не выбраны"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Інфармацыя адсутнічае"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Экран трансляцыі"</string>
diff --git a/v7/mediarouter/res/values-bg/strings.xml b/v7/mediarouter/res/values-bg/strings.xml
index 036b31f..d756d6c 100644
--- a/v7/mediarouter/res/values-bg/strings.xml
+++ b/v7/mediarouter/res/values-bg/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Бутон за предаване"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Бутон за предаване. Връзката е прекратена"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Бутон за предаване. Свързва се"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Бутон за предаване. Установена е връзка"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Предаване към"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Търсят се устройства"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Прекратяване на връзката"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Разгъване"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свиване"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Обложка на албума"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Плъзгач за силата на звука"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Няма избрана мултимедия"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Няма налична информация"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Екранът се предава"</string>
diff --git a/v7/mediarouter/res/values-bn-rBD/strings.xml b/v7/mediarouter/res/values-bn-rBD/strings.xml
index 0e3e491..b94b9af 100644
--- a/v7/mediarouter/res/values-bn-rBD/strings.xml
+++ b/v7/mediarouter/res/values-bn-rBD/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"সিস্টেম"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ডিভাইসগুলি"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"কাস্ট করার বোতাম"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"কাস্ট করার বোতাম৷ সংযোগ বিচ্ছিন্ন হয়েছে"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"কাস্ট করার বোতাম৷ সংযোগ করা হচ্ছে"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"কাস্ট করার বোতাম৷ সংযুক্ত হয়েছে"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"এতে কাস্ট করুন"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"ডিভাইসগুলিকে খোঁজা হচ্ছে"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"সংযোগ বিচ্ছিন্ন করুন"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"প্রসারিত করুন"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"সঙ্কুচিত করুন"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"অ্যালবাম শৈলি"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ভলিউম স্লাইডার"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"কোনো মিডিয়া নির্বাচন করা হয়নি"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"কোনো তথ্য উপলব্ধ নেই"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"স্ক্রীন কাস্ট করা হচ্ছে"</string>
diff --git a/v7/mediarouter/res/values-bs-rBA/strings.xml b/v7/mediarouter/res/values-bs-rBA/strings.xml
index a6894f5..df4e3ef 100644
--- a/v7/mediarouter/res/values-bs-rBA/strings.xml
+++ b/v7/mediarouter/res/values-bs-rBA/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Dugme za prebacivanje"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme za prebacivanje. Veza je prekinuta"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme za prebacivanje. Povezivanje"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme za prebacivanje. Povezan"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Prebacujte na"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Traženje uređaja"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširi"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skupi"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Omot albuma"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za jačinu zvuka"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nijedan medij nije odabran"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nema dostupnih informacija"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prebacuje se ekran"</string>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
index 7fc51f7..400d424 100644
--- a/v7/mediarouter/res/values-ca/strings.xml
+++ b/v7/mediarouter/res/values-ca/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositius"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Botó d\'emetre"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botó Emet. Desconnectat."</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botó Emet. S\'està connectant."</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botó Emet. Connectat."</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Emet a"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"S\'estan cercant dispositius"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconnecta"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Desplega"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Replega"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Imatge de l\'àlbum"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control lliscant de volum"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No s\'ha seleccionat cap fitxer multimèdia"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hi ha informació disponible"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emissió de pantalla"</string>
diff --git a/v7/mediarouter/res/values-cs/strings.xml b/v7/mediarouter/res/values-cs/strings.xml
index f5a286e..5a29bac 100644
--- a/v7/mediarouter/res/values-cs/strings.xml
+++ b/v7/mediarouter/res/values-cs/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Systém"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Zařízení"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Tlačítko odesílání"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tlačítko odesílání. Odpojeno"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tlačítko odesílání. Připojování"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tlačítko odesílání. Připojeno"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Odesílat do"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Hledání zařízení"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojit"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbalit"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sbalit"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Obal alba"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Posuvník hlasitosti"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nebyla vybrána žádná média"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nejsou k dispozici žádné informace"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Odesílání obsahu obrazovky"</string>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
index 9e5f9a5..f33a4ee 100644
--- a/v7/mediarouter/res/values-da/strings.xml
+++ b/v7/mediarouter/res/values-da/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheder"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knap"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knap. Forbindelsen er afbrudt"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knap. Opretter forbindelse"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knap. Tilsluttet"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Finder enheder"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Afbryd"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Udvid"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafik"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Lydstyrkeskyder"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Der er ikke valgt nogen medier"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Der er ingen tilgængelige oplysninger"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skærmen castes"</string>
diff --git a/v7/mediarouter/res/values-de/strings.xml b/v7/mediarouter/res/values-de/strings.xml
index 91d764f..13686aa 100644
--- a/v7/mediarouter/res/values-de/strings.xml
+++ b/v7/mediarouter/res/values-de/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Geräte"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast-Symbol"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Streaming-Schaltfläche. Nicht verbunden"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Streaming-Schaltfläche. Verbindung wird hergestellt"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Streaming-Schaltfläche. Verbunden"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Streamen auf"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Geräte werden gesucht."</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Verbindung trennen"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Maximieren"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minimieren"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumcover"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Schieberegler für die Lautstärke"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Keine Medien ausgewählt"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Keine Informationen verfügbar"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Bildschirm wird gestreamt."</string>
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/res/values-el/strings.xml
index 0a1a62f..3f45621 100644
--- a/v7/mediarouter/res/values-el/strings.xml
+++ b/v7/mediarouter/res/values-el/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Σύστημα"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Συσκευές"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Κουμπί Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Κουμπί μετάδοσης. Αποσυνδέθηκε"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Κουμπί μετάδοση. Σύνδεση σε εξέλιξη"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Κουμπί μετάδοσης. Συνδέθηκε"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Μετάδοση σε"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Εύρεση συσκευών"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Αποσύνδεση"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Ανάπτυξη"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Σύμπτυξη"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Εξώφυλλο άλμπουμ"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ρυθμιστικό έντασης ήχου"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Δεν έχουν επιλεγεί μέσα"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Δεν υπάρχουν διαθέσιμες πληροφορίες"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Μετάδοση οθόνης"</string>
diff --git a/v7/mediarouter/res/values-en-rAU/strings.xml b/v7/mediarouter/res/values-en-rAU/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rAU/strings.xml
+++ b/v7/mediarouter/res/values-en-rAU/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/res/values-en-rGB/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rGB/strings.xml
+++ b/v7/mediarouter/res/values-en-rGB/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/res/values-en-rIN/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rIN/strings.xml
+++ b/v7/mediarouter/res/values-en-rIN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/res/values-es-rUS/strings.xml
index 2318059..90aa823 100644
--- a/v7/mediarouter/res/values-es-rUS/strings.xml
+++ b/v7/mediarouter/res/values-es-rUS/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Botón para transmitir"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón para transmitir (desconectado)"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón para transmitir (conectando)"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón para transmitir (conectado)"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Transmitir a"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Imagen del álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control deslizante del volumen"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No se seleccionó ningún contenido multimedia"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Sin información disponible"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitiendo pantalla"</string>
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/res/values-es/strings.xml
index 9f108fe..52a886f 100644
--- a/v7/mediarouter/res/values-es/strings.xml
+++ b/v7/mediarouter/res/values-es/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Botón de enviar"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón de enviar. Desconectado"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón de enviar. Conectando"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón de enviar. Conectado"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Enviar a"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Portada del álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control deslizante de volumen"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No se ha seleccionado ningún medio"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hay información disponible"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Enviando pantalla"</string>
diff --git a/v7/mediarouter/res/values-et-rEE/strings.xml b/v7/mediarouter/res/values-et-rEE/strings.xml
index 3fab845..ce1847a 100644
--- a/v7/mediarouter/res/values-et-rEE/strings.xml
+++ b/v7/mediarouter/res/values-et-rEE/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Süsteem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Seadmed"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Ülekandenupp"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Ülekandenupp. Ühendus on katkestatud"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Ülekandenupp. Ühendamine"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Ülekandenupp. Ühendatud"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Ülekandmine seadmesse"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Seadmete otsimine"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Katkesta ühendus"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Laiendamine"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ahendamine"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumi kujundus"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Helitugevuse liugur"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Meediat pole valitud"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Teave puudub"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekraanikuva ülekandmine"</string>
diff --git a/v7/mediarouter/res/values-eu-rES/strings.xml b/v7/mediarouter/res/values-eu-rES/strings.xml
index bae67ed..c03d73b 100644
--- a/v7/mediarouter/res/values-eu-rES/strings.xml
+++ b/v7/mediarouter/res/values-eu-rES/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Gailuak"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Igorri botoia"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Igortzeko botoia. Deskonektatuta"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Igortzeko botoia. Konektatzen"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Igortzeko botoia. Konektatuta"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Igorri hona"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Gailuak bilatzen"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Deskonektatu"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Zabaldu"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tolestu"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumaren azala"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bolumenaren graduatzailea"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ez da hautatu multimedia-edukirik"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ez dago informaziorik"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Pantaila igortzen"</string>
diff --git a/v7/mediarouter/res/values-fa/strings.xml b/v7/mediarouter/res/values-fa/strings.xml
index eb34931..7cc9fbc 100644
--- a/v7/mediarouter/res/values-fa/strings.xml
+++ b/v7/mediarouter/res/values-fa/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"سیستم"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"دستگاهها"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"دکمه ارسال محتوا"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"دکمه فرستادن. ارتباط قطع شد"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"دکمه فرستادن. درحال مرتبطسازی"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"دکمه فرستادن. مرتبط شد"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"ارسال محتوا به"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"پیدا کردن دستگاهها"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"قطع ارتباط"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"بزرگ کردن"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"کوچک کردن"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"عکس روی جلد آلبوم"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"لغزنده میزان صدا"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"رسانه انتخاب نشده است"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"اطلاعات در دسترس نیست"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"درحال فرستادن صفحه"</string>
diff --git a/v7/mediarouter/res/values-fi/strings.xml b/v7/mediarouter/res/values-fi/strings.xml
index f37317a..2465802 100644
--- a/v7/mediarouter/res/values-fi/strings.xml
+++ b/v7/mediarouter/res/values-fi/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Järjestelmä"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Laitteet"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast-painike"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-painike. Yhteys katkaistu"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-painike. Yhdistetään"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-painike. Yhdistetty"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Suoratoiston kohde"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Etsitään laitteita"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Katkaise yhteys"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Laajenna"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tiivistä"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumin kansikuva"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Äänenvoimakkuuden liukusäädin"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ei valittua mediaa."</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tietoja ei ole saatavilla"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Suoratoistetaan näyttöä"</string>
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/res/values-fr-rCA/strings.xml
index 5719479..fd1ea8c 100644
--- a/v7/mediarouter/res/values-fr-rCA/strings.xml
+++ b/v7/mediarouter/res/values-fr-rCA/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Système"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Bouton Diffuser"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Bouton Diffuser. Déconnecté"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Bouton Diffuser. Connexion en cours…"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Bouton Diffuser. Connecté"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Diffuser sur"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Se déconnecter"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Développer"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Réduire"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Image de l\'album"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Curseur de réglage du volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Aucun média sélectionné"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Aucune information disponible"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Diffusion de l\'écran en cours"</string>
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/res/values-fr/strings.xml
index 6ce8329..8c96485 100644
--- a/v7/mediarouter/res/values-fr/strings.xml
+++ b/v7/mediarouter/res/values-fr/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Système"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Icône Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Icône Cast. Déconnecté"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Icône Cast. Connexion…"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Icône Cast. Connecté"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Caster sur"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils en cours…"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Déconnecter"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Développer"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Réduire"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Image de l\'album"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Curseur de volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Aucun média sélectionné"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Aucune information disponible"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Diffusion de l\'écran en cours…"</string>
diff --git a/v7/mediarouter/res/values-gl-rES/strings.xml b/v7/mediarouter/res/values-gl-rES/strings.xml
index c922b68..83489ac 100644
--- a/v7/mediarouter/res/values-gl-rES/strings.xml
+++ b/v7/mediarouter/res/values-gl-rES/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Botón de emitir"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón de emitir. Desconectado"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón de emitir. Conectando"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón de emitir. Conectado"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Emitir en"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Ampliar"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Contraer"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Portada do álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control desprazable do volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Non se seleccionaron recursos"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Non hai información dispoñible"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emisión de pantalla"</string>
diff --git a/v7/mediarouter/res/values-gu-rIN/strings.xml b/v7/mediarouter/res/values-gu-rIN/strings.xml
index e3be8fc..eb7a9b8 100644
--- a/v7/mediarouter/res/values-gu-rIN/strings.xml
+++ b/v7/mediarouter/res/values-gu-rIN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"સિસ્ટમ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ઉપકરણો"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"કાસ્ટ કરો બટન"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"કાસ્ટ કરો બટન. ડિસ્કનેક્ટ કર્યું"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"કાસ્ટ કરો બટન. કનેક્ટ થઈ રહ્યું છે"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"કાસ્ટ કરો બટન. કનેક્ટ થયું"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"આના પર કાસ્ટ કરો"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"ઉપકરણો શોધી રહ્યાં છીએ"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ડિસ્કનેક્ટ કરો"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"વિસ્તૃત કરો"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"સંકુચિત કરો"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"આલ્બમ કલા"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"વૉલ્યુમ સ્લાઇડર"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"કોઈ મીડિયા પસંદ કરેલ નથી"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"કોઈ માહિતી ઉપલબ્ધ નથી"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"સ્ક્રીનને કાસ્ટ કરી રહ્યાં છે"</string>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index 9d0650b..e74967e 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"डिवाइस"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट करें बटन"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट करें बटन. डिस्कनेक्ट है"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट करें बटन. कनेक्ट हो रहा है"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट करें बटन. कनेक्ट है"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"इस पर कास्ट करें"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"डिवाइस ढूंढ रहा है"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्कनेक्ट करें"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करें"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त करें"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"एल्बम आर्ट"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"वॉल्यूम स्लाइडर"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"कोई मीडिया चयनित नहीं है"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोई जानकारी उपलब्ध नहीं"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्ट हो रही है"</string>
diff --git a/v7/mediarouter/res/values-hr/strings.xml b/v7/mediarouter/res/values-hr/strings.xml
index 371088b..f50d748 100644
--- a/v7/mediarouter/res/values-hr/strings.xml
+++ b/v7/mediarouter/res/values-hr/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sustav"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za emitiranje"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Gumb za emitiranje. Veza prekinuta"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Gumb za emitiranje. Povezivanje"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Gumb za emitiranje. Povezan"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Emitiranje na"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Traženje uređaja"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširivanje"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sažimanje"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Naslovnica albuma"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za glasnoću"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nije odabran nijedan medij"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Informacije nisu dostupne"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emitiranje zaslona"</string>
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/res/values-hu/strings.xml
index a3d6990..6420985 100644
--- a/v7/mediarouter/res/values-hu/strings.xml
+++ b/v7/mediarouter/res/values-hu/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Rendszer"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Eszközök"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Átküldés gomb"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Átküldés gomb. Kapcsolat bontva"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Átküldés gomb. Csatlakozás"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Átküldés gomb. Csatlakoztatva"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Átküldés ide"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Eszközök keresése"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Leválasztás"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Kibontás"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Összecsukás"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Lemezborító"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Hangerőszabályzó"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nincs média kiválasztva"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nincs információ"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Képernyőtartalom átküldése"</string>
diff --git a/v7/mediarouter/res/values-hy-rAM/strings.xml b/v7/mediarouter/res/values-hy-rAM/strings.xml
index a8c1cf3..6e46af8 100644
--- a/v7/mediarouter/res/values-hy-rAM/strings.xml
+++ b/v7/mediarouter/res/values-hy-rAM/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Համակարգ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Սարքեր"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Հեռարձակման կոճակ"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Հեռարձակման կոճակ: Սարքն անջատված է"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Հեռարձակման կոճակ: Սարքը կապակցվում է"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Հեռարձակման կոճակ: Սարքը կապակցված է"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Ընտրեք սարքը"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Սարքերի որոնում"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Անջատել"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Ընդարձակել"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Կոծկել"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Ալբոմի շապիկ"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ձայնի ուժգնության կարգավորիչ"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Մեդիա ֆայլեր չեն ընտրվել"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Տեղեկությունները հասանելի չեն"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Էկրանը հեռարձակվում է"</string>
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
index 4bc0852..43e0c62 100644
--- a/v7/mediarouter/res/values-in/strings.xml
+++ b/v7/mediarouter/res/values-in/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Perangkat"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Tombol transmisi"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tombol transmisi. Terputus"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tombol transmisi. Menghubungkan"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tombol transmisi. Terhubung"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Transmisikan ke"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari perangkat"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Luaskan"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ciutkan"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Sampul album"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bilah geser volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tidak ada media yang dipilih"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tidak ada info yang tersedia"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmisi layar"</string>
diff --git a/v7/mediarouter/res/values-is-rIS/strings.xml b/v7/mediarouter/res/values-is-rIS/strings.xml
index 08e41e6..53de253 100644
--- a/v7/mediarouter/res/values-is-rIS/strings.xml
+++ b/v7/mediarouter/res/values-is-rIS/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Kerfi"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Tæki"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Útsendingarhnappur"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Útsendingarhnappur. Aftengt"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Útsendingarhnappur. Tengist"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Útsendingarhnappur. Tengt"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Senda út í"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Leitað að tækjum"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Aftengjast"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Stækka"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minnka"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Plötuumslag"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Hljóðstyrkssleði"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Enginn miðill valinn"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Engar upplýsingar í boði"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skjár sendur út"</string>
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/res/values-it/strings.xml
index 87b570c..df6bbfe 100644
--- a/v7/mediarouter/res/values-it/strings.xml
+++ b/v7/mediarouter/res/values-it/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivi"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Pulsante Trasmetti"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Pulsante Trasmetti. Disconnesso"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Pulsante Trasmetti. Connessione in corso"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Pulsante Trasmetti. Connesso"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Trasmetti a"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Ricerca di dispositivi in corso"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Scollega"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Espandi"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Comprimi"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Copertina"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Dispositivo di scorrimento del volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nessun contenuto multimediale selezionato"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nessuna informazione disponibile"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Trasmissione dello schermo in corso"</string>
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/res/values-iw/strings.xml
index 8b52adf..be705a6 100644
--- a/v7/mediarouter/res/values-iw/strings.xml
+++ b/v7/mediarouter/res/values-iw/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"מערכת"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"מכשירים"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"לחצן הפעלת Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"לחצן הפעלת Cast. מנותק"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"לחצן הפעלת Cast. מתחבר"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"לחצן הפעלת Cast. מחובר"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"העבר אל"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"מחפש מכשירים"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"נתק"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"הרחב"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"כווץ"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"עטיפת אלבום"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"מחוון עוצמה"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"לא נבחרה מדיה"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"אין מידע זמין"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"העברת מסך מתבצעת"</string>
diff --git a/v7/mediarouter/res/values-ja/strings.xml b/v7/mediarouter/res/values-ja/strings.xml
index b126965..75d75d6 100644
--- a/v7/mediarouter/res/values-ja/strings.xml
+++ b/v7/mediarouter/res/values-ja/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"システム"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"端末"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"キャストアイコン"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"キャスト アイコン。接続解除済み"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"キャスト アイコン。接続中"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"キャスト アイコン。接続済み"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"キャストするデバイス"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"端末を検索しています"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"接続を解除"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"折りたたむ"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"アルバムアート"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量スライダー"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"メディアが選択されていません"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"情報がありません"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"画面をキャストしています"</string>
diff --git a/v7/mediarouter/res/values-ka-rGE/strings.xml b/v7/mediarouter/res/values-ka-rGE/strings.xml
index 046e361..3bcc513 100644
--- a/v7/mediarouter/res/values-ka-rGE/strings.xml
+++ b/v7/mediarouter/res/values-ka-rGE/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"სისტემა"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"მოწყობილობები"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ტრანსლირების ღილაკი"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ტრანსლირების ღილაკი. გათიშული"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ტრანსლირების ღილაკი. მიმდინარეობს დაკავშირება"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"ტრანსლირების ღილაკი. დაკავშირებული"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"ტრანსლირებული"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"მიმდინარეობს მოწყობილობების მოძიება"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"კავშირის გაწყვეტა"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"გაშლა"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"ჩაკეცვა"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ალბომის გარეკანი"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ხმის სლაიდერი"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"მედია არჩეული არ არის"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"ინფორმაცია არ არის ხელმისაწვდომი"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"მიმდინარეობს ეკრანის გადაცემა"</string>
diff --git a/v7/mediarouter/res/values-kk-rKZ/strings.xml b/v7/mediarouter/res/values-kk-rKZ/strings.xml
index 5cf4e5a..43e75b7 100644
--- a/v7/mediarouter/res/values-kk-rKZ/strings.xml
+++ b/v7/mediarouter/res/values-kk-rKZ/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Жүйе"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Құрылғылар"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Трансляциялау түймесі"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"\"Трансляциялау\" түймесі. Ажыратулы"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"\"Трансляциялау\" түймесі. Қосылуда"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"\"Трансляциялау\" түймесі. Қосылды"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Келесіге трансляциялау"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Құрылғыларды табу"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Ажырату"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Жаю"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жию"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Альбом шебері"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Дыбыс деңгейінің жүгірткісі"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ешбір тасушы таңдалмаған"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Қол жетімді ақпарат жоқ"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Экранды трансляциялау"</string>
diff --git a/v7/mediarouter/res/values-km-rKH/strings.xml b/v7/mediarouter/res/values-km-rKH/strings.xml
index fd05668..44d88f4 100644
--- a/v7/mediarouter/res/values-km-rKH/strings.xml
+++ b/v7/mediarouter/res/values-km-rKH/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"ប្រព័ន្ធ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ឧបករណ៍"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ប៊ូតុងខាស"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ខាសប៊ូតុង៖ បានកាត់ផ្តាច់"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ខាសប៊ូតុង៖ កំពុងភ្ជាប់"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"ខាសប៊ូតុង៖ បានភ្ជាប់ហើយ"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"ខាសទៅ"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"ស្វែងរកឧបករណ៍"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ផ្ដាច់"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"ពង្រីក"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"បង្រួម"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ស្នាដៃសិល្បៈអាល់ប៊ុម"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"របារកម្រិតសំឡេង"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"គ្មានការជ្រើសមេឌៀទេ"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"មិនមានព័ត៌មានទេ"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"កំពុងខាសអេក្រង់"</string>
diff --git a/v7/mediarouter/res/values-kn-rIN/strings.xml b/v7/mediarouter/res/values-kn-rIN/strings.xml
index 9cae5be..193d449 100644
--- a/v7/mediarouter/res/values-kn-rIN/strings.xml
+++ b/v7/mediarouter/res/values-kn-rIN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"ಸಿಸ್ಟಂ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ಸಾಧನಗಳು"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ಬಿತ್ತರಿಸು ಬಟನ್"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ಬಿತ್ತರಿಸು ಬಟನ್. ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ಬಿತ್ತರಿಸು ಬಟನ್. ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"ಬಿತ್ತರಿಸು ಬಟನ್. ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"ಇದಕ್ಕೆ ಬಿತ್ತರಿಸಿ"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"ವಿಸ್ತರಿಸು"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"ಸಂಕುಚಿಸು"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ಆಲ್ಬಮ್ ಕಲೆ"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ವಾಲ್ಯೂಮ್ ಸ್ಲೈಡರ್"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ಯಾವುದೇ ಮಾಧ್ಯಮ ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"ಯಾವುದೇ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"ಪರದೆಯನ್ನು ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string>
diff --git a/v7/mediarouter/res/values-ko/strings.xml b/v7/mediarouter/res/values-ko/strings.xml
index 7f53382..242560a 100644
--- a/v7/mediarouter/res/values-ko/strings.xml
+++ b/v7/mediarouter/res/values-ko/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"시스템"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"기기"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"전송 버튼"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"전송 버튼. 연결 해제됨"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"전송 버튼. 연결 중"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"전송 버튼. 연결됨"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"전송할 기기"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"기기를 찾는 중"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"연결 해제"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"펼치기"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"접기"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"앨범아트"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"볼륨 슬라이더"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"선택한 미디어 없음"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"정보가 없습니다."</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"화면 전송 중"</string>
diff --git a/v7/mediarouter/res/values-ky-rKG/strings.xml b/v7/mediarouter/res/values-ky-rKG/strings.xml
index 99201dc..0898ade 100644
--- a/v7/mediarouter/res/values-ky-rKG/strings.xml
+++ b/v7/mediarouter/res/values-ky-rKG/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Тутум"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Түзмөктөр"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Тышкы экранга чыгаруу баскычы"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Тышкы экранга чыгаруу баскычы. Түзмөк ажырап турат."</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Тышкы экранга чыгаруу баскычы. Түзмөк туташууда"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Тышкы экранга чыгаруу баскычы. Түзмөк туташып турат"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Төмөнкүгө чыгаруу"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Түзмөктөр изделүүдө"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Ажыратуу"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Жайып көрсөтүү"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жыйыштыруу"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Альбом мукабасы"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Үндү катуулатуучу сыдырма"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Бир да медиа файл тандалган жок"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Эч маалымат жок"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Тышкы экранга чыгарылууда"</string>
diff --git a/v7/mediarouter/res/values-lo-rLA/strings.xml b/v7/mediarouter/res/values-lo-rLA/strings.xml
index 2765364..65b3472 100644
--- a/v7/mediarouter/res/values-lo-rLA/strings.xml
+++ b/v7/mediarouter/res/values-lo-rLA/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"ລະບົບ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ອຸປະກອນ"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ປຸ່ມຄາສທ໌"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ປຸ່ມສົ່ງສັນຍານ. ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ປຸ່ມສົ່ງສັນຍານ. ກຳລັງເຊື່ອມຕໍ່"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"ປຸ່ມສົ່ງສັນຍານ. ເຊື່ອມຕໍ່ແລ້ວ"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"ຄາສທ໌ຫາ"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"ກຳລັງຊອກຫາອຸປະກອນ"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ຕັດການເຊື່ອມຕໍ່"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"ຂະຫຍາຍ"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"ຫຍໍ້ລົງ"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ໜ້າປົກອະລະບໍ້າ"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ຕົວປັບລະດັບສຽງ"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ບໍ່ໄດ້ເລືອກມີເດຍໃດໄວ້"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"ບໍ່ມີຂໍ້ມູນ"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"ການສົ່ງພາບໜ້າຈໍ"</string>
diff --git a/v7/mediarouter/res/values-lt/strings.xml b/v7/mediarouter/res/values-lt/strings.xml
index 208752f..35931cf 100644
--- a/v7/mediarouter/res/values-lt/strings.xml
+++ b/v7/mediarouter/res/values-lt/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Įrenginiai"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Perdavimo mygtukas"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Perdavimo mygtukas. Atsijungta"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Perdavimo mygtukas. Prisijungiama"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Perdavimo mygtukas. Prisijungta"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Perduoti į"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Randami įrenginiai"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Atjungti"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Išskleisti"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sutraukti"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumo viršelis"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Garsumo šliaužiklis"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nepasirinkta jokia medija"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Informacija nepasiekiama"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Perduodamas ekranas"</string>
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/res/values-lv/strings.xml
index 832a3ba..c146174 100644
--- a/v7/mediarouter/res/values-lv/strings.xml
+++ b/v7/mediarouter/res/values-lv/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistēma"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Ierīces"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Apraides poga"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Apraides poga. Savienojums pārtraukts"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Apraides poga. Notiek savienojuma izveide"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Apraides poga. Savienojums izveidots"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Apraidīšana uz ierīci"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Notiek ierīču meklēšana"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Atvienot"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Izvērst"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sakļaut"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albuma vāciņš"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Skaļuma slīdnis"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nav atlasīti multivides faili"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nav pieejama informācija"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Notiek ekrāna apraide"</string>
diff --git a/v7/mediarouter/res/values-mk-rMK/strings.xml b/v7/mediarouter/res/values-mk-rMK/strings.xml
index 726e285..6fd428f 100644
--- a/v7/mediarouter/res/values-mk-rMK/strings.xml
+++ b/v7/mediarouter/res/values-mk-rMK/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Уреди"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Копчето за Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Копче за Cast. Исклучено"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Копче за Cast. Се поврзува"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Копче за Cast. Поврзано"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Емитувај на"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Наоѓање уреди"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Исклучи"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Собери"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Корица на албум"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Лизгач за јачина на звук"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Не се избрани медиуми"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Нема достапни информации"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Екранот се емитува"</string>
diff --git a/v7/mediarouter/res/values-ml-rIN/strings.xml b/v7/mediarouter/res/values-ml-rIN/strings.xml
index b1d2cbe..63a37f8 100644
--- a/v7/mediarouter/res/values-ml-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ml-rIN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"സിസ്റ്റം"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ഉപകരണങ്ങൾ"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ടാപ്പുചെയ്യുക"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"കാസ്റ്റ് ബട്ടൺ. വിച്ഛേദിച്ചു"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"കാസ്റ്റ് ബട്ടൺ. കണക്റ്റുചെയ്യുന്നു"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"കാസ്റ്റ് ബട്ടൺ. കണക്റ്റുചെയ്തു"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"ഇതിലേക്ക് കാസ്റ്റുചെയ്യുക"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"ഉപകരണങ്ങൾ കണ്ടെത്തുന്നു"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"വിച്ഛേദിക്കുക"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"വികസിപ്പിക്കുക"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"ചുരുക്കുക"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ആൽബം ആർട്ട്"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"വോളിയം സ്ലൈഡർ"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"മീഡിയയൊന്നും തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"സ്ക്രീൻ കാസ്റ്റുചെയ്യുന്നു"</string>
diff --git a/v7/mediarouter/res/values-mn-rMN/strings.xml b/v7/mediarouter/res/values-mn-rMN/strings.xml
index d07d314..1197bfe 100644
--- a/v7/mediarouter/res/values-mn-rMN/strings.xml
+++ b/v7/mediarouter/res/values-mn-rMN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Төхөөрөмжүүд"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Дамжуулах товчлуур"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Дамжуулах товчлуур. Салсан"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Дамжуулах товчлуур. Холбож байна"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Дамжуулах товчлуур. Холбогдсон"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Дамжуулах"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Төхөөрөмж хайж байна"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Салгах"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Дэлгэх"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Хураах"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Цомгийн зураг"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Дууны түвшин тааруулагч"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ямар ч медиа сонгоогүй"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Мэдээлэл байхгүй байна"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Дэлгэцийг дамжуулж байна"</string>
diff --git a/v7/mediarouter/res/values-mr-rIN/strings.xml b/v7/mediarouter/res/values-mr-rIN/strings.xml
index 4e24aff..40d7d66 100644
--- a/v7/mediarouter/res/values-mr-rIN/strings.xml
+++ b/v7/mediarouter/res/values-mr-rIN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"डिव्हाइसेस"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट बटण"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट बटण. डिस्कनेक्ट केले"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट बटण. कनेक्ट करीत आहे"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट बटण. कनेक्ट केले"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"यावर कास्ट करा"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"डिव्हाइसेस शोधत आहे"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्कनेक्ट करा"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करा"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"संकुचित करा"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"अल्बम कला"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"व्हॉल्यूम स्लायडर"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"मीडिया निवडला नाही"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोणतीही माहिती उपलब्ध नाही"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्ट करीत आहे"</string>
diff --git a/v7/mediarouter/res/values-ms-rMY/strings.xml b/v7/mediarouter/res/values-ms-rMY/strings.xml
index 2a4cd1c..cc32b96 100644
--- a/v7/mediarouter/res/values-ms-rMY/strings.xml
+++ b/v7/mediarouter/res/values-ms-rMY/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Peranti"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Butang Hantar"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butang hantar. Sambungan diputuskan"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butang hantar. Menyambung"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butang hantar. Disambungkan"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Hantar ke"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari peranti"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Kembangkan"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Runtuhkan"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Seni album"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Peluncur kelantangan"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tiada media dipilih"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Maklumat tidak tersedia"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Menghantar skrin"</string>
diff --git a/v7/mediarouter/res/values-my-rMM/strings.xml b/v7/mediarouter/res/values-my-rMM/strings.xml
index eca8835..e31cc92 100644
--- a/v7/mediarouter/res/values-my-rMM/strings.xml
+++ b/v7/mediarouter/res/values-my-rMM/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"စနစ်"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"စက်ပစ္စည်းများ"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ကာစ်တ်လုပ်ရန် ခလုတ်"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ကာစ်ခလုတ်။ ချိတ်ဆက်မထားပါ"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ကာစ်ခလုတ်။ ချိတ်ဆက်နေသည်"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"ကာစ်ခလုတ်။ ချိတ်ဆက်ထားသည်"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"သို့ ကာစ်တ်လုပ်ရန်"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"စက်ပစ္စည်းများ ရှာဖွေခြင်း"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ဆက်သွယ်မှု ဖြတ်ရန်"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"ဖြန့်ချရန်၃"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"ခေါက်သိမ်းရန်..."</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"အယ်လ်ဘမ်ပုံ"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"အသံအတိုးအကျယ်ချိန်သည့် ဆလိုက်ဒါ"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"မည်သည့်မီဒီမှ မရွေးချယ်ထားပါ"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"အချက်အလက် မရရှိနိုင်ပါ"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"တည်းဖြတ်ရေး မျက်နှာပြင်"</string>
diff --git a/v7/mediarouter/res/values-nb/strings.xml b/v7/mediarouter/res/values-nb/strings.xml
index 27f9f03..97ca73c 100644
--- a/v7/mediarouter/res/values-nb/strings.xml
+++ b/v7/mediarouter/res/values-nb/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast-ikonet"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knappen. Frakoblet"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knappen. Kobler til"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knappen. Tilkoblet"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Finner enheter"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Koble fra"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Utvid"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafikk"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Glidebryter for volum"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Du har ikke valgt noen medier"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ingen informasjon er tilgjengelig"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Caster skjermen"</string>
diff --git a/v7/mediarouter/res/values-ne-rNP/strings.xml b/v7/mediarouter/res/values-ne-rNP/strings.xml
index 6abadbf..0e48b45 100644
--- a/v7/mediarouter/res/values-ne-rNP/strings.xml
+++ b/v7/mediarouter/res/values-ne-rNP/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"प्रणाली"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"उपकरणहरू"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast बटन"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast बटन। जडान विच्छेद भयो"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast बटन। जडान हुँदै"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast बटन। जडान भयो"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"यसमा Cast गर्नुहोस्"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"यन्त्रहरू पत्ता लगाउँदै"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"विच्छेद गर्नुहोस्"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तार गर्नुहोस्"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त पार्नुहोस्"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"एल्बम आर्ट"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"भोल्युमको स्लाइडर"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"कुनै मिडिया चयन भएको छैन"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"जानकारी उपलब्ध छैन"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रिन cast गर्दै"</string>
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/res/values-nl/strings.xml
index 4a9346d..5c899fd 100644
--- a/v7/mediarouter/res/values-nl/strings.xml
+++ b/v7/mediarouter/res/values-nl/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Systeem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Apparaten"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast-icoon"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-icoon. Verbinding verbroken"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-icoon. Verbinding maken"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-icoon. Verbonden"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Casten naar"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Apparaten zoeken"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Loskoppelen"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Uitvouwen"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Samenvouwen"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albumhoes"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volumeschuifregelaar"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Geen media geselecteerd"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Geen informatie beschikbaar"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Scherm casten"</string>
diff --git a/v7/mediarouter/res/values-pa-rIN/strings.xml b/v7/mediarouter/res/values-pa-rIN/strings.xml
index 842a8b4..258529d 100644
--- a/v7/mediarouter/res/values-pa-rIN/strings.xml
+++ b/v7/mediarouter/res/values-pa-rIN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"ਸਿਸਟਮ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ਡਿਵਾਈਸਾਂ"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ਕਾਸਟ ਬਟਨ"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ਕਾਸਟ ਬਟਨ। ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ਕਾਸਟ ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"ਕਾਸਟ ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"ਇਸ ਨਾਲ ਕਾਸਟ ਕਰੋ"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"ਡਿਵਾਈਸਾਂ ਲੱਭ ਰਿਹਾ ਹੈ"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"ਬੰਦ ਕਰੋ"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ਐਲਬਮ ਆਰਟ"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ਵੌਲਯੂਮ ਸਲਾਈਡਰ"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ਕੋਈ ਵੀ ਮੀਡੀਆ ਨਹੀਂ ਚੁਣਿਆ ਗਿਆ"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"ਕੋਈ ਜਾਣਕਾਰੀ ਉਪਲਬਧ ਨਹੀਂ"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"ਸਕ੍ਰੀਨ ਜੋੜ ਰਿਹਾ ਹੈ"</string>
diff --git a/v7/mediarouter/res/values-pl/strings.xml b/v7/mediarouter/res/values-pl/strings.xml
index d66be1a..0320550 100644
--- a/v7/mediarouter/res/values-pl/strings.xml
+++ b/v7/mediarouter/res/values-pl/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Urządzenia"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Przycisk Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Przycisk Prześlij ekran. Rozłączono"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Przycisk Prześlij ekran. Łączę"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Przycisk Prześlij ekran. Połączono"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Przesyłaj na"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Znajdowanie urządzeń"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Odłącz"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozwiń"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zwiń"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Okładka albumu"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Suwak głośności"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nie wybrano multimediów"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Brak informacji"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Przesyłam ekran"</string>
diff --git a/v7/mediarouter/res/values-pt-rBR/strings.xml b/v7/mediarouter/res/values-pt-rBR/strings.xml
index 4d7e6cc..2fd84b1 100644
--- a/v7/mediarouter/res/values-pt-rBR/strings.xml
+++ b/v7/mediarouter/res/values-pt-rBR/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão \"Transmitir\". Desconectado"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão \"Transmitir\". Conectando"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão \"Transmitir\". Conectado"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Localizando dispositivos"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Arte do álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controle deslizante de volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhuma mídia selecionada"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitindo a tela"</string>
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/res/values-pt-rPT/strings.xml
index 0c68b92..b62f363 100644
--- a/v7/mediarouter/res/values-pt-rPT/strings.xml
+++ b/v7/mediarouter/res/values-pt-rPT/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão Transmitir. Desligado"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão Transmitir. A ligar..."</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão Transmitir. Ligado"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"A localizar dispositivos"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Desassociar"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Reduzir"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Imagem do álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controlo de deslize do volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhum suporte multimédia selecionado"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"A transmitir o ecrã"</string>
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/res/values-pt/strings.xml
index 4d7e6cc..2fd84b1 100644
--- a/v7/mediarouter/res/values-pt/strings.xml
+++ b/v7/mediarouter/res/values-pt/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão \"Transmitir\". Desconectado"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão \"Transmitir\". Conectando"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão \"Transmitir\". Conectado"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Localizando dispositivos"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Arte do álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controle deslizante de volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhuma mídia selecionada"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitindo a tela"</string>
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/res/values-ro/strings.xml
index 9fe26a9..769a0ac 100644
--- a/v7/mediarouter/res/values-ro/strings.xml
+++ b/v7/mediarouter/res/values-ro/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispozitive"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Butonul de proiecție"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butonul de proiecție. Deconectat"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butonul de proiecție. Se conectează"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butonul de proiecție. Conectat"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Proiectați pe"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Se caută dispozitive"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Deconectați-vă"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Extindeți"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Restrângeți"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Grafica albumului"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Glisor pentru volum"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Niciun fișier media selectat"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nu sunt disponibile informații"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Se proiectează ecranul"</string>
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/res/values-ru/strings.xml
index 4607a8c..9bd2170 100644
--- a/v7/mediarouter/res/values-ru/strings.xml
+++ b/v7/mediarouter/res/values-ru/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляции"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляции. Устройство отключено."</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляции. Устройство подключается."</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляции. Устройство подключено."</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Выберите устройство"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Поиск устройств…"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Отключить"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Развернуть"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свернуть"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Обложка"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Регулятор громкости"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медиафайл не выбран"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Данных нет"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Подключение к удаленному монитору"</string>
diff --git a/v7/mediarouter/res/values-si-rLK/strings.xml b/v7/mediarouter/res/values-si-rLK/strings.xml
index 144a0d5..baeac3e 100644
--- a/v7/mediarouter/res/values-si-rLK/strings.xml
+++ b/v7/mediarouter/res/values-si-rLK/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"පද්ධතිය"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"උපාංග"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"විකාශ බොත්තම"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"විකාශ බොත්තම. විසන්ධි කරන ලදී"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"විකාශ බොත්තම සම්බන්ධ කරමින්"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"විකාශ බොත්තම සම්බන්ධ කරන ලදී"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"විකාශය"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"උපාංග සෙවීම"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"විසන්ධි කරන්න"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"දිග හරින්න"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"හකුළන්න"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ඇල්බම කලාව"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"හඬ පරිමා ස්ලයිඩරය"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"මාධ්යය තෝරා නැත"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"ලබා ගත හැකි තොරතුරු නොමැත"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"විකාශ තිරය"</string>
diff --git a/v7/mediarouter/res/values-sk/strings.xml b/v7/mediarouter/res/values-sk/strings.xml
index b546bde..4a0f4bf 100644
--- a/v7/mediarouter/res/values-sk/strings.xml
+++ b/v7/mediarouter/res/values-sk/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Systém"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Zariadenia"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Tlačidlo prenosu"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tlačidlo prenosu. Odpojené"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tlačidlo prenosu. Pripája sa"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tlačidlo prenosu. Pripojené"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Prenos do"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Vyhľadávanie zariadení"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojiť"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbaliť"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zbaliť"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Obrázok albumu"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Posúvač hlasitosti"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nie sú vybrané žiadne médiá"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nie sú k dispozícii žiadne informácie"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prenáša sa obrazovka"</string>
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/res/values-sl/strings.xml
index 110c548..4ca2bdc 100644
--- a/v7/mediarouter/res/values-sl/strings.xml
+++ b/v7/mediarouter/res/values-sl/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Naprave"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za predvajanje"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Gumb za predvajanje. Povezava je prekinjena."</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Gumb za predvajanje. Vzpostavljanje povezave."</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Gumb za predvajanje. Povezava je vzpostavljena."</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Predvajanje prek:"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Iskanje naprav"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini povezavo"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Razširi"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Strni"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Naslovnica albuma"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Drsnik za glasnost"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ni izbrane predstavnosti"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Podatki niso na voljo"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Predvajanje zaslona"</string>
diff --git a/v7/mediarouter/res/values-sq-rAL/strings.xml b/v7/mediarouter/res/values-sq-rAL/strings.xml
index 8ed93c3..45e3a34 100644
--- a/v7/mediarouter/res/values-sq-rAL/strings.xml
+++ b/v7/mediarouter/res/values-sq-rAL/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistemi"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Pajisjet"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Butoni i transmetimit"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butoni i transmetimit. Je i shkëputur"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butoni i transmetimit. Po lidhet"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butoni i transmetimit. Je i lidhur"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Transmeto te"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Gjetja e pajisjeve"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Shkëpute"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Zgjeroje"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Palose"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Kopertina e albumit"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Rrëshqitësi i volumit"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nuk u zgjodh asnjë media"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nuk jepet asnjë informacion"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Po transmeton ekranin"</string>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
index 5a72bd4..bddc045 100644
--- a/v7/mediarouter/res/values-sr/strings.xml
+++ b/v7/mediarouter/res/values-sr/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Уређаји"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Дугме Пребаци"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Дугме Пребаци. Веза је прекинута"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Дугме Пребаци. Повезује се"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Дугме Пребаци. Повезан је"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Пребацујте на"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Проналажење уређаја"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Прекини везу"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Скупи"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Омот албума"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Клизач за јачину звука"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Нема изабраних медија"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Нису доступне никакве информације"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Пребацује се екран"</string>
diff --git a/v7/mediarouter/res/values-sv/strings.xml b/v7/mediarouter/res/values-sv/strings.xml
index 3724902..9597bf9 100644
--- a/v7/mediarouter/res/values-sv/strings.xml
+++ b/v7/mediarouter/res/values-sv/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knappen"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knappen. Frånkopplad"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knappen. Ansluter"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knappen. Ansluten"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Casta till"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Letar efter enheter"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Koppla från"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Utöka"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Komprimera"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Skivomslag"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volymreglage"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Inga media har valts"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Det finns ingen information"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skärmen castas"</string>
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/res/values-sw/strings.xml
index f12fd5c..f7ae8f5 100644
--- a/v7/mediarouter/res/values-sw/strings.xml
+++ b/v7/mediarouter/res/values-sw/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Mfumo"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Vifaa"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Kitufe cha kutuma"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Kitufe cha kutuma. Kimeondolewa"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Kitufe cha kutuma. Kinaunganisha"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Kitufe cha kutuma. Kimeunganishwa"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Tuma kwenye"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Inatafuta vifaa"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Ondoa"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Panua"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Kunja"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Sanaa ya albamu"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Kitelezi cha sauti"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Hakuna maudhui yaliyochaguliwa"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Hakuna maelezo yaliyopatikana"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Inatuma skrini"</string>
diff --git a/v7/mediarouter/res/values-ta-rIN/strings.xml b/v7/mediarouter/res/values-ta-rIN/strings.xml
index c314178..0ef3fc3 100644
--- a/v7/mediarouter/res/values-ta-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ta-rIN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"அமைப்பு"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"திரையிடு பட்டன்"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"அனுப்புதல் பொத்தான். துண்டிக்கப்பட்டது"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"அனுப்புதல் பொத்தான். இணைக்கிறது"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"அனுப்புதல் பொத்தான். இணைக்கப்பட்டது"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"இதில் திரையிடு"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"சாதனங்களைத் தேடுகிறது"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"தொடர்பைத் துண்டி"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"விரிவாக்கு"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"சுருக்கு"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ஆல்பம் ஆர்ட்"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ஒலியளவு ஸ்லைடர்"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"மீடியா எதுவும் தேர்ந்தெடுக்கப்படவில்லை"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"தகவல் எதுவுமில்லை"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"திரையை அனுப்புகிறீர்கள்"</string>
diff --git a/v7/mediarouter/res/values-te-rIN/strings.xml b/v7/mediarouter/res/values-te-rIN/strings.xml
index 59a4f19..c7ae34f 100644
--- a/v7/mediarouter/res/values-te-rIN/strings.xml
+++ b/v7/mediarouter/res/values-te-rIN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"సిస్టమ్"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"పరికరాలు"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ప్రసారం చేయి బటన్"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ప్రసార బటన్. డిస్కనెక్ట్ చేయబడింది"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ప్రసార బటన్. కనెక్ట్ చేస్తోంది"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"ప్రసార బటన్. కనెక్ట్ చేయబడింది"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"దీనికి ప్రసారం చేయండి"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"పరికరాలను కనుగొంటోంది"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"డిస్కనెక్ట్ చేయి"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"విస్తరింపజేస్తుంది"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"కుదిస్తుంది"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ఆల్బమ్ ఆర్ట్"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"వాల్యూమ్ స్లయిడర్"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"మీడియా ఏదీ ఎంచుకోబడలేదు"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"సమాచారం అందుబాటులో లేదు"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"స్క్రీన్ను ప్రసారం చేస్తోంది"</string>
diff --git a/v7/mediarouter/res/values-th/strings.xml b/v7/mediarouter/res/values-th/strings.xml
index 1bfd091..219374c 100644
--- a/v7/mediarouter/res/values-th/strings.xml
+++ b/v7/mediarouter/res/values-th/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"ระบบ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"อุปกรณ์"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"ปุ่ม \"แคสต์\""</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ปุ่ม \"แคสต์\" ยกเลิกการเชื่อมต่อ"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ปุ่ม \"แคสต์\" กำลังเชื่อมต่อ"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"ปุ่ม \"แคสต์\" เชื่อมต่อแล้ว"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"แคสต์ไปยัง"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"กำลังค้นหาอุปกรณ์"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ยกเลิกการเชื่อมต่อ"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"ขยาย"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"ยุบ"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"ปกอัลบั้ม"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"แถบเลื่อนปรับระดับเสียง"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ไม่ได้เลือกสื่อไว้"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"ไม่มีข้อมูล"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"กำลังแคสต์หน้าจอ"</string>
diff --git a/v7/mediarouter/res/values-tl/strings.xml b/v7/mediarouter/res/values-tl/strings.xml
index 82396e1..e2bb7c7 100644
--- a/v7/mediarouter/res/values-tl/strings.xml
+++ b/v7/mediarouter/res/values-tl/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Mga Device"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Button na I-cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Button na I-cast. Nadiskonekta"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Button na I-cast. Kumokonekta"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Button na I-cast. Nakakonekta"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"I-cast sa"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Naghahanap ng mga device"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Idiskonekta"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Palawakin"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"I-collapse"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Slider ng volume"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Walang piniling media"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Walang available na impormasyon"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Kina-cast ang screen"</string>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
index e639963..187682f 100644
--- a/v7/mediarouter/res/values-tr/strings.xml
+++ b/v7/mediarouter/res/values-tr/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Yayın düğmesi"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayınla düğmesi. Bağlantı kesildi"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayınla düğmesi. Bağlanıyor"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayınla düğmesi. Bağlandı"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Şuraya yayınla:"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar bulunuyor"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantıyı kes"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişlet"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Daralt"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albüm kapağı"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ses düzeyi kaydırma çubuğu"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Medya seçilmedi"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Bilgi yok"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayınlanıyor"</string>
diff --git a/v7/mediarouter/res/values-uk/strings.xml b/v7/mediarouter/res/values-uk/strings.xml
index a768e2c..8c2a16a 100644
--- a/v7/mediarouter/res/values-uk/strings.xml
+++ b/v7/mediarouter/res/values-uk/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Пристрої"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляції"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляції. Від’єднано"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляції. Під’єднання"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляції. Під’єднано"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Транслювати на"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Пошук пристроїв"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Відключити"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Розгорнути"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Згорнути"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Обкладинка альбому"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Повзунок гучності"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медіа-файл не вибрано"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Немає даних"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Трансляція екрана"</string>
diff --git a/v7/mediarouter/res/values-ur-rPK/strings.xml b/v7/mediarouter/res/values-ur-rPK/strings.xml
index 5cb3b36..053373f 100644
--- a/v7/mediarouter/res/values-ur-rPK/strings.xml
+++ b/v7/mediarouter/res/values-ur-rPK/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"سسٹم"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"آلات"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"کاسٹ کرنے کا بٹن"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"کاسٹ کرنے کا بٹن۔ غیر منسلک ہے"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"کاسٹ کرنے کا بٹن۔ منسلک ہو رہا ہے"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"کاسٹ کرنے کا بٹن۔ منسلک ہے"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"اس میں کاسٹ کریں"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"آلات تلاش ہو رہے ہیں"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"غیر منسلک کریں"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"پھیلائیں"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"سکیڑیں"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"البم آرٹ"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"والیوم سلائیڈر"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"کوئی میڈیا منتخب نہیں ہے"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"کوئی معلومات دستیاب نہیں"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"سکرین کاسٹ ہو رہی ہے"</string>
diff --git a/v7/mediarouter/res/values-uz-rUZ/strings.xml b/v7/mediarouter/res/values-uz-rUZ/strings.xml
index 9955cdfd..9d1e455 100644
--- a/v7/mediarouter/res/values-uz-rUZ/strings.xml
+++ b/v7/mediarouter/res/values-uz-rUZ/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Tizim"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Qurilmalar"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Translatsiya tugmasi"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Translatsiya tugmasi. Uzildi"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Translatsiya tugmasi. Ulanmoqda"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Translatsiya tugmasi. Ulandi"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Quyidagiga translatsiya qilish:"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Qurilmalarni topish"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Ulanishni uzish"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Yoyish"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Yig‘ish"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Albom muqovasi"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ovoz balandligi slayderi"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Multimedia tanlamagan"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Hech qanday ma’lumot yo‘q"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekranni translatsiya qilish"</string>
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/res/values-vi/strings.xml
index 0080e3e..488b9f0 100644
--- a/v7/mediarouter/res/values-vi/strings.xml
+++ b/v7/mediarouter/res/values-vi/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Hệ thống"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Thiết bị"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Nút truyền"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Nút truyền. Đã ngắt kết nối"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Nút truyền. Đang kết nối"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Nút truyền. Đã kết nối"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Truyền tới"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Tìm thiết bị"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Ngắt kết nối"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Mở rộng"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Thu gọn"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Ảnh bìa album"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Thanh trượt âm lượng"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Không có phương tiện nào được chọn"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Không có thông tin nào"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Đang truyền màn hình"</string>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
index aabe727..c22a91c 100644
--- a/v7/mediarouter/res/values-zh-rCN/strings.xml
+++ b/v7/mediarouter/res/values-zh-rCN/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"系统"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"设备"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"投射按钮"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投射按钮。已断开连接"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投射按钮。正在连接"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"投射按钮。已连接"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"投射到"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"正在查找设备"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"断开连接"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"展开"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"折叠"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"专辑封面"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑块"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"未选择任何媒体"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"没有任何相关信息"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投射屏幕"</string>
diff --git a/v7/mediarouter/res/values-zh-rHK/strings.xml b/v7/mediarouter/res/values-zh-rHK/strings.xml
index d01c823..d17469b 100644
--- a/v7/mediarouter/res/values-zh-rHK/strings.xml
+++ b/v7/mediarouter/res/values-zh-rHK/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投放按鈕。已解除連接"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投放按鈕。正在連接"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"投放按鈕。已連接"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"投放至"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"正在尋找裝置"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"中斷連線"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"專輯封面"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑桿"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"尚未選擇媒體"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"沒有詳細資料"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投放螢幕"</string>
diff --git a/v7/mediarouter/res/values-zh-rTW/strings.xml b/v7/mediarouter/res/values-zh-rTW/strings.xml
index 68347e5..1a71c84 100644
--- a/v7/mediarouter/res/values-zh-rTW/strings.xml
+++ b/v7/mediarouter/res/values-zh-rTW/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投放按鈕;已中斷連線"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投放按鈕;連線中"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"投放按鈕;已連線"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"投放到"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"正在尋找裝置"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"中斷連線"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"專輯封面"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑桿"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"未選取任何媒體"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"沒有可用的資訊"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投放螢幕"</string>
diff --git a/v7/mediarouter/res/values-zu/strings.xml b/v7/mediarouter/res/values-zu/strings.xml
index e50acc8..860aa09 100644
--- a/v7/mediarouter/res/values-zu/strings.xml
+++ b/v7/mediarouter/res/values-zu/strings.xml
@@ -19,6 +19,9 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"Isistimu"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Amadivayisi"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"Inkinobho ye-Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Inkinobho yokusakaza. Kunqanyuliwe"</string>
+ <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Inkinobho yokusakaza. Kuyaxhunywa"</string>
+ <string name="mr_cast_button_connected" msgid="5088427771788648085">"Inkinobho yokusakaza. Kuxhunyiwe"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"Sakaza ku-"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Ithola amadivayisi"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Nqamula"</string>
@@ -29,6 +32,7 @@
<string name="mr_controller_expand_group" msgid="8062427022744266907">"Nweba"</string>
<string name="mr_controller_collapse_group" msgid="7924809056904240926">"Goqa"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"Ubuciko be-albhamu"</string>
+ <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Isilayida sevolumu"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ayikho imidiya ekhethiwe"</string>
<string name="mr_controller_no_info_available" msgid="5585418471741142924">"Alukho ulwazi olutholakalayo"</string>
<string name="mr_controller_casting_screen" msgid="4868457957151124867">"Isikrini sokusakaza"</string>
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
index 1516261..9c7747c 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
@@ -46,9 +46,9 @@
private static final String LOG_TAG = "ColorCutQuantizer";
private static final boolean LOG_TIMINGS = false;
- private static final int COMPONENT_RED = -3;
- private static final int COMPONENT_GREEN = -2;
- private static final int COMPONENT_BLUE = -1;
+ static final int COMPONENT_RED = -3;
+ static final int COMPONENT_GREEN = -2;
+ static final int COMPONENT_BLUE = -1;
private static final int QUANTIZE_WORD_WIDTH = 5;
private static final int QUANTIZE_WORD_MASK = (1 << QUANTIZE_WORD_WIDTH) - 1;
@@ -398,7 +398,7 @@
*
* @see Vbox#findSplitPoint()
*/
- private static void modifySignificantOctet(final int[] a, final int dimension,
+ static void modifySignificantOctet(final int[] a, final int dimension,
final int lower, final int upper) {
switch (dimension) {
case COMPONENT_RED:
@@ -469,7 +469,7 @@
/**
* Quantized RGB888 values to have a word width of {@value #QUANTIZE_WORD_WIDTH}.
*/
- private static int approximateToRgb888(int r, int g, int b) {
+ static int approximateToRgb888(int r, int g, int b) {
return Color.rgb(modifyWordWidth(r, QUANTIZE_WORD_WIDTH, 8),
modifyWordWidth(g, QUANTIZE_WORD_WIDTH, 8),
modifyWordWidth(b, QUANTIZE_WORD_WIDTH, 8));
@@ -482,21 +482,21 @@
/**
* @return red component of the quantized color
*/
- private static int quantizedRed(int color) {
+ static int quantizedRed(int color) {
return (color >> (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)) & QUANTIZE_WORD_MASK;
}
/**
* @return green component of a quantized color
*/
- private static int quantizedGreen(int color) {
+ static int quantizedGreen(int color) {
return (color >> QUANTIZE_WORD_WIDTH) & QUANTIZE_WORD_MASK;
}
/**
* @return blue component of a quantized color
*/
- private static int quantizedBlue(int color) {
+ static int quantizedBlue(int color) {
return color & QUANTIZE_WORD_MASK;
}
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
index 6d0368d..93570de 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
@@ -84,14 +84,14 @@
void onGenerated(Palette palette);
}
- private static final int DEFAULT_RESIZE_BITMAP_AREA = 160 * 160;
- private static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
+ static final int DEFAULT_RESIZE_BITMAP_AREA = 160 * 160;
+ static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
- private static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
- private static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
+ static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
+ static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
- private static final String LOG_TAG = "Palette";
- private static final boolean LOG_TIMINGS = false;
+ static final String LOG_TAG = "Palette";
+ static final boolean LOG_TIMINGS = false;
/**
* Start generating a {@link Palette} with the returned {@link Builder} instance.
@@ -151,7 +151,7 @@
private final Swatch mDominantSwatch;
- private Palette(List<Swatch> swatches, List<Target> targets) {
+ Palette(List<Swatch> swatches, List<Target> targets) {
mSwatches = swatches;
mTargets = targets;
@@ -345,7 +345,7 @@
return mDominantSwatch != null ? mDominantSwatch.getRgb() : defaultColor;
}
- private void generate() {
+ void generate() {
// We need to make sure that the scored targets are generated first. This is so that
// inherited targets have something to inherit from
for (int i = 0, count = mTargets.size(); i < count; i++) {
@@ -951,7 +951,7 @@
/**
* The default filter.
*/
- private static final Filter DEFAULT_FILTER = new Filter() {
+ static final Filter DEFAULT_FILTER = new Filter() {
private static final float BLACK_MAX_LIGHTNESS = 0.05f;
private static final float WHITE_MIN_LIGHTNESS = 0.95f;
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Target.java b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
index d1e0742..640970b 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Target.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
@@ -47,13 +47,13 @@
private static final float WEIGHT_LUMA = 0.52f;
private static final float WEIGHT_POPULATION = 0.24f;
- private static final int INDEX_MIN = 0;
- private static final int INDEX_TARGET = 1;
- private static final int INDEX_MAX = 2;
+ static final int INDEX_MIN = 0;
+ static final int INDEX_TARGET = 1;
+ static final int INDEX_MAX = 2;
- private static final int INDEX_WEIGHT_SAT = 0;
- private static final int INDEX_WEIGHT_LUMA = 1;
- private static final int INDEX_WEIGHT_POP = 2;
+ static final int INDEX_WEIGHT_SAT = 0;
+ static final int INDEX_WEIGHT_LUMA = 1;
+ static final int INDEX_WEIGHT_POP = 2;
/**
* A target which has the characteristics of a vibrant color which is light in luminance.
@@ -111,18 +111,18 @@
setDefaultMutedSaturationValues(DARK_MUTED);
}
- private final float[] mSaturationTargets = new float[3];
- private final float[] mLightnessTargets = new float[3];
- private final float[] mWeights = new float[3];
- private boolean mIsExclusive = true; // default to true
+ final float[] mSaturationTargets = new float[3];
+ final float[] mLightnessTargets = new float[3];
+ final float[] mWeights = new float[3];
+ boolean mIsExclusive = true; // default to true
- private Target() {
+ Target() {
setTargetDefaultValues(mSaturationTargets);
setTargetDefaultValues(mLightnessTargets);
setDefaultWeights();
}
- private Target(Target from) {
+ Target(Target from) {
System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
mSaturationTargets.length);
System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
index d419dd2..4762548 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
@@ -19,6 +19,7 @@
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
@@ -295,7 +296,7 @@
final View view = inflater.inflate(pl.resId, parent, false);
if (view.getBackground() == null) {
- view.setBackgroundDrawable(background);
+ ViewCompat.setBackground(view, background);
}
final ViewGroup widgetFrame = (ViewGroup) view.findViewById(android.R.id.widget_frame);
diff --git a/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java b/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java
new file mode 100644
index 0000000..6229b20
--- /dev/null
+++ b/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * DividerItemDecoration is a {@link RecyclerView.ItemDecoration} that can be used as a divider
+ * between items of a {@link LinearLayoutManager}. It supports both {@link #HORIZONTAL} and
+ * {@link #VERTICAL} orientations.
+ *
+ * <pre>
+ * mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
+ * mLayoutManager.getOrientation());
+ * recyclerView.addItemDecoration(mDividerItemDecoration);
+ * </pre>
+ */
+public class DividerItemDecoration extends RecyclerView.ItemDecoration {
+ public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+ public static final int VERTICAL = LinearLayout.VERTICAL;
+
+ private static final int[] ATTRS = new int[]{ android.R.attr.listDivider };
+
+ private Drawable mDivider;
+
+ /**
+ * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}.
+ */
+ private int mOrientation;
+
+ private final Rect mBounds = new Rect();
+
+ /**
+ * Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a
+ * {@link LinearLayoutManager}.
+ *
+ * @param context Current context, it will be used to access resources.
+ * @param orientation Divider orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}.
+ */
+ public DividerItemDecoration(Context context, int orientation) {
+ final TypedArray a = context.obtainStyledAttributes(ATTRS);
+ mDivider = a.getDrawable(0);
+ a.recycle();
+ setOrientation(orientation);
+ }
+
+ /**
+ * Sets the orientation for this divider. This should be called if
+ * {@link RecyclerView.LayoutManager} changes orientation.
+ *
+ * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
+ */
+ public void setOrientation(int orientation) {
+ if (orientation != HORIZONTAL && orientation != VERTICAL) {
+ throw new IllegalArgumentException(
+ "Invalid orientation. It should be either HORIZONTAL or VERTICAL");
+ }
+ mOrientation = orientation;
+ }
+
+ /**
+ * Sets the {@link Drawable} for this divider.
+ *
+ * @param drawable Drawable that should be used as a divider.
+ */
+ public void setDrawable(@NonNull Drawable drawable) {
+ if (drawable == null) {
+ throw new IllegalArgumentException("Drawable cannot be null.");
+ }
+ mDivider = drawable;
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ if (parent.getLayoutManager() == null) {
+ return;
+ }
+ if (mOrientation == VERTICAL) {
+ drawVertical(c, parent);
+ } else {
+ drawHorizontal(c, parent);
+ }
+ }
+
+ private void drawVertical(Canvas canvas, RecyclerView parent) {
+ canvas.save();
+ final int left;
+ final int right;
+ if (parent.getClipToPadding()) {
+ left = parent.getPaddingLeft();
+ right = parent.getWidth() - parent.getPaddingRight();
+ canvas.clipRect(left, parent.getPaddingTop(), right,
+ parent.getHeight() - parent.getPaddingBottom());
+ } else {
+ left = 0;
+ right = parent.getWidth();
+ }
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = parent.getChildAt(i);
+ parent.getDecoratedBoundsWithMargins(child, mBounds);
+ final int bottom = mBounds.bottom + Math.round(ViewCompat.getTranslationY(child));
+ final int top = bottom - mDivider.getIntrinsicHeight();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(canvas);
+ }
+ canvas.restore();
+ }
+
+ private void drawHorizontal(Canvas canvas, RecyclerView parent) {
+ canvas.save();
+ final int top;
+ final int bottom;
+ if (parent.getClipToPadding()) {
+ top = parent.getPaddingTop();
+ bottom = parent.getHeight() - parent.getPaddingBottom();
+ canvas.clipRect(parent.getPaddingLeft(), top,
+ parent.getWidth() - parent.getPaddingRight(), bottom);
+ } else {
+ top = 0;
+ bottom = parent.getHeight();
+ }
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = parent.getChildAt(i);
+ parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);
+ final int right = mBounds.right + Math.round(ViewCompat.getTranslationX(child));
+ final int left = right - mDivider.getIntrinsicWidth();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(canvas);
+ }
+ canvas.restore();
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+ RecyclerView.State state) {
+ if (mOrientation == VERTICAL) {
+ outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
+ } else {
+ outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
+ }
+ }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
index 4d19163..4293852 100644
--- a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
@@ -505,6 +505,27 @@
}
@Override
+ int getItemPrefetchCount() {
+ return mSpanCount;
+ }
+
+ @Override
+ int gatherPrefetchIndicesForLayoutState(RecyclerView.State state, LayoutState layoutState,
+ int[] outIndices) {
+ int remainingSpan = mSpanCount;
+ int count = 0;
+ while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) {
+ final int pos = layoutState.mCurrentPosition;
+ outIndices[count] = pos;
+ final int spanSize = mSpanSizeLookup.getSpanSize(pos);
+ remainingSpan -= spanSize;
+ layoutState.mCurrentPosition += layoutState.mItemDirection;
+ count++;
+ }
+ return count;
+ }
+
+ @Override
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, LayoutChunkResult result) {
final int otherDirSpecMode = mOrientationHelper.getModeInOther();
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index 5ee2537..5fbb67c 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -1180,6 +1180,36 @@
&& mOrientationHelper.getEnd() == 0;
}
+ @Override
+ int getItemPrefetchCount() {
+ return 1;
+ }
+
+ int gatherPrefetchIndicesForLayoutState(RecyclerView.State state, LayoutState layoutState,
+ int[] outIndices) {
+ final int pos = layoutState.mCurrentPosition;
+ if (pos >= 0 && pos < state.getItemCount()) {
+ outIndices[0] = pos;
+ return 1;
+ }
+ return 0;
+ }
+
+ @Override
+ int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) {
+ int delta = (mOrientation == HORIZONTAL) ? dx : dy;
+ if (getChildCount() == 0 || delta == 0) {
+ // can't support this scroll, so don't bother prefetching
+ return 0;
+ }
+
+
+ final int layoutDirection = delta > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
+ final int absDy = Math.abs(delta);
+ updateLayoutState(layoutDirection, absDy, true, state);
+ return gatherPrefetchIndicesForLayoutState(state, mLayoutState, outIndices);
+ }
+
int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getChildCount() == 0 || dy == 0) {
return 0;
@@ -1323,7 +1353,6 @@
}
}
}
-
}
/**
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 87ebb16..47e9933 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -58,6 +58,7 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TypedValue;
+import android.view.Display;
import android.view.FocusFinder;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -74,8 +75,10 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import static android.support.v7.widget.AdapterHelper.Callback;
import static android.support.v7.widget.AdapterHelper.UpdateOp;
@@ -174,6 +177,14 @@
*/
static final boolean ALLOW_SIZE_IN_UNSPECIFIED_SPEC = Build.VERSION.SDK_INT >= 23;
+ static final boolean POST_UPDATES_ON_ANIMATION = Build.VERSION.SDK_INT >= 16;
+
+ /**
+ * On L+, with RenderThread, the UI thread has idle time after it has passed a frame off to
+ * RenderThread but before the next frame begins. We schedule prefetch work in this window.
+ */
+ private static final boolean ALLOW_PREFETCHING = Build.VERSION.SDK_INT >= 21;
+
static final boolean DISPATCH_TEMP_DETACH = false;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
@@ -237,6 +248,11 @@
private static final String TRACE_BIND_VIEW_TAG = "RV OnBindView";
/**
+ * RecyclerView is attempting to pre-populate off screen views.
+ */
+ private static final String TRACE_PREFETCH_TAG = "RV Prefetch";
+
+ /**
* RecyclerView is creating a new View.
* If too many of these present in Systrace:
* - There might be a problem in Recycling (e.g. custom Animations that set transient state and
@@ -330,7 +346,7 @@
// binary OR of change events that were eaten during a layout or scroll.
private int mEatenAccessibilityChangeFlags;
private boolean mAdapterUpdateDuringMeasure;
- private final boolean mPostUpdatesOnAnimation;
+
private final AccessibilityManager mAccessibilityManager;
private List<OnChildAttachStateChangeListener> mOnChildAttachStateListeners;
@@ -403,6 +419,9 @@
private final ViewFlinger mViewFlinger = new ViewFlinger();
+ private static final long MIN_PREFETCH_TIME_NANOS = TimeUnit.MILLISECONDS.toNanos(4);
+ ViewPrefetcher mViewPrefetcher = ALLOW_PREFETCHING ? new ViewPrefetcher() : null;
+
final State mState = new State();
private OnScrollListener mScrollListener;
@@ -501,8 +520,6 @@
}
setScrollContainer(true);
setFocusableInTouchMode(true);
- final int version = Build.VERSION.SDK_INT;
- mPostUpdatesOnAnimation = version >= 16;
final ViewConfiguration vc = ViewConfiguration.get(context);
mTouchSlop = vc.getScaledTouchSlop();
@@ -854,6 +871,22 @@
}
/**
+ * Returns whether this RecyclerView will clip its children to its padding, and resize (but
+ * not clip) any EdgeEffect to the padded region, if padding is present.
+ * <p>
+ * By default, children are clipped to the padding of their parent
+ * RecyclerView. This clipping behavior is only enabled if padding is non-zero.
+ *
+ * @return true if this RecyclerView clips children to its padding and resizes (but doesn't
+ * clip) any EdgeEffect to the padded region, false otherwise.
+ *
+ * @attr name android:clipToPadding
+ */
+ public boolean getClipToPadding() {
+ return mClipToPadding;
+ }
+
+ /**
* Configure the scrolling touch slop for a specific use case.
*
* Set up the RecyclerView's scrolling motion threshold based on common usages.
@@ -1092,6 +1125,7 @@
mLayout.dispatchAttachedToWindow(this);
}
}
+ mRecycler.updateViewCacheSize();
requestLayout();
}
@@ -2341,6 +2375,13 @@
mLayout.dispatchAttachedToWindow(this);
}
mPostedAnimatorRunner = false;
+ Display display = ViewCompat.getDisplay(this);
+ if (ALLOW_PREFETCHING
+ && display != null
+ && display.getRefreshRate() >= 30.0f) {
+ // break 60 fps assumption if data appears good
+ mViewPrefetcher.mFrameIntervalNanos = (long) (1000000000 / display.getRefreshRate());
+ }
}
@Override
@@ -2707,6 +2748,9 @@
vtev)) {
getParent().requestDisallowInterceptTouchEvent(true);
}
+ if (ALLOW_PREFETCHING) {
+ mViewPrefetcher.postFromTraversal(dx, dy);
+ }
}
} break;
@@ -4235,6 +4279,26 @@
}
}
+ /**
+ * Returns the bounds of the view including its decoration and margins.
+ *
+ * @param view The view element to check
+ * @param outBounds A rect that will receive the bounds of the element including its
+ * decoration and margins.
+ */
+ public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
+ getDecoratedBoundsWithMarginsInt(view, outBounds);
+ }
+
+ static void getDecoratedBoundsWithMarginsInt(View view, Rect outBounds) {
+ final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ final Rect insets = lp.mDecorInsets;
+ outBounds.set(view.getLeft() - insets.left - lp.leftMargin,
+ view.getTop() - insets.top - lp.topMargin,
+ view.getRight() + insets.right + lp.rightMargin,
+ view.getBottom() + insets.bottom + lp.bottomMargin);
+ }
+
Rect getItemDecorInsetsForChild(View child) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!lp.mInsetsDirty) {
@@ -4362,6 +4426,76 @@
|| mAdapterHelper.hasPendingUpdates();
}
+ /**
+ * Runs prefetch work immediately after a traversal, in the downtime while the UI thread is
+ * waiting for VSYNC.
+ */
+ class ViewPrefetcher implements Runnable {
+ long mFrameIntervalNanos = TimeUnit.MILLISECONDS.toNanos(16);
+
+ long mPostTimeNanos;
+ private int mDx;
+ private int mDy;
+
+ private int[] mItemPrefetchArray;
+
+ /**
+ * Schedule a prefetch immediately after the current traversal.
+ */
+ public void postFromTraversal(int dx, int dy) {
+ if (ALLOW_PREFETCHING
+ && mAdapter != null
+ && mLayout != null
+ && mLayout.getItemPrefetchCount() > 0) {
+ mDx = dx;
+ mDy = dy;
+ mPostTimeNanos = System.nanoTime();
+ RecyclerView.this.post(this);
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ TraceCompat.beginSection(TRACE_PREFETCH_TAG);
+ final int prefetchCount = mLayout.getItemPrefetchCount();
+ if (mAdapter == null
+ || mLayout == null
+ || !mLayout.isItemPrefetchEnabled()
+ || prefetchCount < 1
+ || hasPendingAdapterUpdates()) {
+ // abort - no work
+ return;
+ }
+
+ // Query last vsync so we can predict next one. Note that drawing time not yet
+ // valid in animation/input callbacks, so query it here to be safe.
+ long lastFrameVsyncNanos = TimeUnit.MILLISECONDS.toNanos(getDrawingTime());
+ if (lastFrameVsyncNanos == 0) {
+ // abort - couldn't get last vsync for estimating next
+ return;
+ }
+
+ long nowNanos = System.nanoTime();
+ long nextFrameNanos = lastFrameVsyncNanos + mFrameIntervalNanos;
+ if (nowNanos - mPostTimeNanos > mFrameIntervalNanos
+ || nextFrameNanos - nowNanos < MIN_PREFETCH_TIME_NANOS) {
+ // abort - Executing either too far after post, or too near next scheduled vsync
+ return;
+ }
+
+ if (mItemPrefetchArray == null || mItemPrefetchArray.length < prefetchCount) {
+ mItemPrefetchArray = new int[prefetchCount];
+ }
+ Arrays.fill(mItemPrefetchArray, -1);
+ int viewCount = mLayout.gatherPrefetchIndices(mDx, mDy, mState, mItemPrefetchArray);
+ mRecycler.prefetch(mItemPrefetchArray, viewCount);
+ } finally {
+ TraceCompat.endSection();
+ }
+ }
+ }
+
private class ViewFlinger implements Runnable {
private int mLastFlingX;
private int mLastFlingY;
@@ -4478,6 +4612,9 @@
setScrollState(SCROLL_STATE_IDLE); // setting state to idle will stop this.
} else {
postOnAnimation();
+ if (ALLOW_PREFETCHING) {
+ mViewPrefetcher.postFromTraversal(dx, dy);
+ }
}
}
// call this after the onAnimation is complete not to have inconsistent callbacks etc.
@@ -4651,7 +4788,7 @@
}
void triggerUpdateProcessor() {
- if (mPostUpdatesOnAnimation && mHasFixedSize && mIsAttached) {
+ if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
@@ -4794,13 +4931,14 @@
private final List<ViewHolder>
mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
- private int mViewCacheMax = DEFAULT_CACHE_SIZE;
+ private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
+ int mViewCacheMax = DEFAULT_CACHE_SIZE;
private RecycledViewPool mRecyclerPool;
private ViewCacheExtension mViewCacheExtension;
- private static final int DEFAULT_CACHE_SIZE = 2;
+ static final int DEFAULT_CACHE_SIZE = 2;
/**
* Clear scrap views out of this recycler. Detached views contained within a
@@ -4817,9 +4955,19 @@
* @param viewCount Number of views to keep before sending views to the shared pool
*/
public void setViewCacheSize(int viewCount) {
- mViewCacheMax = viewCount;
+ mRequestedCacheMax = viewCount;
+ updateViewCacheSize();
+ }
+
+ void updateViewCacheSize() {
+ int extraCache = 0;
+ if (mLayout != null && ALLOW_PREFETCHING) {
+ extraCache = mLayout.isItemPrefetchEnabled() ? mLayout.getItemPrefetchCount() : 0;
+ }
+ mViewCacheMax = mRequestedCacheMax + extraCache;
// first, try the views that can be recycled
- for (int i = mCachedViews.size() - 1; i >= 0 && mCachedViews.size() > viewCount; i--) {
+ for (int i = mCachedViews.size() - 1;
+ i >= 0 && mCachedViews.size() > mViewCacheMax; i--) {
recycleCachedViewAt(i);
}
}
@@ -5698,6 +5846,21 @@
}
}
}
+
+ void prefetch(int[] itemPrefetchArray, int viewCount) {
+ if (viewCount == 0) return;
+
+ int childPosition = itemPrefetchArray[viewCount - 1];
+ if (childPosition < 0) {
+ throw new IllegalArgumentException("Recycler requested to prefetch invalid view "
+ + childPosition);
+ }
+ View prefetchView = getViewForPosition(childPosition);
+ if (viewCount > 1) {
+ prefetch(itemPrefetchArray, viewCount - 1);
+ }
+ recycleView(prefetchView);
+ }
}
/**
@@ -6343,6 +6506,7 @@
*/
private boolean mMeasurementCacheEnabled = true;
+ private boolean mItemPrefetchEnabled = true;
/**
* These measure specs might be the measure specs that were passed into RecyclerView's
@@ -6624,6 +6788,52 @@
return false;
}
+ /**
+ * Sets whether the LayoutManager should be queried for views outside of
+ * its viewport while the UI thread is idle between frames.
+ *
+ * <p>If enabled, the LayoutManager will be queried for items to inflate/bind in between
+ * view system traversals on devices running API 21 or greater. Default value is true.</p>
+ *
+ * <p>On platforms API level 21 and higher, the UI thread is idle between passing a frame
+ * to RenderThread and the starting up its next frame at the next VSync pulse. By
+ * prefetching out of window views in this time period, delays from inflation and view
+ * binding are much less likely to cause jank and stuttering during scrolls and flings.</p>
+ *
+ * <p>While prefetch is enabled, it will have the side effect of expanding the effective
+ * size of the View cache to hold prefetched views.</p>
+ *
+ * @param enabled <code>True</code> if items should be prefetched in between traversals.
+ *
+ * @see #isItemPrefetchEnabled()
+ */
+ public final void setItemPrefetchEnabled(boolean enabled) {
+ if (enabled != mItemPrefetchEnabled) {
+ mItemPrefetchEnabled = enabled;
+ if (mRecyclerView != null) {
+ mRecyclerView.mRecycler.updateViewCacheSize();
+ }
+ }
+ }
+
+ /**
+ * Sets whether the LayoutManager should be queried for views outside of
+ * its viewport while the UI thread is idle between frames.
+ *
+ * @see #setItemPrefetchEnabled(boolean)
+ *
+ * @return true if item prefetch is enabled, false otherwise
+ */
+ public final boolean isItemPrefetchEnabled() {
+ return mItemPrefetchEnabled;
+ }
+
+ int getItemPrefetchCount() { return 0; }
+
+ int gatherPrefetchIndices(int dx, int dy, State state, int[] outIndices) {
+ return 0;
+ }
+
void dispatchAttachedToWindow(RecyclerView view) {
mIsAttachedToWindow = true;
onAttachedToWindow(view);
@@ -8118,12 +8328,7 @@
* decoration and margins.
*/
public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
- final LayoutParams lp = (LayoutParams) view.getLayoutParams();
- final Rect insets = lp.mDecorInsets;
- outBounds.set(view.getLeft() - insets.left - lp.leftMargin,
- view.getTop() - insets.top - lp.topMargin,
- view.getRight() + insets.right + lp.rightMargin,
- view.getBottom() + insets.bottom + lp.bottomMargin);
+ RecyclerView.getDecoratedBoundsWithMarginsInt(view, outBounds);
}
/**
diff --git a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
index 12745fe..8e7f307 100644
--- a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
@@ -610,8 +610,9 @@
}
}
- if (!anchorInfo.mValid || mPendingScrollPosition != NO_POSITION ||
- mPendingSavedState != null) {
+ boolean recalculateAnchor = !anchorInfo.mValid || mPendingScrollPosition != NO_POSITION ||
+ mPendingSavedState != null;
+ if (recalculateAnchor) {
anchorInfo.reset();
if (mPendingSavedState != null) {
applyPendingSavedState(anchorInfo);
@@ -619,7 +620,6 @@
resolveShouldLayoutReverse();
anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
}
-
updateAnchorInfoForLayout(state, anchorInfo);
anchorInfo.mValid = true;
}
@@ -642,8 +642,18 @@
}
}
} else {
- for (int i = 0; i < mSpanCount; i++) {
- mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorInfo.mOffset);
+ if (recalculateAnchor || mAnchorInfo.mSpanReferenceLines == null) {
+ for (int i = 0; i < mSpanCount; i++) {
+ mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout,
+ anchorInfo.mOffset);
+ }
+ mAnchorInfo.saveSpanReferenceLines(mSpans);
+ } else {
+ for (int i = 0; i < mSpanCount; i++) {
+ final Span span = mSpans[i];
+ span.clear();
+ span.setLine(mAnchorInfo.mSpanReferenceLines[i]);
+ }
}
}
}
@@ -1056,8 +1066,8 @@
return 0;
}
return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation,
- findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
- , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
+ findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
+ findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
this, mSmoothScrollbarEnabled, mShouldReverseLayout);
}
@@ -1076,8 +1086,8 @@
return 0;
}
return ScrollbarHelper.computeScrollExtent(state, mPrimaryOrientation,
- findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
- , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
+ findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
+ findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
this, mSmoothScrollbarEnabled);
}
@@ -1096,8 +1106,8 @@
return 0;
}
return ScrollbarHelper.computeScrollRange(state, mPrimaryOrientation,
- findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
- , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
+ findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
+ findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
this, mSmoothScrollbarEnabled);
}
@@ -1250,8 +1260,8 @@
if (getChildCount() > 0) {
final AccessibilityRecordCompat record = AccessibilityEventCompat
.asRecord(event);
- final View start = findFirstVisibleItemClosestToStart(false, true);
- final View end = findFirstVisibleItemClosestToEnd(false, true);
+ final View start = findFirstVisibleItemClosestToStart(false);
+ final View end = findFirstVisibleItemClosestToEnd(false);
if (start == null || end == null) {
return;
}
@@ -1273,8 +1283,8 @@
* of returning null.
*/
int findFirstVisibleItemPositionInt() {
- final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true, true) :
- findFirstVisibleItemClosestToStart(true, true);
+ final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true) :
+ findFirstVisibleItemClosestToStart(true);
return first == null ? NO_POSITION : getPosition(first);
}
@@ -1302,7 +1312,7 @@
* This method does not do any sorting based on child's start coordinate, instead, it uses
* children order.
*/
- View findFirstVisibleItemClosestToStart(boolean fullyVisible, boolean acceptPartiallyVisible) {
+ View findFirstVisibleItemClosestToStart(boolean fullyVisible) {
final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
final int limit = getChildCount();
@@ -1319,7 +1329,7 @@
// as long as fully visible is not requested.
return child;
}
- if (acceptPartiallyVisible && partiallyVisible == null) {
+ if (partiallyVisible == null) {
partiallyVisible = child;
}
}
@@ -1332,7 +1342,7 @@
* This method does not do any sorting based on child's end coordinate, instead, it uses
* children order.
*/
- View findFirstVisibleItemClosestToEnd(boolean fullyVisible, boolean acceptPartiallyVisible) {
+ View findFirstVisibleItemClosestToEnd(boolean fullyVisible) {
final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
View partiallyVisible = null;
@@ -1348,7 +1358,7 @@
// as long as fully visible is not requested.
return child;
}
- if (acceptPartiallyVisible && partiallyVisible == null) {
+ if (partiallyVisible == null) {
partiallyVisible = child;
}
}
@@ -2085,6 +2095,8 @@
mPrimaryOrientation.offsetChildren(-totalScroll);
// always reset this if we scroll for a proper save instance state
mLastLayoutFromEnd = mShouldReverseLayout;
+ mLayoutState.mAvailable = 0;
+ recycle(recycler, mLayoutState);
return totalScroll;
}
@@ -3041,6 +3053,9 @@
boolean mLayoutFromEnd;
boolean mInvalidateOffsets;
boolean mValid;
+ // this is where we save span reference lines in case we need to re-use them for multi-pass
+ // measure steps
+ int[] mSpanReferenceLines;
public AnchorInfo() {
reset();
@@ -3052,6 +3067,20 @@
mLayoutFromEnd = false;
mInvalidateOffsets = false;
mValid = false;
+ if (mSpanReferenceLines != null) {
+ Arrays.fill(mSpanReferenceLines, -1);
+ }
+ }
+
+ void saveSpanReferenceLines(Span[] spans) {
+ int spanCount = spans.length;
+ if (mSpanReferenceLines == null || mSpanReferenceLines.length < spanCount) {
+ mSpanReferenceLines = new int[mSpans.length];
+ }
+ for (int i = 0; i < spanCount; i++) {
+ // does not matter start or end since this is only recorded when span is reset
+ mSpanReferenceLines[i] = spans[i].getStartLine(Span.INVALID_LINE);
+ }
}
void assignCoordinateFromPadding() {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
index 34b6621..3a72152 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.view.View;
+import android.view.ViewGroup;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -46,7 +47,7 @@
}
public RecyclerView setupBasic(Config config, GridTestAdapter testAdapter) throws Throwable {
- RecyclerView recyclerView = new RecyclerView(getActivity());
+ RecyclerView recyclerView = new WrappedRecyclerView(getActivity());
mAdapter = testAdapter;
mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation,
config.mReverseLayout);
@@ -149,6 +150,8 @@
CountDownLatch mLayoutLatch;
+ CountDownLatch prefetchLatch;
+
List<GridLayoutManagerTest.Callback>
mCallbacks = new ArrayList<GridLayoutManagerTest.Callback>();
@@ -227,6 +230,23 @@
});
}
+ public void expectPrefetch(int count) {
+ prefetchLatch = new CountDownLatch(count);
+ }
+
+ public void waitForPrefetch(int seconds) throws Throwable {
+ prefetchLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+ checkForMainThreadException();
+ MatcherAssert.assertThat("all prefetches should complete on time",
+ prefetchLatch.getCount(), CoreMatchers.is(0L));
+ // use a runnable to ensure RV layout is finished
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ }
+ });
+ }
+
public void expectIdleState(int count) {
snapLatch = new CountDownLatch(count);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -255,6 +275,12 @@
}
});
}
+
+ @Override
+ int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) {
+ if (prefetchLatch != null) prefetchLatch.countDown();
+ return super.gatherPrefetchIndices(dx, dy, state, outIndices);
+ }
}
class GridTestAdapter extends TestAdapter {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
index 353e84e..50c9ba3 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
@@ -345,6 +345,8 @@
CountDownLatch snapLatch;
+ CountDownLatch prefetchLatch;
+
OrientationHelper mSecondaryOrientation;
OnLayoutListener mOnLayoutListener;
@@ -370,6 +372,23 @@
});
}
+ public void expectPrefetch(int count) {
+ prefetchLatch = new CountDownLatch(count);
+ }
+
+ public void waitForPrefetch(int seconds) throws Throwable {
+ prefetchLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+ checkForMainThreadException();
+ MatcherAssert.assertThat("all prefetches should complete on time",
+ prefetchLatch.getCount(), CoreMatchers.is(0L));
+ // use a runnable to ensure RV layout is finished
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ }
+ });
+ }
+
public void expectIdleState(int count) {
snapLatch = new CountDownLatch(count);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -576,5 +595,11 @@
}
layoutLatch.countDown();
}
+
+ @Override
+ int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) {
+ if (prefetchLatch != null) prefetchLatch.countDown();
+ return super.gatherPrefetchIndices(dx, dy, state, outIndices);
+ }
}
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index 5f7f244..7a7a4d4 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -1107,11 +1107,21 @@
return Looper.myLooper() == Looper.getMainLooper();
}
- public void runTestOnUiThread(Runnable r) throws Throwable {
+ public void runTestOnUiThread(final Runnable r) throws Throwable {
if (Looper.myLooper() == Looper.getMainLooper()) {
r.run();
} else {
- InstrumentationRegistry.getInstrumentation().runOnMainSync(r);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ r.run();
+ } catch (Throwable t) {
+ postExceptionToInstrumentation(t);
+ }
+ }
+ });
+ checkForMainThreadException();
}
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
index 82f8cf0..418e5ee 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
@@ -84,8 +84,7 @@
mRecyclerView = new RecyclerView(getActivity());
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setHasFixedSize(true);
- mLayoutManager = new WrappedLayoutManager(config.mSpanCount,
- config.mOrientation);
+ mLayoutManager = new WrappedLayoutManager(config.mSpanCount, config.mOrientation);
mLayoutManager.setGapStrategy(config.mGapStrategy);
mLayoutManager.setReverseLayout(config.mReverseLayout);
mRecyclerView.setLayoutManager(mLayoutManager);
@@ -475,7 +474,7 @@
// until bug is fixed, we'll fake it.
// public issue id: 57819
Boolean mFakeRTL;
- CountDownLatch snapLatch;
+ CountDownLatch mSnapLatch;
@Override
boolean isLayoutRTL() {
@@ -500,14 +499,14 @@
}
public void expectIdleState(int count) {
- snapLatch = new CountDownLatch(count);
+ mSnapLatch = new CountDownLatch(count);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
- snapLatch.countDown();
- if (snapLatch.getCount() == 0L) {
+ mSnapLatch.countDown();
+ if (mSnapLatch.getCount() == 0L) {
mRecyclerView.removeOnScrollListener(this);
}
}
@@ -516,10 +515,10 @@
}
public void waitForSnap(int seconds) throws Throwable {
- snapLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+ mSnapLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
checkForMainThreadException();
MatcherAssert.assertThat("all scrolling should complete on time",
- snapLatch.getCount(), CoreMatchers.is(0L));
+ mSnapLatch.getCount(), CoreMatchers.is(0L));
// use a runnable to ensure RV layout is finished
getInstrumentation().runOnMainSync(new Runnable() {
@Override
@@ -854,6 +853,7 @@
/ AVG_ITEM_PER_VIEW : mRecyclerViewHeight / AVG_ITEM_PER_VIEW;
}
super.onBindViewHolder(holder, position);
+
Item item = mItems.get(position);
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
.getLayoutParams();
@@ -862,8 +862,8 @@
.setFullSpan(mFullSpanItems.contains(item.mAdapterIndex));
} else {
StaggeredGridLayoutManager.LayoutParams slp
- = (StaggeredGridLayoutManager.LayoutParams) mLayoutManager
- .generateDefaultLayoutParams();
+ = (StaggeredGridLayoutManager.LayoutParams) mLayoutManager
+ .generateDefaultLayoutParams();
holder.itemView.setLayoutParams(slp);
slp.setFullSpan(mFullSpanItems.contains(item.mAdapterIndex));
lp = slp;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
index 281745c..2dd16ef 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
@@ -501,43 +501,6 @@
return true;
}
- static class WrappedRecyclerView extends RecyclerView {
-
- public WrappedRecyclerView(Context context) {
- super(context);
- }
-
- public void waitUntilLayout() {
- while (isLayoutRequested()) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
-
- public void waitUntilAnimations() throws InterruptedException {
- final CountDownLatch latch = new CountDownLatch(1);
- if (mItemAnimator == null || !mItemAnimator.isRunning(
- new ItemAnimator.ItemAnimatorFinishedListener() {
- @Override
- public void onAnimationsFinished() {
- latch.countDown();
- }
- })) {
- latch.countDown();
- }
- MatcherAssert.assertThat("waiting too long for animations",
- latch.await(60, TimeUnit.SECONDS), CoreMatchers.is(true));
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- }
- }
-
static class WrapContentConfig {
public boolean unlimitedWidth;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
index 4ace4ca..1ebd17f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
@@ -440,13 +440,4 @@
private interface ThrowingRunnable {
void run() throws Throwable;
}
-
- @Override
- public void runTestOnUiThread(Runnable r) throws Throwable {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- r.run();
- } else {
- super.runTestOnUiThread(r);
- }
- }
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java
new file mode 100644
index 0000000..6819a6a
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+public class GridLayoutManagerCacheTest extends BaseGridLayoutManagerTest {
+
+ final Config mConfig;
+ final int mDx;
+ final int mDy;
+
+ public GridLayoutManagerCacheTest(Config config, int dx, int dy) {
+ mConfig = config;
+ mDx = dx;
+ mDy = dy;
+ }
+
+ @Parameterized.Parameters(name = "config:{0}, dx:{1}, dy:{2}")
+ public static List<Object[]> getParams() {
+ List<Object[]> result = new ArrayList<>();
+ List<Config> configs = createBaseVariations();
+ for (Config config : configs) {
+ for (int dx : new int[] {-1, 0, 1}) {
+ for (int dy : new int[] {-1, 0, 1}) {
+ result.add(new Object[]{config, dx, dy});
+ }
+ }
+ }
+ return result;
+ }
+
+ private ArrayList<RecyclerView.ViewHolder> cachedViews() {
+ return mRecyclerView.mRecycler.mCachedViews;
+ }
+
+ private boolean cachedViewsContains(int position) {
+ // Note: can't make assumptions about order here, so just check all cached views
+ for (int i = 0; i < cachedViews().size(); i++) {
+ if (cachedViews().get(i).getAdapterPosition() == position) return true;
+ }
+ return false;
+ }
+
+ @MediumTest
+ @Test
+ public void cacheAndPrefetch() throws Throwable {
+ final Config config = (Config) mConfig.clone();
+ RecyclerView recyclerView = setupBasic(config);
+ waitForFirstLayout(recyclerView);
+
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // pretend to have an extra 5s before next frame so prefetch won't abort early
+ ((WrappedRecyclerView)mRecyclerView).setDrawingTimeOffset(5000);
+
+ // scroll to the middle, so we can move in either direction
+ mRecyclerView.scrollToPosition(mConfig.mItemCount / 2);
+ }
+ });
+
+ mRecyclerView.setItemViewCacheSize(0);
+ {
+ mGlm.expectPrefetch(1);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mRecyclerView.mRecycler.recycleAndClearCachedViews();
+ mRecyclerView.mViewPrefetcher.postFromTraversal(mDx, mDy);
+
+ // Lie about post time, so prefetch executes even if it is delayed
+ mRecyclerView.mViewPrefetcher.mPostTimeNanos += TimeUnit.SECONDS.toNanos(5);
+ }
+ });
+ mGlm.waitForPrefetch(1);
+ }
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // validate cache state on UI thread
+ if ((config.mOrientation == HORIZONTAL && mDx == 0)
+ || (config.mOrientation == VERTICAL && mDy == 0)) {
+ assertEquals(0, cachedViews().size());
+ } else {
+ assertEquals(config.mSpanCount, cachedViews().size());
+
+ boolean reverseScroll = config.mOrientation == HORIZONTAL ? mDx < 0 : mDy < 0;
+ int lastVisibleItemPosition = mGlm.findLastVisibleItemPosition();
+ int firstVisibleItemPosition = mGlm.findFirstVisibleItemPosition();
+
+ for (int i = 0; i < config.mSpanCount; i++) {
+ if (mConfig.mReverseLayout == reverseScroll) {
+ // Pos scroll on pos layout, or reverse scroll on reverse layout
+ // = toward last
+ assertTrue(cachedViewsContains(lastVisibleItemPosition + 1 + i));
+ } else {
+ // Pos scroll on reverse layout, or reverse scroll on pos layout
+ // = toward first
+ assertTrue(cachedViewsContains(firstVisibleItemPosition - 1 - i));
+ }
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
index 2b33828..8211fe6 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
@@ -29,6 +29,8 @@
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.StateListDrawable;
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@@ -131,7 +133,8 @@
stl.addState(new int[]{android.R.attr.state_focused},
new ColorDrawable(Color.RED));
stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- testViewHolder.itemView.setBackground(stl);
+ //noinspection deprecation using this for kitkat tests
+ testViewHolder.itemView.setBackgroundDrawable(stl);
return testViewHolder;
}
@@ -284,11 +287,13 @@
}
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void horizontalAccessibilitySpanIndices() throws Throwable {
accessibilitySpanIndicesTest(HORIZONTAL);
}
@Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
public void verticalAccessibilitySpanIndices() throws Throwable {
accessibilitySpanIndicesTest(VERTICAL);
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
index 6f77867..1703dcd 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
@@ -27,6 +27,7 @@
import android.graphics.Rect;
import android.os.Build;
import android.support.test.filters.SdkSuppress;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.Gravity;
import android.view.View;
@@ -37,6 +38,7 @@
import java.util.Arrays;
import java.util.List;
+@MediumTest
@RunWith(Parameterized.class)
public class GridLayoutManagerWrapContentTest extends BaseWrapContentTest {
private boolean mHorizontal = false;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
index d33611c..6c311e4 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
@@ -78,7 +78,7 @@
RecyclerView.LayoutManager mLayoutManager;
- BaseWrapContentTest.WrappedRecyclerView mRecyclerView;
+ WrappedRecyclerView mRecyclerView;
OrientationHelper mHelper;
@@ -102,7 +102,7 @@
}
mLayoutManager = createFromConfig();
- mRecyclerView = new BaseWrapContentTest.WrappedRecyclerView(getActivity());
+ mRecyclerView = new WrappedRecyclerView(getActivity());
mHelper = OrientationHelper.createOrientationHelper(
mLayoutManager, 1 - mConfig.mOrientation);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java
new file mode 100644
index 0000000..cacc9f4
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.FrameLayout;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+public class LinearLayoutManagerCacheTest extends BaseLinearLayoutManagerTest {
+
+ final Config mConfig;
+ final int mDx;
+ final int mDy;
+
+ public LinearLayoutManagerCacheTest(Config config, int dx, int dy) {
+ mConfig = config;
+ mDx = dx;
+ mDy = dy;
+ }
+
+ @Parameterized.Parameters(name = "config:{0}, dx:{1}, dy:{2}")
+ public static List<Object[]> getParams() {
+ List<Object[]> result = new ArrayList<>();
+ List<Config> configs = createBaseVariations();
+ for (Config config : configs) {
+ for (int dx : new int[] {-1, 0, 1}) {
+ for (int dy : new int[] {-1, 0, 1}) {
+ result.add(new Object[]{config, dx, dy});
+ }
+ }
+ }
+ return result;
+ }
+
+ private ArrayList<RecyclerView.ViewHolder> cachedViews() {
+ return mRecyclerView.mRecycler.mCachedViews;
+ }
+
+ @MediumTest
+ @Test
+ public void cacheAndPrefetch() throws Throwable {
+ final Config config = (Config) mConfig.clone();
+
+ setupByConfig(config, true);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // pretend to have an extra 5s before next frame so prefetch won't abort early
+ ((WrappedRecyclerView)mRecyclerView).setDrawingTimeOffset(5000);
+
+ mRecyclerView.scrollToPosition(100);
+ }
+ });
+
+ mRecyclerView.setItemViewCacheSize(0);
+ {
+ mLayoutManager.expectPrefetch(1);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mRecyclerView.mRecycler.recycleAndClearCachedViews();
+ mRecyclerView.mViewPrefetcher.postFromTraversal(mDx, mDy);
+
+ // Lie about post time, so prefetch executes even if it is delayed
+ mRecyclerView.mViewPrefetcher.mPostTimeNanos += TimeUnit.SECONDS.toNanos(5);
+ }
+ });
+ mLayoutManager.waitForPrefetch(1);
+ }
+
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // validate cache state on UI thread
+ if ((config.mOrientation == HORIZONTAL && mDx == 0)
+ || (config.mOrientation == VERTICAL && mDy == 0)) {
+ assertEquals(0, cachedViews().size());
+ } else {
+ boolean reverseScroll = config.mOrientation == HORIZONTAL ? mDx < 0 : mDy < 0;
+ int lastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
+ int firstVisibleItemPosition = mLayoutManager.findFirstVisibleItemPosition();
+ assertEquals(1, cachedViews().size());
+ int prefetchedPosition = cachedViews().get(0).getAdapterPosition();
+ if (mConfig.mReverseLayout == reverseScroll) {
+ // Pos scroll on pos layout, or reverse scroll on reverse layout = toward last
+ assertEquals(lastVisibleItemPosition + 1, prefetchedPosition);
+ } else {
+ // Pos scroll on reverse layout, or reverse scroll on pos layout = toward first
+ assertEquals(firstVisibleItemPosition - 1, prefetchedPosition);
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
index 2bb0750..185aa4b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
@@ -122,8 +122,8 @@
}
RecyclerView.LayoutManager layoutManager = createFromConfig();
- BaseWrapContentTest.WrappedRecyclerView
- recyclerView = new BaseWrapContentTest.WrappedRecyclerView(getActivity());
+ WrappedRecyclerView
+ recyclerView = new WrappedRecyclerView(getActivity());
recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
recyclerView.setLayoutManager(layoutManager);
recyclerView.setLayoutParams(wrapContent);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
index b232271..7079364 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
@@ -309,7 +309,6 @@
layout();
}
-
@Test
public void dontSaveChildrenState() throws InterruptedException {
MockLayoutManager mlm = new MockLayoutManager() {
@@ -343,6 +342,20 @@
loggingView.getOnSavedInstanceCnt());
}
+ @Test
+ public void prefetchChangesCacheSize() {
+ MockLayoutManager mlm = new MockLayoutManager() {
+ @Override
+ int getItemPrefetchCount() {
+ return 3;
+ }
+ };
+ RecyclerView.Recycler recycler = mRecyclerView.mRecycler;
+ assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax);
+ mRecyclerView.setLayoutManager(mlm);
+ assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax);
+ }
+
static class MockLayoutManager extends RecyclerView.LayoutManager {
int mLayoutCount = 0;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
index ea1573d..768f2f1 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
@@ -25,6 +25,7 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.recyclerview.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -43,6 +44,7 @@
* represent the same item in the adapter. Keeping a focused view visible is up-to-the
* LayoutManager and all FW LayoutManagers already have tests for it.
*/
+@MediumTest
@RunWith(Parameterized.class)
public class RecyclerViewFocusRecoveryTest extends BaseRecyclerViewInstrumentationTest {
TestLayoutManager mLayoutManager;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewPrefetchTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewPrefetchTest.java
new file mode 100644
index 0000000..6b817be
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewPrefetchTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewPrefetchTest extends BaseRecyclerViewInstrumentationTest {
+ private class PrefetchLayoutManager extends TestLayoutManager {
+ CountDownLatch prefetchLatch = new CountDownLatch(1);
+
+ @Override
+ public boolean canScrollVertically() {
+ return true;
+ }
+
+ @Override
+ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+ super.onLayoutChildren(recycler, state);
+ detachAndScrapAttachedViews(recycler);
+ layoutRange(recycler, 0, 5);
+ }
+
+ @Override
+ public void onLayoutCompleted(RecyclerView.State state) {
+ super.onLayoutCompleted(state);
+ layoutLatch.countDown();
+ }
+
+ @Override
+ int getItemPrefetchCount() {
+ return 1;
+ }
+
+ @Override
+ int gatherPrefetchIndices(int dx, int dy, RecyclerView.State state, int[] outIndices) {
+ prefetchLatch.countDown();
+ outIndices[0] = 6;
+ return 1;
+ }
+
+ void waitForPrefetch(int time) throws InterruptedException {
+ assertThat(prefetchLatch.await(time, TimeUnit.SECONDS),
+ is(true));
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ }
+ });
+ }
+ }
+
+ private ArrayList<RecyclerView.ViewHolder> cachedViews() {
+ return mRecyclerView.mRecycler.mCachedViews;
+ }
+
+ @Test
+ public void prefetchTest() throws Throwable {
+ RecyclerView recyclerView = new RecyclerView(getActivity());
+ recyclerView.setAdapter(new TestAdapter(50));
+ PrefetchLayoutManager layout = new PrefetchLayoutManager();
+ recyclerView.setLayoutManager(layout);
+
+ {
+ layout.expectLayouts(1);
+ setRecyclerView(recyclerView);
+ layout.waitForLayout(10);
+ }
+
+ assertThat(layout.prefetchLatch.getCount(), is(1L)); // shouldn't have fired yet
+ assertThat(cachedViews().size(), is(0));
+ smoothScrollBy(50);
+
+ layout.waitForPrefetch(10);
+ assertThat(cachedViews().size(), is(1));
+ assertThat(cachedViews().get(0).getAdapterPosition(), is(6));
+ }
+}
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
index f8d11d8..71484dd 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
@@ -304,9 +304,9 @@
final String boundsLog = mLayoutManager.getBoundsLog();
VisibleChildren queryResult = new VisibleChildren(mLayoutManager.getSpanCount());
queryResult.findFirstPartialVisibleClosestToStart = mLayoutManager
- .findFirstVisibleItemClosestToStart(false, true);
+ .findFirstVisibleItemClosestToStart(false);
queryResult.findFirstPartialVisibleClosestToEnd = mLayoutManager
- .findFirstVisibleItemClosestToEnd(false, true);
+ .findFirstVisibleItemClosestToEnd(false);
queryResult.firstFullyVisiblePositions = mLayoutManager
.findFirstCompletelyVisibleItemPositions(
provideArr ? new int[mLayoutManager.getSpanCount()] : null);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
index d4955d5..51b469d 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
@@ -62,6 +62,46 @@
@MediumTest
@Test
+ public void snapOnScrollSameViewFixedSize() throws Throwable {
+ // This test is a special case for fixed sized children.
+ final Config config = ((Config) mConfig.clone()).itemCount(10);
+ setupByConfig(config);
+ RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(1000, 950);
+ mRecyclerView.setLayoutParams(lp);
+ mAdapter.mOnBindCallback = new OnBindCallback() {
+ @Override
+ void onBoundItem(TestViewHolder vh, int position) {
+ StaggeredGridLayoutManager.LayoutParams slp = getLayoutParamsForPosition(position);
+ vh.itemView.setLayoutParams(slp);
+ }
+
+ @Override
+ boolean assignRandomSize() {
+ return false;
+ }
+ };
+ waitFirstLayout();
+ setupSnapHelper();
+
+ // Record the current center view.
+ View view = findCenterView(mLayoutManager);
+ assertCenterAligned(view);
+ // This number comes from the sizes of the fixed views that are created for this config/
+ // See getLayoutParamsForPosition(int) below. Obtained manually.
+ int scrollDistance = mLayoutManager.canScrollHorizontally() ? 52 : 52;
+ int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
+ mLayoutManager.expectIdleState(2);
+ smoothScrollBy(scrollDist);
+ mLayoutManager.waitForSnap(10);
+
+ // Views have not changed
+ View viewAfterScroll = findCenterView(mLayoutManager);
+ assertSame("The view should NOT have scrolled", view, viewAfterScroll);
+ assertCenterAligned(viewAfterScroll);
+ }
+
+ @MediumTest
+ @Test
public void snapOnScrollSameView() throws Throwable {
final Config config = (Config) mConfig.clone();
setupByConfig(config);
@@ -71,18 +111,18 @@
// Record the current center view.
View view = findCenterView(mLayoutManager);
assertCenterAligned(view);
- // For a staggered grid layout manager we need to keep the distance
+ // For a staggered grid layout manager with unknown item size we need to keep the distance
// small enough to ensure we do not scroll over to an offset view in a different span.
- int scrollDistance = 5;
+ int scrollDistance = findMinSafeScrollDistance();
int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
mLayoutManager.expectIdleState(2);
smoothScrollBy(scrollDist);
mLayoutManager.waitForSnap(10);
// Views have not changed
- View viewAfterFling = findCenterView(mLayoutManager);
- assertSame("The view should have scrolled", view, viewAfterFling);
- assertCenterAligned(viewAfterFling);
+ View viewAfterScroll = findCenterView(mLayoutManager);
+ assertSame("The view should NOT have scrolled", view, viewAfterScroll);
+ assertCenterAligned(viewAfterScroll);
}
@Test
@@ -163,6 +203,21 @@
assertCenterAligned(viewAfterFling);
}
+ private StaggeredGridLayoutManager.LayoutParams getLayoutParamsForPosition(int position) {
+ // Only enabled fixed sizes if the config says so.
+ if (mLayoutManager.canScrollHorizontally()) {
+ int width = 400 + position * 70;
+ return new StaggeredGridLayoutManager.LayoutParams(width, 300);
+ } else {
+ int height = 300 + position * 70;
+ return new StaggeredGridLayoutManager.LayoutParams(300, height);
+ }
+ }
+
+ @Nullable View findCenterView(RecyclerView.LayoutManager layoutManager) {
+ return mLayoutManager.findFirstVisibleItemClosestToCenter();
+ }
+
private void setupSnapHelper() throws Throwable {
SnapHelper snapHelper = new LinearSnapHelper();
mLayoutManager.expectIdleState(1);
@@ -174,7 +229,11 @@
mLayoutManager.waitForLayout(2);
View view = findCenterView(mLayoutManager);
- int scrollDistance = (getViewDimension(view) / 2) + 10;
+ int scrollDistance = distFromCenter(view) / 2;
+ if (scrollDistance == 0) {
+ return;
+ }
+
int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
mLayoutManager.expectIdleState(2);
@@ -182,10 +241,6 @@
mLayoutManager.waitForSnap(10);
}
- @Nullable View findCenterView(RecyclerView.LayoutManager layoutManager) {
- return mLayoutManager.findFirstVisibleItemClosestToCenter();
- }
-
private int getViewDimension(View view) {
OrientationHelper helper;
if (mLayoutManager.canScrollHorizontally()) {
@@ -206,6 +261,28 @@
}
}
+ private int findMinSafeScrollDistance() {
+ int minDist = Integer.MAX_VALUE;
+ for (int i = mLayoutManager.getChildCount() - 1; i >= 0; i--) {
+ final View child = mLayoutManager.getChildAt(i);
+ int dist = distFromCenter(child);
+ if (dist < minDist) {
+ minDist = dist;
+ }
+ }
+ return minDist / 2 - 1;
+ }
+
+ private int distFromCenter(View view) {
+ if (mLayoutManager.canScrollHorizontally()) {
+ return Math.abs(mRecyclerView.getWidth() / 2 -
+ mLayoutManager.getViewBounds(view).centerX());
+ } else {
+ return Math.abs(mRecyclerView.getHeight() / 2 -
+ mLayoutManager.getViewBounds(view).centerY());
+ }
+ }
+
private boolean fling(final int velocityX, final int velocityY)
throws Throwable {
final AtomicBoolean didStart = new AtomicBoolean(false);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
index e6e202c..18cae23 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
@@ -135,17 +135,17 @@
assertEquals("last completely visible item from span 1 should be 1", 1, into[1]);
assertEquals("first fully visible child should be at position",
0, mRecyclerView.getChildViewHolder(mLayoutManager.
- findFirstVisibleItemClosestToStart(true, true)).getPosition());
+ findFirstVisibleItemClosestToStart(true)).getPosition());
assertEquals("last fully visible child should be at position",
4, mRecyclerView.getChildViewHolder(mLayoutManager.
- findFirstVisibleItemClosestToEnd(true, true)).getPosition());
+ findFirstVisibleItemClosestToEnd(true)).getPosition());
assertEquals("first visible child should be at position",
0, mRecyclerView.getChildViewHolder(mLayoutManager.
- findFirstVisibleItemClosestToStart(false, true)).getPosition());
+ findFirstVisibleItemClosestToStart(false)).getPosition());
assertEquals("last visible child should be at position",
4, mRecyclerView.getChildViewHolder(mLayoutManager.
- findFirstVisibleItemClosestToEnd(false, true)).getPosition());
+ findFirstVisibleItemClosestToEnd(false)).getPosition());
}
@@ -323,7 +323,8 @@
stl.addState(new int[]{android.R.attr.state_focused},
new ColorDrawable(Color.RED));
stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- testViewHolder.itemView.setBackground(stl);
+ //noinspection deprecation used to support kitkat tests
+ testViewHolder.itemView.setBackgroundDrawable(stl);
return testViewHolder;
}
@@ -681,9 +682,15 @@
smoothScrollToPosition(mAdapter.getItemCount() / 2);
final int changePosition = mAdapter.getItemCount() / 4;
mLayoutManager.expectLayouts(1);
- mAdapter.changeAndNotify(changePosition, 1);
- mLayoutManager.assertNoLayout("no layout should happen when an invisible child is updated",
- 1);
+ if (RecyclerView.POST_UPDATES_ON_ANIMATION) {
+ mAdapter.changeAndNotify(changePosition, 1);
+ mLayoutManager.assertNoLayout("no layout should happen when an invisible child is "
+ + "updated", 1);
+ } else {
+ mAdapter.changeAndNotify(changePosition, 1);
+ mLayoutManager.waitForLayout(1);
+ }
+
// delete an item before visible area
int deletedPosition = mLayoutManager.getPosition(mLayoutManager.getChildAt(0)) - 2;
assertTrue("test sanity", deletedPosition >= 0);
@@ -800,10 +807,10 @@
.asRecord(event);
final int start = mRecyclerView
.getChildLayoutPosition(
- mLayoutManager.findFirstVisibleItemClosestToStart(false, true));
+ mLayoutManager.findFirstVisibleItemClosestToStart(false));
final int end = mRecyclerView
.getChildLayoutPosition(
- mLayoutManager.findFirstVisibleItemClosestToEnd(false, true));
+ mLayoutManager.findFirstVisibleItemClosestToEnd(false));
assertEquals("first item position should match",
Math.min(start, end), record.getFromIndex());
assertEquals("last item position should match",
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
index 5e07dca..5021ecb 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
@@ -25,6 +25,7 @@
import android.graphics.Rect;
import android.os.Build;
import android.support.test.filters.SdkSuppress;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.Gravity;
import android.view.View;
@@ -35,6 +36,7 @@
import java.util.Arrays;
import java.util.List;
+@MediumTest
@RunWith(Parameterized.class)
public class StaggeredGridLayoutManagerWrapContentTest extends BaseWrapContentTest {
int mOrientation = StaggeredGridLayoutManager.VERTICAL;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java b/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
index 1f0f3ef..b0f90d6 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
@@ -25,8 +25,12 @@
import static org.hamcrest.MatcherAssert.assertThat;
import android.graphics.Rect;
+import android.support.annotation.NonNull;
import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.Toast;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,33 +48,44 @@
@MediumTest
@RunWith(Parameterized.class)
public class TestResizingRelayoutWithAutoMeasure extends BaseRecyclerViewInstrumentationTest {
+ private final int mRvWidth;
+ private final int mRvHeight;
private final RecyclerView.LayoutManager mLayoutManager;
private final float mWidthMultiplier;
private final float mHeightMultiplier;
public TestResizingRelayoutWithAutoMeasure(@SuppressWarnings("UnusedParameters") String name,
+ int rvWidth, int rvHeight,
RecyclerView.LayoutManager layoutManager, float widthMultiplier,
float heightMultiplier) {
+ mRvWidth = rvWidth;
+ mRvHeight = rvHeight;
mLayoutManager = layoutManager;
mWidthMultiplier = widthMultiplier;
mHeightMultiplier = heightMultiplier;
}
- @Parameterized.Parameters(name = "{0} w:{2} h:{3}")
+ @Parameterized.Parameters(name = "{0} rv w/h:{1}/{2} changed w/h:{4}/{5}")
public static List<Object[]> getParams() {
List<Object[]> params = new ArrayList<>();
- for (float w : new float[]{.5f, 1f, 2f}) {
- for (float h : new float[]{.5f, 1f, 2f}) {
- params.add(
- new Object[]{"linear layout", new LinearLayoutManager(null), w, h}
- );
- params.add(
- new Object[]{"grid layout", new GridLayoutManager(null, 3), w, h}
- );
- params.add(
- new Object[]{"staggered", new StaggeredGridLayoutManager(3,
- StaggeredGridLayoutManager.VERTICAL), w, h}
- );
+ for(int[] rvSize : new int[][]{new int[]{200, 200}, new int[]{200, 100},
+ new int[]{100, 200}}) {
+ for (float w : new float[]{.5f, 1f, 2f}) {
+ for (float h : new float[]{.5f, 1f, 2f}) {
+ params.add(
+ new Object[]{"linear layout", rvSize[0], rvSize[1],
+ new LinearLayoutManager(null), w, h}
+ );
+ params.add(
+ new Object[]{"grid layout", rvSize[0], rvSize[1],
+ new GridLayoutManager(null, 3), w, h}
+ );
+ params.add(
+ new Object[]{"staggered", rvSize[0], rvSize[1],
+ new StaggeredGridLayoutManager(3,
+ StaggeredGridLayoutManager.VERTICAL), w, h}
+ );
+ }
}
}
return params;
@@ -78,9 +93,12 @@
@Test
public void testResizeDuringMeasurements() throws Throwable {
- final RecyclerView recyclerView = new RecyclerView(getActivity());
+ final WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
- recyclerView.setAdapter(new TestAdapter(500));
+ StaticAdapter adapter = new StaticAdapter(50, ViewGroup.LayoutParams.MATCH_PARENT,
+ mRvHeight / 5);
+ recyclerView.setLayoutParams(new FrameLayout.LayoutParams(mRvWidth, mRvHeight));
+ recyclerView.setAdapter(adapter);
setRecyclerView(recyclerView);
getInstrumentation().waitForIdleSync();
assertThat("Test sanity", recyclerView.getChildCount() > 0, is(true));
@@ -88,38 +106,57 @@
smoothScrollToPosition(lastPosition);
assertThat("test sanity", recyclerView.findViewHolderForAdapterPosition(lastPosition),
notNullValue());
+ assertThat("test sanity", mRvWidth, is(recyclerView.getWidth()));
+ assertThat("test sanity", mRvHeight, is(recyclerView.getHeight()));
+ recyclerView.waitUntilLayout();
+ recyclerView.waitUntilAnimations();
+ final Map<Integer, Rect> startPositions = capturePositions(recyclerView);
runTestOnUiThread(new Runnable() {
@Override
public void run() {
- int startHeight = recyclerView.getMeasuredHeight();
- int startWidth = recyclerView.getMeasuredWidth();
- Map<Integer, Rect> startPositions = capturePositions(recyclerView);
recyclerView.measure(
- makeMeasureSpec((int) (startWidth * mWidthMultiplier),
+ makeMeasureSpec((int) (mRvWidth * mWidthMultiplier),
mWidthMultiplier == 1f ? EXACTLY : AT_MOST),
- makeMeasureSpec((int) (startHeight * mHeightMultiplier),
+ makeMeasureSpec((int) (mRvHeight * mHeightMultiplier),
mHeightMultiplier == 1f ? EXACTLY : AT_MOST));
recyclerView.measure(
- makeMeasureSpec(startWidth, EXACTLY),
- makeMeasureSpec(startHeight, EXACTLY));
+ makeMeasureSpec(mRvWidth, EXACTLY),
+ makeMeasureSpec(mRvHeight, EXACTLY));
recyclerView.dispatchLayout();
Map<Integer, Rect> endPositions = capturePositions(recyclerView);
assertStartItemPositions(startPositions, endPositions);
}
});
+ recyclerView.waitUntilLayout();
+ recyclerView.waitUntilAnimations();
+ checkForMainThreadException();
}
private void assertStartItemPositions(Map<Integer, Rect> startPositions,
Map<Integer, Rect> endPositions) {
+ String log = log(startPositions, endPositions);
for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
Rect rect = endPositions.get(entry.getKey());
- assertThat("view for position " + entry.getKey() + " at" + entry.getValue(), rect,
+ assertThat(log + "view for position " + entry.getKey() + " at" + entry.getValue(), rect,
notNullValue());
- assertThat("rect for position " + entry.getKey(), entry.getValue(), is(rect));
+ assertThat(log + "rect for position " + entry.getKey(), entry.getValue(), is(rect));
}
}
+ @NonNull
+ private String log(Map<Integer, Rect> startPositions, Map<Integer, Rect> endPositions) {
+ StringBuilder logBuilder = new StringBuilder();
+ for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
+ logBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
+ }
+ logBuilder.append("------\n");
+ for (Map.Entry<Integer, Rect> entry : endPositions.entrySet()) {
+ logBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
+ }
+ return logBuilder.toString();
+ }
+
private Map<Integer, Rect> capturePositions(RecyclerView recyclerView) {
Map<Integer, Rect> positions = new HashMap<>();
for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
@@ -138,4 +175,52 @@
}
return positions;
}
+
+ private class StaticAdapter extends RecyclerView.Adapter<TestViewHolder> {
+ final int mSize;
+ // is passed to the layout params of the item
+ final int mMinItemWidth;
+ final int mMinItemHeight;
+
+ public StaticAdapter(int size, int minItemWidth, int minItemHeight) {
+ mSize = size;
+ mMinItemWidth = minItemWidth;
+ mMinItemHeight = minItemHeight;
+ }
+
+ @Override
+ public TestViewHolder onCreateViewHolder(ViewGroup parent,
+ int viewType) {
+ return new TestViewHolder(new View(parent.getContext()));
+ }
+
+ @Override
+ public void onBindViewHolder(TestViewHolder holder, int position) {
+ holder.mBoundItem = new Item(position, "none");
+ if (mMinItemHeight < 1 && mMinItemWidth < 1) {
+ return;
+ }
+ ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+ if (lp == null) {
+ lp = new ViewGroup.LayoutParams(0, 0);
+ }
+ if (mMinItemWidth > 0) {
+ lp.width = (int) (mMinItemWidth + (position % 10) * mMinItemWidth / 7f);
+ } else {
+ lp.width = mMinItemWidth;
+ }
+
+ if (mMinItemHeight > 0) {
+ lp.height = (int) (mMinItemHeight + (position % 10) * mMinItemHeight / 7f);
+ } else {
+ lp.height = mMinItemHeight;
+ }
+ holder.itemView.setLayoutParams(lp);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mSize;
+ }
+ }
}
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
index b485fa6..b0e6613 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
@@ -26,6 +26,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
@@ -40,6 +41,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+@MediumTest
@RunWith(AndroidJUnit4.class)
public class WrapContentBasicTest extends AndroidTestCase {
@@ -200,6 +202,63 @@
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
+
+ // START MOCKITO OVERRIDES
+ // We override package protected methods to make them public. This is necessary to run
+ // mockito on Kitkat
+ @Override
+ public void setRecyclerView(RecyclerView recyclerView) {
+ super.setRecyclerView(recyclerView);
+ }
+
+ @Override
+ public void dispatchAttachedToWindow(RecyclerView view) {
+ super.dispatchAttachedToWindow(view);
+ }
+
+ @Override
+ public void dispatchDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+ super.dispatchDetachedFromWindow(view, recycler);
+ }
+
+ @Override
+ public void setExactMeasureSpecsFrom(RecyclerView recyclerView) {
+ super.setExactMeasureSpecsFrom(recyclerView);
+ }
+
+ @Override
+ public void setMeasureSpecs(int wSpec, int hSpec) {
+ super.setMeasureSpecs(wSpec, hSpec);
+ }
+
+ @Override
+ public void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) {
+ super.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
+ }
+
+ @Override
+ public boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec,
+ RecyclerView.LayoutParams lp) {
+ return super.shouldReMeasureChild(child, widthSpec, heightSpec, lp);
+ }
+
+ @Override
+ public boolean shouldMeasureChild(View child, int widthSpec, int heightSpec,
+ RecyclerView.LayoutParams lp) {
+ return super.shouldMeasureChild(child, widthSpec, heightSpec, lp);
+ }
+
+ @Override
+ public void removeAndRecycleScrapInt(RecyclerView.Recycler recycler) {
+ super.removeAndRecycleScrapInt(recycler);
+ }
+
+ @Override
+ public void stopSmoothScroller() {
+ super.stopSmoothScroller();
+ }
+
+ // END MOCKITO OVERRIDES
}
public class WrapAdapter extends RecyclerView.Adapter {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java b/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
index 1da3ba5..58a0841 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
@@ -16,10 +16,18 @@
package android.support.v7.widget;
+import android.app.Instrumentation;
import android.content.Context;
+import android.support.test.InstrumentationRegistry;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* RecyclerView wrapper used in tests. This class can fake behavior like layout direction w/o
* playing with framework support.
@@ -27,11 +35,21 @@
public class WrappedRecyclerView extends RecyclerView {
Boolean mFakeRTL;
+ private long mDrawingTimeOffsetMs;
public void setFakeRTL(Boolean fakeRTL) {
mFakeRTL = fakeRTL;
}
+ public void setDrawingTimeOffset(long offsetMs) {
+ mDrawingTimeOffsetMs = offsetMs;
+ }
+
+ @Override
+ public long getDrawingTime() {
+ return super.getDrawingTime() + mDrawingTimeOffsetMs;
+ }
+
public WrappedRecyclerView(Context context) {
super(context);
init(context);
@@ -51,6 +69,34 @@
//initializeScrollbars(null);
}
+ public void waitUntilLayout() {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ while (isLayoutRequested()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void waitUntilAnimations() throws InterruptedException {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ final CountDownLatch latch = new CountDownLatch(1);
+ if (mItemAnimator == null || !mItemAnimator.isRunning(
+ new ItemAnimator.ItemAnimatorFinishedListener() {
+ @Override
+ public void onAnimationsFinished() {
+ latch.countDown();
+ }
+ })) {
+ latch.countDown();
+ }
+ MatcherAssert.assertThat("waiting too long for animations",
+ latch.await(60, TimeUnit.SECONDS), CoreMatchers.is(true));
+ }
+
+
@Override
public int getLayoutDirection() {
if (mFakeRTL == null) {