Avoid absolute path loading .so after M am: 405f6d6e7c am: 5ab545784d
am: 4c2f5b63e9
* commit '4c2f5b63e935777645bb819b5e261ad5dda1796d':
Avoid absolute path loading .so after M
diff --git a/.gitignore b/.gitignore
index c8c3ed8..a72b3dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,5 @@
project.properties
**/bin
**/gen
+*.iml
+**/out
diff --git a/Android.mk b/Android.mk
index 4abc112..8fd0693b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,8 +23,15 @@
.PHONY: update-support-api
.PHONY: check-support-api
+.PHONY: support-gradle-archive
+support-gradle-archive: PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
+support-gradle-archive:
+ $(PRIVATE_LOCAL_PATH)/gradlew -p $(PRIVATE_LOCAL_PATH) createArchive
+
# Run the check-support-api task on a SDK build
sdk: check-support-api
+# Run the support-gradle-archive task on a SDK build
+sdk: support-gradle-archive
# Build all support libraries
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/apicheck.mk b/apicheck.mk
index 1638607..739cfb3 100644
--- a/apicheck.mk
+++ b/apicheck.mk
@@ -20,6 +20,7 @@
# $(support_module_java_libraries) - dependent libraries
# $(support_module_java_packages) - list of package names containing public classes
# $(support_module_src_files) - list of source files
+# $(support_module_aidl_includes) - list of aidl files
# $(api_check_current_msg_file) - file containing error message for current API check
# $(api_check_last_msg_file) - file containing error message for last SDK API check
# ---------------------------------------------
@@ -39,6 +40,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(support_module_src_files)
+LOCAL_AIDL_INCLUDES := $(support_module_aidl_includes)
LOCAL_JAVA_LIBRARIES := $(support_module_java_libraries)
LOCAL_ADDITIONAL_JAVA_DIR := \
$(call intermediates-dir-for,$(LOCAL_MODULE_CLASS),$(support_module),,COMMON)/src
@@ -117,6 +119,7 @@
support_module :=
support_module_api_dir :=
support_module_src_files :=
+support_module_aidl_includes :=
support_module_java_libraries :=
support_module_java_packages :=
support_module_api_file :=
diff --git a/build.gradle b/build.gradle
index 6a90344..3b23406 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,8 +9,8 @@
}
}
-ext.supportVersion = '23.0.1'
-ext.extraVersion = 19
+ext.supportVersion = '23.2.0-SNAPSHOT'
+ext.extraVersion = 25
ext.supportRepoOut = ''
ext.buildToolsVersion = '22.1.0'
ext.buildNumber = Integer.toString(ext.extraVersion)
@@ -34,6 +34,7 @@
}
ext.supportRepoOut = new File(buildDir, 'support_repo')
+ext.testApkDistOut = new File(buildDir, 'test_apks')
// Main task called by the build server.
task(createArchive) << {
@@ -170,6 +171,17 @@
}
}
+project.gradle.buildFinished { buildResult ->
+ if (buildResult.getFailure() != null) {
+ println()
+ println 'Build failed. Possible causes include:'
+ println ' 1) Bad codes'
+ println ' 2) Out of date prebuilts in prebuilts/sdk'
+ println ' 3) Need to update the compileSdkVersion in a library\'s build.gradle'
+ println()
+ }
+}
+
FileCollection getAndroidPrebuilt(String apiLevel) {
files("$rootDir/../../prebuilts/sdk/$apiLevel/android.jar")
}
diff --git a/customtabs/api/23.txt b/customtabs/api/23.0.0.txt
similarity index 100%
rename from customtabs/api/23.txt
rename to customtabs/api/23.0.0.txt
diff --git a/customtabs/api/23.1.0.txt b/customtabs/api/23.1.0.txt
new file mode 100644
index 0000000..caa5ea4b
--- /dev/null
+++ b/customtabs/api/23.1.0.txt
@@ -0,0 +1,88 @@
+package android.support.customtabs {
+
+ public class CustomTabsCallback {
+ ctor public CustomTabsCallback();
+ method public void extraCallback(java.lang.String, android.os.Bundle);
+ method public void onNavigationEvent(int, android.os.Bundle);
+ field public static final int NAVIGATION_ABORTED = 4; // 0x4
+ field public static final int NAVIGATION_FAILED = 3; // 0x3
+ field public static final int NAVIGATION_FINISHED = 2; // 0x2
+ field public static final int NAVIGATION_STARTED = 1; // 0x1
+ field public static final int TAB_HIDDEN = 6; // 0x6
+ field public static final int TAB_SHOWN = 5; // 0x5
+ }
+
+ public class CustomTabsClient {
+ method public static boolean bindCustomTabsService(android.content.Context, java.lang.String, android.support.customtabs.CustomTabsServiceConnection);
+ method public android.os.Bundle extraCommand(java.lang.String, android.os.Bundle);
+ method public android.support.customtabs.CustomTabsSession newSession(android.support.customtabs.CustomTabsCallback);
+ method public boolean warmup(long);
+ }
+
+ public final class CustomTabsIntent {
+ method public void launchUrl(android.app.Activity, android.net.Uri);
+ field public static final java.lang.String EXTRA_ACTION_BUTTON_BUNDLE = "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE";
+ field public static final java.lang.String EXTRA_CLOSE_BUTTON_ICON = "android.support.customtabs.extra.CLOSE_BUTTON_ICON";
+ field public static final java.lang.String EXTRA_ENABLE_URLBAR_HIDING = "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
+ field public static final java.lang.String EXTRA_EXIT_ANIMATION_BUNDLE = "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE";
+ field public static final java.lang.String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS";
+ field public static final java.lang.String EXTRA_SESSION = "android.support.customtabs.extra.SESSION";
+ field public static final java.lang.String EXTRA_TINT_ACTION_BUTTON = "android.support.customtabs.extra.TINT_ACTION_BUTTON";
+ field public static final java.lang.String EXTRA_TITLE_VISIBILITY_STATE = "android.support.customtabs.extra.TITLE_VISIBILITY";
+ field public static final java.lang.String EXTRA_TOOLBAR_COLOR = "android.support.customtabs.extra.TOOLBAR_COLOR";
+ field public static final java.lang.String KEY_DESCRIPTION = "android.support.customtabs.customaction.DESCRIPTION";
+ field public static final java.lang.String KEY_ICON = "android.support.customtabs.customaction.ICON";
+ field public static final java.lang.String KEY_MENU_ITEM_TITLE = "android.support.customtabs.customaction.MENU_ITEM_TITLE";
+ field public static final java.lang.String KEY_PENDING_INTENT = "android.support.customtabs.customaction.PENDING_INTENT";
+ field public static final int NO_TITLE = 0; // 0x0
+ field public static final int SHOW_PAGE_TITLE = 1; // 0x1
+ field public final android.content.Intent intent;
+ field public final android.os.Bundle startAnimationBundle;
+ }
+
+ public static final class CustomTabsIntent.Builder {
+ ctor public CustomTabsIntent.Builder();
+ ctor public CustomTabsIntent.Builder(android.support.customtabs.CustomTabsSession);
+ method public android.support.customtabs.CustomTabsIntent.Builder addMenuItem(java.lang.String, android.app.PendingIntent);
+ method public android.support.customtabs.CustomTabsIntent build();
+ method public android.support.customtabs.CustomTabsIntent.Builder enableUrlBarHiding();
+ method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent, boolean);
+ method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent);
+ method public android.support.customtabs.CustomTabsIntent.Builder setCloseButtonIcon(android.graphics.Bitmap);
+ method public android.support.customtabs.CustomTabsIntent.Builder setExitAnimations(android.content.Context, int, int);
+ method public android.support.customtabs.CustomTabsIntent.Builder setShowTitle(boolean);
+ method public android.support.customtabs.CustomTabsIntent.Builder setStartAnimations(android.content.Context, int, int);
+ method public android.support.customtabs.CustomTabsIntent.Builder setToolbarColor(int);
+ }
+
+ public abstract class CustomTabsService extends android.app.Service {
+ ctor public CustomTabsService();
+ method protected boolean cleanUpSession(android.support.customtabs.CustomTabsSessionToken);
+ method protected abstract android.os.Bundle extraCommand(java.lang.String, android.os.Bundle);
+ method protected abstract boolean mayLaunchUrl(android.support.customtabs.CustomTabsSessionToken, android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+ method protected abstract boolean newSession(android.support.customtabs.CustomTabsSessionToken);
+ method public android.os.IBinder onBind(android.content.Intent);
+ method protected abstract boolean updateVisuals(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle);
+ method protected abstract boolean warmup(long);
+ field public static final java.lang.String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
+ field public static final java.lang.String KEY_URL = "android.support.customtabs.otherurls.URL";
+ }
+
+ public abstract class CustomTabsServiceConnection implements android.content.ServiceConnection {
+ ctor public CustomTabsServiceConnection();
+ method public abstract void onCustomTabsServiceConnected(android.content.ComponentName, android.support.customtabs.CustomTabsClient);
+ method public final void onServiceConnected(android.content.ComponentName, android.os.IBinder);
+ }
+
+ public final class CustomTabsSession {
+ method public boolean mayLaunchUrl(android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+ method public boolean setActionButton(android.graphics.Bitmap, java.lang.String);
+ }
+
+ public class CustomTabsSessionToken {
+ method public android.support.customtabs.CustomTabsCallback getCallback();
+ method public static android.support.customtabs.CustomTabsSessionToken getSessionTokenFromIntent(android.content.Intent);
+ }
+
+}
+
diff --git a/customtabs/api/current.txt b/customtabs/api/current.txt
index b66c71e..caa5ea4b 100644
--- a/customtabs/api/current.txt
+++ b/customtabs/api/current.txt
@@ -8,6 +8,8 @@
field public static final int NAVIGATION_FAILED = 3; // 0x3
field public static final int NAVIGATION_FINISHED = 2; // 0x2
field public static final int NAVIGATION_STARTED = 1; // 0x1
+ field public static final int TAB_HIDDEN = 6; // 0x6
+ field public static final int TAB_SHOWN = 5; // 0x5
}
public class CustomTabsClient {
@@ -21,9 +23,11 @@
method public void launchUrl(android.app.Activity, android.net.Uri);
field public static final java.lang.String EXTRA_ACTION_BUTTON_BUNDLE = "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE";
field public static final java.lang.String EXTRA_CLOSE_BUTTON_ICON = "android.support.customtabs.extra.CLOSE_BUTTON_ICON";
+ field public static final java.lang.String EXTRA_ENABLE_URLBAR_HIDING = "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
field public static final java.lang.String EXTRA_EXIT_ANIMATION_BUNDLE = "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE";
field public static final java.lang.String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS";
field public static final java.lang.String EXTRA_SESSION = "android.support.customtabs.extra.SESSION";
+ field public static final java.lang.String EXTRA_TINT_ACTION_BUTTON = "android.support.customtabs.extra.TINT_ACTION_BUTTON";
field public static final java.lang.String EXTRA_TITLE_VISIBILITY_STATE = "android.support.customtabs.extra.TITLE_VISIBILITY";
field public static final java.lang.String EXTRA_TOOLBAR_COLOR = "android.support.customtabs.extra.TOOLBAR_COLOR";
field public static final java.lang.String KEY_DESCRIPTION = "android.support.customtabs.customaction.DESCRIPTION";
@@ -41,6 +45,8 @@
ctor public CustomTabsIntent.Builder(android.support.customtabs.CustomTabsSession);
method public android.support.customtabs.CustomTabsIntent.Builder addMenuItem(java.lang.String, android.app.PendingIntent);
method public android.support.customtabs.CustomTabsIntent build();
+ method public android.support.customtabs.CustomTabsIntent.Builder enableUrlBarHiding();
+ method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent, boolean);
method public android.support.customtabs.CustomTabsIntent.Builder setActionButton(android.graphics.Bitmap, java.lang.String, android.app.PendingIntent);
method public android.support.customtabs.CustomTabsIntent.Builder setCloseButtonIcon(android.graphics.Bitmap);
method public android.support.customtabs.CustomTabsIntent.Builder setExitAnimations(android.content.Context, int, int);
@@ -56,6 +62,7 @@
method protected abstract boolean mayLaunchUrl(android.support.customtabs.CustomTabsSessionToken, android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
method protected abstract boolean newSession(android.support.customtabs.CustomTabsSessionToken);
method public android.os.IBinder onBind(android.content.Intent);
+ method protected abstract boolean updateVisuals(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle);
method protected abstract boolean warmup(long);
field public static final java.lang.String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
field public static final java.lang.String KEY_URL = "android.support.customtabs.otherurls.URL";
@@ -69,6 +76,7 @@
public final class CustomTabsSession {
method public boolean mayLaunchUrl(android.net.Uri, android.os.Bundle, java.util.List<android.os.Bundle>);
+ method public boolean setActionButton(android.graphics.Bitmap, java.lang.String);
}
public class CustomTabsSessionToken {
diff --git a/customtabs/src/android/support/customtabs/CustomTabsCallback.java b/customtabs/src/android/support/customtabs/CustomTabsCallback.java
index ea5f3e3..d7fdd39 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsCallback.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsCallback.java
@@ -44,6 +44,16 @@
public static final int NAVIGATION_ABORTED = 4;
/**
+ * Sent when the tab becomes visible.
+ */
+ public static final int TAB_SHOWN = 5;
+
+ /**
+ * Sent when the tab becomes hidden.
+ */
+ public static final int TAB_HIDDEN = 6;
+
+ /**
* To be called when a navigation event happens.
*
* @param navigationEvent The code corresponding to the navigation event.
diff --git a/customtabs/src/android/support/customtabs/CustomTabsIntent.java b/customtabs/src/android/support/customtabs/CustomTabsIntent.java
index 2276f94..ab3685f 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsIntent.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsIntent.java
@@ -57,6 +57,12 @@
"android.support.customtabs.extra.TOOLBAR_COLOR";
/**
+ * Boolean extra that enables the url bar to hide as the user scrolls down the page
+ */
+ public static final String EXTRA_ENABLE_URLBAR_HIDING =
+ "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
+
+ /**
* Extra bitmap that specifies the icon of the back button on the toolbar. If the client chooses
* not to customize it, a default close button will be used.
*/
@@ -109,6 +115,13 @@
"android.support.customtabs.customaction.PENDING_INTENT";
/**
+ * Extra boolean that specifies whether the custom action button should be tinted. Default is
+ * false and the action button will not be tinted.
+ */
+ public static final String EXTRA_TINT_ACTION_BUTTON =
+ "android.support.customtabs.extra.TINT_ACTION_BUTTON";
+
+ /**
* Use an {@code ArrayList<Bundle>} for specifying menu related params. There should be a
* separate {@link Bundle} for each custom menu item.
*/
@@ -202,6 +215,14 @@
}
/**
+ * Enables the url bar to hide as the user scrolls down on the page.
+ */
+ public Builder enableUrlBarHiding() {
+ mIntent.putExtra(EXTRA_ENABLE_URLBAR_HIDING, true);
+ return this;
+ }
+
+ /**
* Sets the Close button icon for the custom tab.
*
* @param icon The icon {@link Bitmap}
@@ -243,18 +264,29 @@
* @param icon The icon.
* @param description The description for the button. To be used for accessibility.
* @param pendingIntent pending intent delivered when the button is clicked.
+ * @param shouldTint Whether the action button should be tinted.
*/
- public Builder setActionButton(@NonNull Bitmap icon,
- @NonNull String description, @NonNull PendingIntent pendingIntent) {
+ public Builder setActionButton(@NonNull Bitmap icon, @NonNull String description,
+ @NonNull PendingIntent pendingIntent, boolean shouldTint) {
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_ICON, icon);
bundle.putString(KEY_DESCRIPTION, description);
bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent);
mIntent.putExtra(EXTRA_ACTION_BUTTON_BUNDLE, bundle);
+ mIntent.putExtra(EXTRA_TINT_ACTION_BUTTON, shouldTint);
return this;
}
/**
+ * See {@link CustomTabsIntent.Builder#setActionButton(
+ * Bitmap, String, PendingIntent, boolean)}
+ */
+ public Builder setActionButton(@NonNull Bitmap icon, @NonNull String description,
+ @NonNull PendingIntent pendingIntent) {
+ return setActionButton(icon, description, pendingIntent, false);
+ }
+
+ /**
* Sets the start animations,
*
* @param context Application context.
diff --git a/customtabs/src/android/support/customtabs/CustomTabsService.java b/customtabs/src/android/support/customtabs/CustomTabsService.java
index 37f1a60..25697c5 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsService.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsService.java
@@ -50,7 +50,7 @@
public static final String KEY_URL =
"android.support.customtabs.otherurls.URL";
- private Map<IBinder, DeathRecipient> mDeathRecipientMap = new ArrayMap<>();
+ private final Map<IBinder, DeathRecipient> mDeathRecipientMap = new ArrayMap<>();
private ICustomTabsService.Stub mBinder = new ICustomTabsService.Stub() {
@@ -90,6 +90,12 @@
public Bundle extraCommand(String commandName, Bundle args) {
return CustomTabsService.this.extraCommand(commandName, args);
}
+
+ @Override
+ public boolean updateVisuals(ICustomTabsCallback callback, Bundle bundle) {
+ return CustomTabsService.this.updateVisuals(
+ new CustomTabsSessionToken(callback), bundle);
+ }
};
@Override
@@ -176,4 +182,15 @@
* @return The result {@link Bundle}, or null.
*/
protected abstract Bundle extraCommand(String commandName, Bundle args);
+
+ /**
+ * Updates the visuals of custom tabs for the given session. Will only succeed if the given
+ * session matches the currently active one.
+ * @param sessionToken The currently active session that the custom tab belongs to.
+ * @param bundle The action button configuration bundle. This bundle should be constructed
+ * with the same structure in {@link CustomTabsIntent.Builder}.
+ * @return Whether the operation was successful.
+ */
+ protected abstract boolean updateVisuals(CustomTabsSessionToken sessionToken,
+ Bundle bundle);
}
diff --git a/customtabs/src/android/support/customtabs/CustomTabsSession.java b/customtabs/src/android/support/customtabs/CustomTabsSession.java
index ee45b7c..a51cf0e 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsSession.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsSession.java
@@ -17,10 +17,12 @@
package android.support.customtabs;
import android.content.ComponentName;
+import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.support.annotation.NonNull;
import java.util.List;
@@ -65,6 +67,27 @@
}
}
+ /**
+ * Update the visuals for the button on a custom tab. Will only succeed if the given
+ * session is the active one in browser.
+ * @param icon The new icon of the action button.
+ * @param description Content description of the action button.
+ * @return Whether the update succeeded.
+ */
+ public boolean setActionButton(@NonNull Bitmap icon, @NonNull String description) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(CustomTabsIntent.KEY_ICON, icon);
+ bundle.putString(CustomTabsIntent.KEY_DESCRIPTION, description);
+
+ Bundle metaBundle = new Bundle();
+ metaBundle.putBundle(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE, bundle);
+ try {
+ return mService.updateVisuals(mCallback, metaBundle);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
/* package */ IBinder getBinder() {
return mCallback.asBinder();
}
@@ -72,4 +95,4 @@
/* package */ ComponentName getComponentName() {
return mComponentName;
}
-}
\ No newline at end of file
+}
diff --git a/customtabs/src/android/support/customtabs/ICustomTabsService.aidl b/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
index 2565928..e53ca84 100644
--- a/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
+++ b/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
@@ -32,4 +32,5 @@
boolean mayLaunchUrl(in ICustomTabsCallback callback, in Uri url,
in Bundle extras, in List<Bundle> otherLikelyBundles) = 3;
Bundle extraCommand(String commandName, in Bundle args) = 4;
+ boolean updateVisuals(in ICustomTabsCallback callback, in Bundle bundle) = 5;
}
diff --git a/design/Android.mk b/design/Android.mk
index 0b0b2a8..6f4ac3b 100644
--- a/design/Android.mk
+++ b/design/Android.mk
@@ -23,13 +23,17 @@
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, dummy)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
- frameworks/support/v7/appcompat/res
+ frameworks/support/v7/appcompat/res \
+ frameworks/support/v7/recyclerview/res
LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
- --extra-packages android.support.v7.appcompat
+ --extra-packages android.support.v7.appcompat \
+ --extra-packages android.support.v7.recyclerview
LOCAL_JAR_EXCLUDE_FILES := none
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files := $(LOCAL_SRC_FILES)
+
# A helper sub-library to resolve cyclic dependencies between src and the platform dependent
# implementations
include $(CLEAR_VARS)
@@ -38,9 +42,12 @@
LOCAL_SRC_FILES := $(call all-java-files-under, base)
LOCAL_JAVA_LIBRARIES := android-support-design-res \
android-support-v4 \
- android-support-v7-appcompat
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of Eclair MR1 APIs
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-design-eclair-mr1
@@ -49,9 +56,12 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-base
LOCAL_JAVA_LIBRARIES := android-support-design-res \
android-support-v4 \
- android-support-v7-appcompat
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of Honeycomb APIs
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-design-honeycomb
@@ -60,9 +70,12 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-eclair-mr1
LOCAL_JAVA_LIBRARIES := android-support-design-res \
android-support-v4 \
- android-support-v7-appcompat
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of Honeycomb MR1 APIs
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-design-honeycomb-mr1
@@ -71,20 +84,40 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-honeycomb
LOCAL_JAVA_LIBRARIES := android-support-design-res \
android-support-v4 \
- android-support-v7-appcompat
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
+# A helper sub-library that makes direct use of ICS APIs
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-design-ics
+LOCAL_SDK_VERSION := 14
+LOCAL_SRC_FILES := $(call all-java-files-under, ics)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-honeycomb-mr1
+LOCAL_JAVA_LIBRARIES := android-support-design-res \
+ android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of Lollipop APIs
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-design-lollipop
LOCAL_SDK_VERSION := 21
LOCAL_SRC_FILES := $(call all-java-files-under, lollipop)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-honeycomb-mr1
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-ics
LOCAL_JAVA_LIBRARIES := android-support-design-res \
android-support-v4 \
- android-support-v7-appcompat
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# Here is the final static library that apps can link against.
# The R class is automatically excluded from the generated library.
# Applications that use this library must specify LOCAL_RESOURCE_DIR
@@ -96,14 +129,16 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-lollipop
LOCAL_JAVA_LIBRARIES := android-support-design-res \
android-support-v4 \
- android-support-v7-appcompat
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# API Check
# ---------------------------------------------
support_module := $(LOCAL_MODULE)
support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(LOCAL_SRC_FILES)
support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
support_module_java_packages := android.support.design.*
include $(SUPPORT_API_CHECK)
diff --git a/design/api/23.txt b/design/api/23.0.0.txt
similarity index 100%
rename from design/api/23.txt
rename to design/api/23.0.0.txt
diff --git a/design/api/23.1.0.txt b/design/api/23.1.0.txt
new file mode 100644
index 0000000..f68ab1b
--- /dev/null
+++ b/design/api/23.1.0.txt
@@ -0,0 +1,420 @@
+package android.support.design.widget {
+
+ public class AppBarLayout extends android.widget.LinearLayout {
+ ctor public AppBarLayout(android.content.Context);
+ ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
+ method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
+ method public float getTargetElevation();
+ method public final int getTotalScrollRange();
+ method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
+ method public void setExpanded(boolean);
+ method public void setExpanded(boolean, boolean);
+ method public void setTargetElevation(float);
+ }
+
+ public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
+ ctor public AppBarLayout.Behavior();
+ ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
+ method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
+ method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, float, float, boolean);
+ method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int, int);
+ method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.os.Parcelable);
+ method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
+ method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int);
+ method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View);
+ method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
+ }
+
+ public static abstract class AppBarLayout.Behavior.DragCallback {
+ ctor public AppBarLayout.Behavior.DragCallback();
+ method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
+ }
+
+ protected static class AppBarLayout.Behavior.SavedState extends android.view.View.BaseSavedState {
+ ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
+ ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
+ }
+
+ public static class AppBarLayout.LayoutParams extends android.widget.LinearLayout.LayoutParams {
+ ctor public AppBarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public AppBarLayout.LayoutParams(int, int);
+ ctor public AppBarLayout.LayoutParams(int, int, float);
+ ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public AppBarLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
+ ctor public AppBarLayout.LayoutParams(android.support.design.widget.AppBarLayout.LayoutParams);
+ method public int getScrollFlags();
+ method public android.view.animation.Interpolator getScrollInterpolator();
+ method public void setScrollFlags(int);
+ method public void setScrollInterpolator(android.view.animation.Interpolator);
+ field public static final int SCROLL_FLAG_ENTER_ALWAYS = 4; // 0x4
+ field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
+ field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
+ field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
+ field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
+ }
+
+ public static abstract interface AppBarLayout.OnOffsetChangedListener {
+ method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
+ }
+
+ public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
+ ctor public AppBarLayout.ScrollingViewBehavior();
+ ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+ method public int getOverlayTop();
+ method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
+ method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
+ method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
+ method public void setOverlayTop(int);
+ }
+
+ public class CollapsingToolbarLayout extends android.widget.FrameLayout {
+ ctor public CollapsingToolbarLayout(android.content.Context);
+ ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
+ ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
+ method public int getCollapsedTitleGravity();
+ method public android.graphics.Typeface getCollapsedTitleTypeface();
+ method public android.graphics.drawable.Drawable getContentScrim();
+ method public int getExpandedTitleGravity();
+ method public android.graphics.Typeface getExpandedTitleTypeface();
+ method public android.graphics.drawable.Drawable getStatusBarScrim();
+ method public java.lang.CharSequence getTitle();
+ method public boolean isTitleEnabled();
+ method public void setCollapsedTitleGravity(int);
+ method public void setCollapsedTitleTextAppearance(int);
+ method public void setCollapsedTitleTextColor(int);
+ method public void setCollapsedTitleTypeface(android.graphics.Typeface);
+ method public void setContentScrim(android.graphics.drawable.Drawable);
+ method public void setContentScrimColor(int);
+ method public void setContentScrimResource(int);
+ method public void setExpandedTitleColor(int);
+ method public void setExpandedTitleGravity(int);
+ method public void setExpandedTitleTextAppearance(int);
+ method public void setExpandedTitleTypeface(android.graphics.Typeface);
+ method public void setScrimsShown(boolean);
+ method public void setScrimsShown(boolean, boolean);
+ method public void setStatusBarScrim(android.graphics.drawable.Drawable);
+ method public void setStatusBarScrimColor(int);
+ method public void setStatusBarScrimResource(int);
+ method public void setTitle(java.lang.CharSequence);
+ method public void setTitleEnabled(boolean);
+ }
+
+ public static class CollapsingToolbarLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public CollapsingToolbarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public CollapsingToolbarLayout.LayoutParams(int, int);
+ ctor public CollapsingToolbarLayout.LayoutParams(int, int, int);
+ ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public CollapsingToolbarLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ method public int getCollapseMode();
+ method public float getParallaxMultiplier();
+ method public void setCollapseMode(int);
+ method public void setParallaxMultiplier(float);
+ field public static final int COLLAPSE_MODE_OFF = 0; // 0x0
+ field public static final int COLLAPSE_MODE_PARALLAX = 2; // 0x2
+ field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
+ }
+
+ public class CoordinatorLayout extends android.view.ViewGroup {
+ ctor public CoordinatorLayout(android.content.Context);
+ ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
+ ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
+ method public void dispatchDependentViewsChanged(android.view.View);
+ method public boolean doViewsOverlap(android.view.View, android.view.View);
+ method public java.util.List<android.view.View> getDependencies(android.view.View);
+ method public android.graphics.drawable.Drawable getStatusBarBackground();
+ method public boolean isPointInChildBounds(android.view.View, int, int);
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void onDraw(android.graphics.Canvas);
+ method protected void onLayout(boolean, int, int, int, int);
+ method public void onLayoutChild(android.view.View, int);
+ method public void onMeasureChild(android.view.View, int, int, int, int);
+ method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+ method public void setStatusBarBackgroundColor(int);
+ method public void setStatusBarBackgroundResource(int);
+ }
+
+ public static abstract class CoordinatorLayout.Behavior {
+ ctor public CoordinatorLayout.Behavior();
+ ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
+ method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
+ method public final int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
+ method public final float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
+ method public static java.lang.Object getTag(android.view.View);
+ method public boolean isDirty(android.support.design.widget.CoordinatorLayout, V);
+ method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+ method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
+ method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+ method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+ method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+ method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+ method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
+ method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
+ method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
+ method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
+ method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+ method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
+ method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
+ method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+ method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+ method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+ method public static void setTag(android.view.View, java.lang.Object);
+ }
+
+ public static abstract class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
+ }
+
+ public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public CoordinatorLayout.LayoutParams(int, int);
+ ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+ ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ method public int getAnchorId();
+ method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+ method public void setAnchorId(int);
+ method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
+ field public int anchorGravity;
+ field public int gravity;
+ field public int keyline;
+ }
+
+ protected static class CoordinatorLayout.SavedState extends android.view.View.BaseSavedState {
+ ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+ ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
+ }
+
+ public class FloatingActionButton extends android.widget.ImageButton {
+ ctor public FloatingActionButton(android.content.Context);
+ ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
+ ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
+ method public void hide();
+ method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+ method public void setRippleColor(int);
+ method public void show();
+ method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+ }
+
+ public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+ ctor public FloatingActionButton.Behavior();
+ method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
+ method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
+ method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
+ }
+
+ public static abstract class FloatingActionButton.OnVisibilityChangedListener {
+ ctor public FloatingActionButton.OnVisibilityChangedListener();
+ method public void onHidden(android.support.design.widget.FloatingActionButton);
+ method public void onShown(android.support.design.widget.FloatingActionButton);
+ }
+
+ abstract class HeaderBehavior extends android.support.design.widget.ViewOffsetBehavior {
+ ctor public HeaderBehavior();
+ ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
+ }
+
+ abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
+ ctor public HeaderScrollingViewBehavior();
+ ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+ method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
+ }
+
+ public class NavigationView extends android.widget.FrameLayout {
+ ctor public NavigationView(android.content.Context);
+ ctor public NavigationView(android.content.Context, android.util.AttributeSet);
+ ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
+ method public void addHeaderView(android.view.View);
+ method public android.graphics.drawable.Drawable getItemBackground();
+ method public android.content.res.ColorStateList getItemIconTintList();
+ method public android.content.res.ColorStateList getItemTextColor();
+ method public android.view.Menu getMenu();
+ method public android.view.View inflateHeaderView(int);
+ method public void inflateMenu(int);
+ method public void removeHeaderView(android.view.View);
+ method public void setCheckedItem(int);
+ method public void setItemBackground(android.graphics.drawable.Drawable);
+ method public void setItemBackgroundResource(int);
+ method public void setItemIconTintList(android.content.res.ColorStateList);
+ method public void setItemTextAppearance(int);
+ method public void setItemTextColor(android.content.res.ColorStateList);
+ method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
+ }
+
+ public static abstract interface NavigationView.OnNavigationItemSelectedListener {
+ method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
+ }
+
+ public static class NavigationView.SavedState extends android.view.View.BaseSavedState {
+ ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
+ ctor public NavigationView.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
+ field public android.os.Bundle menuState;
+ }
+
+ public final class Snackbar {
+ method public void dismiss();
+ method public int getDuration();
+ method public android.view.View getView();
+ method public boolean isShown();
+ method public boolean isShownOrQueued();
+ method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
+ method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
+ method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
+ method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
+ method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
+ method public android.support.design.widget.Snackbar setActionTextColor(int);
+ method public android.support.design.widget.Snackbar setCallback(android.support.design.widget.Snackbar.Callback);
+ method public android.support.design.widget.Snackbar setDuration(int);
+ method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
+ method public android.support.design.widget.Snackbar setText(int);
+ method public void show();
+ field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
+ field public static final int LENGTH_LONG = 0; // 0x0
+ field public static final int LENGTH_SHORT = -1; // 0xffffffff
+ }
+
+ public static abstract class Snackbar.Callback {
+ ctor public Snackbar.Callback();
+ method public void onDismissed(android.support.design.widget.Snackbar, int);
+ method public void onShown(android.support.design.widget.Snackbar);
+ field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
+ field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
+ field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
+ field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
+ field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
+ }
+
+ public class SwipeDismissBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+ ctor public SwipeDismissBehavior();
+ method public int getDragState();
+ method public void setDragDismissDistance(float);
+ method public void setEndAlphaSwipeDistance(float);
+ method public void setListener(android.support.design.widget.SwipeDismissBehavior.OnDismissListener);
+ method public void setSensitivity(float);
+ method public void setStartAlphaSwipeDistance(float);
+ method public void setSwipeDirection(int);
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ field public static final int SWIPE_DIRECTION_ANY = 2; // 0x2
+ field public static final int SWIPE_DIRECTION_END_TO_START = 1; // 0x1
+ field public static final int SWIPE_DIRECTION_START_TO_END = 0; // 0x0
+ }
+
+ public static abstract interface SwipeDismissBehavior.OnDismissListener {
+ method public abstract void onDismiss(android.view.View);
+ method public abstract void onDragStateChanged(int);
+ }
+
+ public class TabLayout extends android.widget.HorizontalScrollView {
+ ctor public TabLayout(android.content.Context);
+ ctor public TabLayout(android.content.Context, android.util.AttributeSet);
+ ctor public TabLayout(android.content.Context, android.util.AttributeSet, int);
+ method public void addTab(android.support.design.widget.TabLayout.Tab);
+ method public void addTab(android.support.design.widget.TabLayout.Tab, int);
+ method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
+ method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
+ method public int getSelectedTabPosition();
+ method public android.support.design.widget.TabLayout.Tab getTabAt(int);
+ method public int getTabCount();
+ method public int getTabGravity();
+ method public int getTabMode();
+ method public android.content.res.ColorStateList getTabTextColors();
+ method public android.support.design.widget.TabLayout.Tab newTab();
+ method public void removeAllTabs();
+ method public void removeTab(android.support.design.widget.TabLayout.Tab);
+ method public void removeTabAt(int);
+ method public void setOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
+ method public void setScrollPosition(int, float, boolean);
+ method public void setSelectedTabIndicatorColor(int);
+ method public void setSelectedTabIndicatorHeight(int);
+ method public void setTabGravity(int);
+ method public void setTabMode(int);
+ method public void setTabTextColors(android.content.res.ColorStateList);
+ method public void setTabTextColors(int, int);
+ method public void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
+ method public void setupWithViewPager(android.support.v4.view.ViewPager);
+ field public static final int GRAVITY_CENTER = 1; // 0x1
+ field public static final int GRAVITY_FILL = 0; // 0x0
+ field public static final int MODE_FIXED = 1; // 0x1
+ field public static final int MODE_SCROLLABLE = 0; // 0x0
+ }
+
+ public static abstract interface TabLayout.OnTabSelectedListener {
+ method public abstract void onTabReselected(android.support.design.widget.TabLayout.Tab);
+ method public abstract void onTabSelected(android.support.design.widget.TabLayout.Tab);
+ method public abstract void onTabUnselected(android.support.design.widget.TabLayout.Tab);
+ }
+
+ public static final class TabLayout.Tab {
+ method public java.lang.CharSequence getContentDescription();
+ method public android.view.View getCustomView();
+ method public android.graphics.drawable.Drawable getIcon();
+ method public int getPosition();
+ method public java.lang.Object getTag();
+ method public java.lang.CharSequence getText();
+ method public boolean isSelected();
+ method public void select();
+ method public android.support.design.widget.TabLayout.Tab setContentDescription(int);
+ method public android.support.design.widget.TabLayout.Tab setContentDescription(java.lang.CharSequence);
+ method public android.support.design.widget.TabLayout.Tab setCustomView(android.view.View);
+ method public android.support.design.widget.TabLayout.Tab setCustomView(int);
+ method public android.support.design.widget.TabLayout.Tab setIcon(android.graphics.drawable.Drawable);
+ method public android.support.design.widget.TabLayout.Tab setIcon(int);
+ method public android.support.design.widget.TabLayout.Tab setTag(java.lang.Object);
+ method public android.support.design.widget.TabLayout.Tab setText(java.lang.CharSequence);
+ method public android.support.design.widget.TabLayout.Tab setText(int);
+ field public static final int INVALID_POSITION = -1; // 0xffffffff
+ }
+
+ public static class TabLayout.TabLayoutOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+ ctor public TabLayout.TabLayoutOnPageChangeListener(android.support.design.widget.TabLayout);
+ method public void onPageScrollStateChanged(int);
+ method public void onPageScrolled(int, float, int);
+ method public void onPageSelected(int);
+ }
+
+ public static class TabLayout.ViewPagerOnTabSelectedListener implements android.support.design.widget.TabLayout.OnTabSelectedListener {
+ ctor public TabLayout.ViewPagerOnTabSelectedListener(android.support.v4.view.ViewPager);
+ method public void onTabReselected(android.support.design.widget.TabLayout.Tab);
+ method public void onTabSelected(android.support.design.widget.TabLayout.Tab);
+ method public void onTabUnselected(android.support.design.widget.TabLayout.Tab);
+ }
+
+ public class TextInputLayout extends android.widget.LinearLayout {
+ ctor public TextInputLayout(android.content.Context);
+ ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
+ ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
+ method public int getCounterMaxLength();
+ method public android.widget.EditText getEditText();
+ method public java.lang.CharSequence getError();
+ method public java.lang.CharSequence getHint();
+ method public android.graphics.Typeface getTypeface();
+ method public boolean isErrorEnabled();
+ method public boolean isHintAnimationEnabled();
+ method public void setCounterEnabled(boolean);
+ method public void setCounterMaxLength(int);
+ method public void setError(java.lang.CharSequence);
+ method public void setErrorEnabled(boolean);
+ method public void setHint(java.lang.CharSequence);
+ method public void setHintAnimationEnabled(boolean);
+ method public void setHintTextAppearance(int);
+ method public void setTypeface(android.graphics.Typeface);
+ }
+
+ class ViewOffsetBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+ ctor public ViewOffsetBehavior();
+ ctor public ViewOffsetBehavior(android.content.Context, android.util.AttributeSet);
+ method public int getLeftAndRightOffset();
+ method public int getTopAndBottomOffset();
+ method public boolean setLeftAndRightOffset(int);
+ method public boolean setTopAndBottomOffset(int);
+ }
+
+}
+
diff --git a/design/api/current.txt b/design/api/current.txt
index de4e09b..7d85b1b 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -12,10 +12,9 @@
method public void setTargetElevation(float);
}
- public static class AppBarLayout.Behavior extends android.support.design.widget.ViewOffsetBehavior {
+ public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
ctor public AppBarLayout.Behavior();
ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
- method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.MotionEvent);
method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, float, float, boolean);
method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[]);
@@ -24,11 +23,16 @@
method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int);
method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View);
- method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.MotionEvent);
+ method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
+ }
+
+ public static abstract class AppBarLayout.Behavior.DragCallback {
+ ctor public AppBarLayout.Behavior.DragCallback();
+ method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
}
protected static class AppBarLayout.Behavior.SavedState extends android.view.View.BaseSavedState {
- ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel);
+ ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
}
@@ -49,41 +53,77 @@
field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
+ field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
}
public static abstract interface AppBarLayout.OnOffsetChangedListener {
method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
}
- public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
+ public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
ctor public AppBarLayout.ScrollingViewBehavior();
ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
method public int getOverlayTop();
method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
- method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
+ method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
method public void setOverlayTop(int);
}
+ public class BottomSheetBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
+ ctor public BottomSheetBehavior();
+ ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
+ method public static android.support.design.widget.BottomSheetBehavior<V> from(V);
+ method public final int getPeekHeight();
+ method public final int getState();
+ method public final void setPeekHeight(int);
+ method public final void setState(int);
+ field public static final int STATE_COLLAPSED = 4; // 0x4
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_EXPANDED = 3; // 0x3
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ protected static class BottomSheetBehavior.SavedState extends android.view.View.BaseSavedState {
+ ctor public BottomSheetBehavior.SavedState(android.os.Parcel);
+ ctor public BottomSheetBehavior.SavedState(android.os.Parcelable, int);
+ field public static final android.os.Parcelable.Creator<android.support.design.widget.BottomSheetBehavior.SavedState> CREATOR;
+ }
+
public class CollapsingToolbarLayout extends android.widget.FrameLayout {
ctor public CollapsingToolbarLayout(android.content.Context);
ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
method public int getCollapsedTitleGravity();
+ method public android.graphics.Typeface getCollapsedTitleTypeface();
method public android.graphics.drawable.Drawable getContentScrim();
method public int getExpandedTitleGravity();
+ method public int getExpandedTitleMarginBottom();
+ method public int getExpandedTitleMarginEnd();
+ method public int getExpandedTitleMarginStart();
+ method public int getExpandedTitleMarginTop();
+ method public android.graphics.Typeface getExpandedTitleTypeface();
method public android.graphics.drawable.Drawable getStatusBarScrim();
method public java.lang.CharSequence getTitle();
method public boolean isTitleEnabled();
method public void setCollapsedTitleGravity(int);
method public void setCollapsedTitleTextAppearance(int);
method public void setCollapsedTitleTextColor(int);
+ method public void setCollapsedTitleTypeface(android.graphics.Typeface);
method public void setContentScrim(android.graphics.drawable.Drawable);
method public void setContentScrimColor(int);
method public void setContentScrimResource(int);
method public void setExpandedTitleColor(int);
method public void setExpandedTitleGravity(int);
+ method public void setExpandedTitleMargin(int, int, int, int);
+ method public void setExpandedTitleMarginBottom(int);
+ method public void setExpandedTitleMarginEnd(int);
+ method public void setExpandedTitleMarginStart(int);
+ method public void setExpandedTitleMarginTop(int);
method public void setExpandedTitleTextAppearance(int);
+ method public void setExpandedTitleTypeface(android.graphics.Typeface);
+ method public void setScrimsShown(boolean);
+ method public void setScrimsShown(boolean, boolean);
method public void setStatusBarScrim(android.graphics.drawable.Drawable);
method public void setStatusBarScrimColor(int);
method public void setStatusBarScrimResource(int);
@@ -173,33 +213,59 @@
}
protected static class CoordinatorLayout.SavedState extends android.view.View.BaseSavedState {
- ctor public CoordinatorLayout.SavedState(android.os.Parcel);
+ ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
}
- public class FloatingActionButton extends android.widget.ImageView {
+ public class FloatingActionButton extends android.support.design.widget.VisibilityAwareImageButton {
ctor public FloatingActionButton(android.content.Context);
ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
+ method public android.graphics.drawable.Drawable getContentBackground();
+ method public boolean getContentRect(android.graphics.Rect);
+ method public float getFloatingActionButtonElevation();
+ method public boolean getUseCompatPadding();
method public void hide();
+ method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
+ method public void setFloatingActionButtonElevation(float);
method public void setRippleColor(int);
+ method public void setUseCompatPadding(boolean);
method public void show();
+ method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
}
public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
ctor public FloatingActionButton.Behavior();
method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
- method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
}
+ public static abstract class FloatingActionButton.OnVisibilityChangedListener {
+ ctor public FloatingActionButton.OnVisibilityChangedListener();
+ method public void onHidden(android.support.design.widget.FloatingActionButton);
+ method public void onShown(android.support.design.widget.FloatingActionButton);
+ }
+
+ abstract class HeaderBehavior extends android.support.design.widget.ViewOffsetBehavior {
+ ctor public HeaderBehavior();
+ ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
+ }
+
+ abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
+ ctor public HeaderScrollingViewBehavior();
+ ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
+ method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
+ }
+
public class NavigationView extends android.widget.FrameLayout {
ctor public NavigationView(android.content.Context);
ctor public NavigationView(android.content.Context, android.util.AttributeSet);
ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
method public void addHeaderView(android.view.View);
+ method public int getHeaderCount();
+ method public android.view.View getHeaderView(int);
method public android.graphics.drawable.Drawable getItemBackground();
method public android.content.res.ColorStateList getItemIconTintList();
method public android.content.res.ColorStateList getItemTextColor();
@@ -221,7 +287,7 @@
}
public static class NavigationView.SavedState extends android.view.View.BaseSavedState {
- ctor public NavigationView.SavedState(android.os.Parcel);
+ ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
ctor public NavigationView.SavedState(android.os.Parcelable);
field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
field public android.os.Bundle menuState;
@@ -232,6 +298,7 @@
method public int getDuration();
method public android.view.View getView();
method public boolean isShown();
+ method public boolean isShownOrQueued();
method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
@@ -261,6 +328,7 @@
public class SwipeDismissBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
ctor public SwipeDismissBehavior();
+ method public boolean canSwipeDismissView(android.view.View);
method public int getDragState();
method public void setDragDismissDistance(float);
method public void setEndAlphaSwipeDistance(float);
@@ -307,7 +375,7 @@
method public void setTabMode(int);
method public void setTabTextColors(android.content.res.ColorStateList);
method public void setTabTextColors(int, int);
- method public void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
+ method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
method public void setupWithViewPager(android.support.v4.view.ViewPager);
field public static final int GRAVITY_CENTER = 1; // 0x1
field public static final int GRAVITY_FILL = 0; // 0x0
@@ -360,15 +428,22 @@
ctor public TextInputLayout(android.content.Context);
ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
+ method public int getCounterMaxLength();
method public android.widget.EditText getEditText();
method public java.lang.CharSequence getError();
method public java.lang.CharSequence getHint();
+ method public android.graphics.Typeface getTypeface();
+ method public boolean isCounterEnabled();
method public boolean isErrorEnabled();
method public boolean isHintAnimationEnabled();
+ method public boolean isHintEnabled();
+ method public void setCounterEnabled(boolean);
+ method public void setCounterMaxLength(int);
method public void setError(java.lang.CharSequence);
method public void setErrorEnabled(boolean);
method public void setHint(java.lang.CharSequence);
method public void setHintAnimationEnabled(boolean);
+ method public void setHintEnabled(boolean);
method public void setHintTextAppearance(int);
method public void setTypeface(android.graphics.Typeface);
}
@@ -382,5 +457,11 @@
method public boolean setTopAndBottomOffset(int);
}
+ class VisibilityAwareImageButton extends android.widget.ImageButton {
+ ctor public VisibilityAwareImageButton(android.content.Context);
+ ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet);
+ ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet, int);
+ }
+
}
diff --git a/design/base/android/support/design/widget/AnimationUtils.java b/design/base/android/support/design/widget/AnimationUtils.java
index a7854f5..8ef1722 100644
--- a/design/base/android/support/design/widget/AnimationUtils.java
+++ b/design/base/android/support/design/widget/AnimationUtils.java
@@ -16,7 +16,9 @@
package android.support.design.widget;
+import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -26,6 +28,8 @@
static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
+ static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new FastOutLinearInInterpolator();
+ static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR = new LinearOutSlowInInterpolator();
static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
/**
diff --git a/design/base/android/support/design/widget/CircularBorderDrawable.java b/design/base/android/support/design/widget/CircularBorderDrawable.java
index ff57777..617a501 100644
--- a/design/base/android/support/design/widget/CircularBorderDrawable.java
+++ b/design/base/android/support/design/widget/CircularBorderDrawable.java
@@ -16,6 +16,7 @@
package android.support.design.widget;
+import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.LinearGradient;
@@ -50,10 +51,13 @@
private int mBottomOuterStrokeColor;
private int mBottomInnerStrokeColor;
- private int mTintColor;
+ private ColorStateList mBorderTint;
+ private int mCurrentBorderTintColor;
private boolean mInvalidateShader = true;
+ private float mRotation;
+
public CircularBorderDrawable() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
@@ -98,8 +102,11 @@
rectF.right -= halfBorderWidth;
rectF.bottom -= halfBorderWidth;
+ canvas.save();
+ canvas.rotate(mRotation, rectF.centerX(), rectF.centerY());
// Draw the oval
canvas.drawOval(rectF, mPaint);
+ canvas.restore();
}
@Override
@@ -115,8 +122,11 @@
invalidateSelf();
}
- void setTintColor(int tintColor) {
- mTintColor = tintColor;
+ void setBorderTint(ColorStateList tint) {
+ if (tint != null) {
+ mCurrentBorderTintColor = tint.getColorForState(getState(), mCurrentBorderTintColor);
+ }
+ mBorderTint = tint;
mInvalidateShader = true;
invalidateSelf();
}
@@ -132,11 +142,38 @@
return mBorderWidth > 0 ? PixelFormat.TRANSLUCENT : PixelFormat.TRANSPARENT;
}
+ final void setRotation(float rotation) {
+ if (rotation != mRotation) {
+ mRotation = rotation;
+ invalidateSelf();
+ }
+ }
+
@Override
protected void onBoundsChange(Rect bounds) {
mInvalidateShader = true;
}
+ @Override
+ public boolean isStateful() {
+ return (mBorderTint != null && mBorderTint.isStateful()) || super.isStateful();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ if (mBorderTint != null) {
+ final int newColor = mBorderTint.getColorForState(state, mCurrentBorderTintColor);
+ if (newColor != mCurrentBorderTintColor) {
+ mInvalidateShader = true;
+ mCurrentBorderTintColor = newColor;
+ }
+ }
+ if (mInvalidateShader) {
+ invalidateSelf();
+ }
+ return mInvalidateShader;
+ }
+
/**
* Creates a vertical {@link LinearGradient}
* @return
@@ -148,14 +185,14 @@
final float borderRatio = mBorderWidth / rect.height();
final int[] colors = new int[6];
- colors[0] = ColorUtils.compositeColors(mTopOuterStrokeColor, mTintColor);
- colors[1] = ColorUtils.compositeColors(mTopInnerStrokeColor, mTintColor);
+ colors[0] = ColorUtils.compositeColors(mTopOuterStrokeColor, mCurrentBorderTintColor);
+ colors[1] = ColorUtils.compositeColors(mTopInnerStrokeColor, mCurrentBorderTintColor);
colors[2] = ColorUtils.compositeColors(
- ColorUtils.setAlphaComponent(mTopInnerStrokeColor, 0), mTintColor);
+ ColorUtils.setAlphaComponent(mTopInnerStrokeColor, 0), mCurrentBorderTintColor);
colors[3] = ColorUtils.compositeColors(
- ColorUtils.setAlphaComponent(mBottomInnerStrokeColor, 0), mTintColor);
- colors[4] = ColorUtils.compositeColors(mBottomInnerStrokeColor, mTintColor);
- colors[5] = ColorUtils.compositeColors(mBottomOuterStrokeColor, mTintColor);
+ ColorUtils.setAlphaComponent(mBottomInnerStrokeColor, 0), mCurrentBorderTintColor);
+ colors[4] = ColorUtils.compositeColors(mBottomInnerStrokeColor, mCurrentBorderTintColor);
+ colors[5] = ColorUtils.compositeColors(mBottomOuterStrokeColor, mCurrentBorderTintColor);
final float[] positions = new float[6];
positions[0] = 0f;
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
index 969e570..189060a 100644
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
@@ -18,13 +18,30 @@
import android.content.res.ColorStateList;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.PorterDuff;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.support.annotation.Nullable;
import android.support.design.R;
-import android.view.View;
+import android.view.ViewTreeObserver;
abstract class FloatingActionButtonImpl {
+ Drawable mShapeDrawable;
+ Drawable mRippleDrawable;
+ CircularBorderDrawable mBorderDrawable;
+ Drawable mContentBackground;
+
+ float mElevation;
+ float mPressedTranslationZ;
+
+ interface InternalVisibilityChangedListener {
+ public void onShown();
+ public void onHidden();
+ }
+
static final int SHOW_HIDE_ANIM_DURATION = 200;
static final int[] PRESSED_ENABLED_STATE_SET = {android.R.attr.state_pressed,
@@ -33,15 +50,19 @@
android.R.attr.state_enabled};
static final int[] EMPTY_STATE_SET = new int[0];
- final View mView;
+ final VisibilityAwareImageButton mView;
final ShadowViewDelegate mShadowViewDelegate;
- FloatingActionButtonImpl(View view, ShadowViewDelegate shadowViewDelegate) {
+ private final Rect mTmpRect = new Rect();
+ private ViewTreeObserver.OnPreDrawListener mPreDrawListener;
+
+ FloatingActionButtonImpl(VisibilityAwareImageButton view,
+ ShadowViewDelegate shadowViewDelegate) {
mView = view;
mShadowViewDelegate = shadowViewDelegate;
}
- abstract void setBackgroundDrawable(Drawable originalBackground, ColorStateList backgroundTint,
+ abstract void setBackgroundDrawable(ColorStateList backgroundTint,
PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth);
abstract void setBackgroundTintList(ColorStateList tint);
@@ -50,19 +71,70 @@
abstract void setRippleColor(int rippleColor);
- abstract void setElevation(float elevation);
+ final void setElevation(float elevation) {
+ if (mElevation != elevation) {
+ mElevation = elevation;
+ onElevationChanged(elevation);
+ }
+ }
- abstract void setPressedTranslationZ(float translationZ);
+ abstract float getElevation();
+
+ final void setPressedTranslationZ(float translationZ) {
+ if (mPressedTranslationZ != translationZ) {
+ mPressedTranslationZ = translationZ;
+ onTranslationZChanged(translationZ);
+ }
+ }
+
+ abstract void onElevationChanged(float elevation);
+
+ abstract void onTranslationZChanged(float translationZ);
abstract void onDrawableStateChanged(int[] state);
abstract void jumpDrawableToCurrentState();
- abstract void hide();
+ abstract void hide(@Nullable InternalVisibilityChangedListener listener, boolean fromUser);
- abstract void show();
+ abstract void show(@Nullable InternalVisibilityChangedListener listener, boolean fromUser);
- Drawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
+ final Drawable getContentBackground() {
+ return mContentBackground;
+ }
+
+ abstract void onCompatShadowChanged();
+
+ final void updatePadding() {
+ Rect rect = mTmpRect;
+ getPadding(rect);
+ onPaddingUpdated(rect);
+ mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom);
+ }
+
+ abstract void getPadding(Rect rect);
+
+ void onPaddingUpdated(Rect padding) {}
+
+ void onAttachedToWindow() {
+ if (requirePreDrawListener()) {
+ ensurePreDrawListener();
+ mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+ }
+ }
+
+ void onDetachedFromWindow() {
+ if (mPreDrawListener != null) {
+ mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
+ mPreDrawListener = null;
+ }
+ }
+
+ boolean requirePreDrawListener() {
+ return false;
+ }
+
+ CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
final Resources resources = mView.getResources();
CircularBorderDrawable borderDrawable = newCircularDrawable();
borderDrawable.setGradientColors(
@@ -71,11 +143,33 @@
resources.getColor(R.color.design_fab_stroke_end_inner_color),
resources.getColor(R.color.design_fab_stroke_end_outer_color));
borderDrawable.setBorderWidth(borderWidth);
- borderDrawable.setTintColor(backgroundTint.getDefaultColor());
+ borderDrawable.setBorderTint(backgroundTint);
return borderDrawable;
}
CircularBorderDrawable newCircularDrawable() {
return new CircularBorderDrawable();
}
+
+ void onPreDraw() {
+ }
+
+ private void ensurePreDrawListener() {
+ if (mPreDrawListener == null) {
+ mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ FloatingActionButtonImpl.this.onPreDraw();
+ return true;
+ }
+ };
+ }
+ }
+
+ GradientDrawable createShapeDrawable() {
+ GradientDrawable d = new GradientDrawable();
+ d.setShape(GradientDrawable.OVAL);
+ d.setColor(Color.WHITE);
+ return d;
+ }
}
diff --git a/design/base/android/support/design/widget/ShadowDrawableWrapper.java b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
index dec1b62..bd7997f 100644
--- a/design/base/android/support/design/widget/ShadowDrawableWrapper.java
+++ b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
@@ -71,6 +71,8 @@
private boolean mAddPaddingForCorners = true;
+ private float mRotation;
+
/**
* If shadow size is set to a value above max shadow, we print a warning
*/
@@ -195,7 +197,17 @@
super.draw(canvas);
}
+ final void setRotation(float rotation) {
+ if (mRotation != rotation) {
+ mRotation = rotation;
+ invalidateSelf();
+ }
+ }
+
private void drawShadow(Canvas canvas) {
+ final int rotateSaved = canvas.save();
+ canvas.rotate(mRotation, mContentBounds.centerX(), mContentBounds.centerY());
+
final float edgeShadowTop = -mCornerRadius - mShadowSize;
final float shadowOffset = mCornerRadius;
final boolean drawHorizontalEdges = mContentBounds.width() - 2 * shadowOffset > 0;
@@ -262,6 +274,8 @@
mContentBounds.height() - 2 * shadowOffset, -mCornerRadius, mEdgeShadowPaint);
}
canvas.restoreToCount(saved);
+
+ canvas.restoreToCount(rotateSaved);
}
private void buildShadowCorners() {
diff --git a/design/base/android/support/design/widget/ShadowViewDelegate.java b/design/base/android/support/design/widget/ShadowViewDelegate.java
index 9a395e6..83a3a7a 100644
--- a/design/base/android/support/design/widget/ShadowViewDelegate.java
+++ b/design/base/android/support/design/widget/ShadowViewDelegate.java
@@ -22,4 +22,5 @@
float getRadius();
void setShadowPadding(int left, int top, int right, int bottom);
void setBackgroundDrawable(Drawable background);
+ boolean isCompatPaddingEnabled();
}
diff --git a/design/base/android/support/design/widget/StateListAnimator.java b/design/base/android/support/design/widget/StateListAnimator.java
index c937b0b..2de5dba 100644
--- a/design/base/android/support/design/widget/StateListAnimator.java
+++ b/design/base/android/support/design/widget/StateListAnimator.java
@@ -124,8 +124,11 @@
if (mLastMatch != null) {
cancel();
}
+
mLastMatch = match;
- if (match != null) {
+
+ View view = mViewRef.get();
+ if (match != null && view != null && view.getVisibility() == View.VISIBLE ) {
start(match);
}
}
diff --git a/design/base/android/support/design/widget/ValueAnimatorCompat.java b/design/base/android/support/design/widget/ValueAnimatorCompat.java
index 1e33f66..20bebb6 100644
--- a/design/base/android/support/design/widget/ValueAnimatorCompat.java
+++ b/design/base/android/support/design/widget/ValueAnimatorCompat.java
@@ -104,6 +104,7 @@
abstract void cancel();
abstract float getAnimatedFraction();
abstract void end();
+ abstract long getDuration();
}
private final Impl mImpl;
@@ -191,4 +192,8 @@
public void end() {
mImpl.end();
}
+
+ public long getDuration() {
+ return mImpl.getDuration();
+ }
}
diff --git a/design/base/android/support/design/widget/VisibilityAwareImageButton.java b/design/base/android/support/design/widget/VisibilityAwareImageButton.java
new file mode 100644
index 0000000..d7a0b13
--- /dev/null
+++ b/design/base/android/support/design/widget/VisibilityAwareImageButton.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageButton;
+
+class VisibilityAwareImageButton extends ImageButton {
+
+ private int mUserSetVisibility;
+
+ public VisibilityAwareImageButton(Context context) {
+ this(context, null);
+ }
+
+ public VisibilityAwareImageButton(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public VisibilityAwareImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mUserSetVisibility = getVisibility();
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ internalSetVisibility(visibility, true);
+ }
+
+ final void internalSetVisibility(int visibility, boolean fromUser) {
+ super.setVisibility(visibility);
+ if (fromUser) {
+ mUserSetVisibility = visibility;
+ }
+ }
+
+ final int getUserSetVisibility() {
+ return mUserSetVisibility;
+ }
+}
diff --git a/design/build.gradle b/design/build.gradle
index 5f5482f..401ec8e 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -5,6 +5,7 @@
dependencies {
compile project(':support-v4')
compile project(':support-appcompat-v7')
+ compile project(':support-recyclerview-v7')
}
android {
@@ -12,7 +13,7 @@
sourceSets {
main.manifest.srcFile 'AndroidManifest.xml'
- main.java.srcDirs = ['base', 'eclair-mr1', 'honeycomb', 'honeycomb-mr1', 'lollipop', 'src']
+ main.java.srcDirs = ['base', 'eclair-mr1', 'honeycomb', 'honeycomb-mr1', 'ics', 'lollipop', 'src']
main.res.srcDirs 'res', 'res-public'
main.assets.srcDir 'assets'
main.resources.srcDir 'src'
@@ -38,3 +39,70 @@
consumerProguardFiles 'proguard-rules.pro'
}
}
+
+android.libraryVariants.all { variant ->
+ def name = variant.buildType.name
+
+ if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
+ return; // Skip debug builds.
+ }
+ def suffix = name.capitalize()
+
+ def jarTask = project.tasks.create(name: "jar${suffix}", type: Jar){
+ dependsOn variant.javaCompile
+ from variant.javaCompile.destinationDir
+ from 'LICENSE.txt'
+ }
+ def javadocTask = project.tasks.create(name: "javadoc${suffix}", type: Javadoc) {
+ source android.sourceSets.main.java
+ classpath = files(variant.javaCompile.classpath.files) + files(
+ "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar")
+ }
+
+ def javadocJarTask = project.tasks.create(name: "javadocJar${suffix}", type: Jar) {
+ classifier = 'javadoc'
+ from 'build/docs/javadoc'
+ }
+
+ def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
+ classifier = 'sources'
+ from android.sourceSets.main.java.srcDirs
+ }
+
+ artifacts.add('archives', javadocJarTask);
+ artifacts.add('archives', sourcesJarTask);
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: uri(rootProject.ext.supportRepoOut)) {
+ }
+
+ pom.project {
+ name 'Android Design Support Library'
+ description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
+ url 'http://developer.android.com/tools/extras/support-library.html'
+ inceptionYear '2011'
+
+ licenses {
+ license {
+ name 'The Apache Software License, Version 2.0'
+ url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ distribution 'repo'
+ }
+ }
+
+ scm {
+ url "http://source.android.com"
+ connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+ }
+ developers {
+ developer {
+ name 'The Android Open Source Project'
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java b/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
index 6fb3126..92f9603 100644
--- a/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
+++ b/design/eclair-mr1/android/support/design/widget/FloatingActionButtonEclairMr1.java
@@ -23,7 +23,9 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
+import android.support.annotation.Nullable;
import android.support.design.R;
+import android.support.design.widget.AnimationUtils.AnimationListenerAdapter;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.view.View;
import android.view.animation.Animation;
@@ -31,21 +33,14 @@
class FloatingActionButtonEclairMr1 extends FloatingActionButtonImpl {
- private Drawable mShapeDrawable;
- private Drawable mRippleDrawable;
- private Drawable mBorderDrawable;
-
- private float mElevation;
- private float mPressedTranslationZ;
private int mAnimationDuration;
-
private StateListAnimator mStateListAnimator;
+ private boolean mIsHiding;
ShadowDrawableWrapper mShadowDrawable;
- private boolean mIsHiding;
-
- FloatingActionButtonEclairMr1(View view, ShadowViewDelegate shadowViewDelegate) {
+ FloatingActionButtonEclairMr1(VisibilityAwareImageButton view,
+ ShadowViewDelegate shadowViewDelegate) {
super(view, shadowViewDelegate);
mAnimationDuration = view.getResources().getInteger(android.R.integer.config_shortAnimTime);
@@ -64,23 +59,18 @@
}
@Override
- void setBackgroundDrawable(Drawable originalBackground, ColorStateList backgroundTint,
+ void setBackgroundDrawable(ColorStateList backgroundTint,
PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
// Now we need to tint the original background with the tint, using
// an InsetDrawable if we have a border width
- mShapeDrawable = DrawableCompat.wrap(originalBackground.mutate());
+ mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
if (backgroundTintMode != null) {
DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
}
// Now we created a mask Drawable which will be used for touch feedback.
- // As we don't know the actual outline of mShapeDrawable, we'll just guess that it's a
- // circle
- GradientDrawable touchFeedbackShape = new GradientDrawable();
- touchFeedbackShape.setShape(GradientDrawable.OVAL);
- touchFeedbackShape.setColor(Color.WHITE);
- touchFeedbackShape.setCornerRadius(mShadowViewDelegate.getRadius());
+ GradientDrawable touchFeedbackShape = createShapeDrawable();
// We'll now wrap that touch feedback mask drawable with a ColorStateList. We do not need
// to inset for any border here as LayerDrawable will nest the padding for us
@@ -97,24 +87,23 @@
layers = new Drawable[] {mShapeDrawable, mRippleDrawable};
}
+ mContentBackground = new LayerDrawable(layers);
+
mShadowDrawable = new ShadowDrawableWrapper(
mView.getResources(),
- new LayerDrawable(layers),
+ mContentBackground,
mShadowViewDelegate.getRadius(),
mElevation,
mElevation + mPressedTranslationZ);
mShadowDrawable.setAddPaddingForCorners(false);
-
mShadowViewDelegate.setBackgroundDrawable(mShadowDrawable);
-
- updatePadding();
}
@Override
void setBackgroundTintList(ColorStateList tint) {
DrawableCompat.setTintList(mShapeDrawable, tint);
if (mBorderDrawable != null) {
- DrawableCompat.setTintList(mBorderDrawable, tint);
+ mBorderDrawable.setBorderTint(tint);
}
}
@@ -129,18 +118,21 @@
}
@Override
- void setElevation(float elevation) {
- if (mElevation != elevation && mShadowDrawable != null) {
+ float getElevation() {
+ return mElevation;
+ }
+
+ @Override
+ void onElevationChanged(float elevation) {
+ if (mShadowDrawable != null) {
mShadowDrawable.setShadowSize(elevation, elevation + mPressedTranslationZ);
- mElevation = elevation;
updatePadding();
}
}
@Override
- void setPressedTranslationZ(float translationZ) {
- if (mPressedTranslationZ != translationZ && mShadowDrawable != null) {
- mPressedTranslationZ = translationZ;
+ void onTranslationZChanged(float translationZ) {
+ if (mShadowDrawable != null) {
mShadowDrawable.setMaxShadowSize(mElevation + translationZ);
updatePadding();
}
@@ -157,15 +149,18 @@
}
@Override
- void hide() {
+ void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
// A hide animation is in progress, or we're already hidden. Skip the call
+ if (listener != null) {
+ listener.onHidden();
+ }
return;
}
Animation anim = android.view.animation.AnimationUtils.loadAnimation(
mView.getContext(), R.anim.design_fab_out);
- anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+ anim.setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR);
anim.setDuration(SHOW_HIDE_ANIM_DURATION);
anim.setAnimationListener(new AnimationUtils.AnimationListenerAdapter() {
@Override
@@ -176,31 +171,49 @@
@Override
public void onAnimationEnd(Animation animation) {
mIsHiding = false;
- mView.setVisibility(View.GONE);
+ mView.internalSetVisibility(View.GONE, fromUser);
+ if (listener != null) {
+ listener.onHidden();
+ }
}
});
mView.startAnimation(anim);
}
@Override
- void show() {
+ void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
if (mView.getVisibility() != View.VISIBLE || mIsHiding) {
// If the view is not visible, or is visible and currently being hidden, run
// the show animation
mView.clearAnimation();
- mView.setVisibility(View.VISIBLE);
+ mView.internalSetVisibility(View.VISIBLE, fromUser);
Animation anim = android.view.animation.AnimationUtils.loadAnimation(
mView.getContext(), R.anim.design_fab_in);
anim.setDuration(SHOW_HIDE_ANIM_DURATION);
- anim.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+ anim.setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR);
+ anim.setAnimationListener(new AnimationListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (listener != null) {
+ listener.onShown();
+ }
+ }
+ });
mView.startAnimation(anim);
+ } else {
+ if (listener != null) {
+ listener.onShown();
+ }
}
}
- private void updatePadding() {
- Rect rect = new Rect();
+ @Override
+ void onCompatShadowChanged() {
+ // Ignore pre-v21
+ }
+
+ void getPadding(Rect rect) {
mShadowDrawable.getPadding(rect);
- mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom);
}
private Animation setupAnimation(Animation animation) {
diff --git a/design/eclair-mr1/android/support/design/widget/ValueAnimatorCompatImplEclairMr1.java b/design/eclair-mr1/android/support/design/widget/ValueAnimatorCompatImplEclairMr1.java
index 42cf086..1c708f5 100644
--- a/design/eclair-mr1/android/support/design/widget/ValueAnimatorCompatImplEclairMr1.java
+++ b/design/eclair-mr1/android/support/design/widget/ValueAnimatorCompatImplEclairMr1.java
@@ -147,6 +147,11 @@
}
}
+ @Override
+ public long getDuration() {
+ return mDuration;
+ }
+
private void update() {
if (mIsRunning) {
// Update the animated fraction
diff --git a/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java b/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java
deleted file mode 100644
index 72ae009..0000000
--- a/design/honeycomb-mr1/android/support/design/widget/FloatingActionButtonHoneycombMr1.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.
- */
-
-package android.support.design.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-
-class FloatingActionButtonHoneycombMr1 extends FloatingActionButtonEclairMr1 {
-
- private boolean mIsHiding;
-
- FloatingActionButtonHoneycombMr1(View view, ShadowViewDelegate shadowViewDelegate) {
- super(view, shadowViewDelegate);
- }
-
- @Override
- void hide() {
- if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
- // A hide animation is in progress, or we're already hidden. Skip the call
- return;
- }
-
- if (!ViewCompat.isLaidOut(mView) || mView.isInEditMode()) {
- // If the view isn't laid out, or we're in the editor, don't run the animation
- mView.setVisibility(View.GONE);
- } else {
- mView.animate()
- .scaleX(0f)
- .scaleY(0f)
- .alpha(0f)
- .setDuration(SHOW_HIDE_ANIM_DURATION)
- .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mIsHiding = true;
- mView.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mIsHiding = false;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mIsHiding = false;
- mView.setVisibility(View.GONE);
- }
- });
- }
- }
-
- @Override
- void show() {
- if (mView.getVisibility() != View.VISIBLE) {
- if (ViewCompat.isLaidOut(mView) && !mView.isInEditMode()) {
- mView.setAlpha(0f);
- mView.setScaleY(0f);
- mView.setScaleX(0f);
- mView.animate()
- .scaleX(1f)
- .scaleY(1f)
- .alpha(1f)
- .setDuration(SHOW_HIDE_ANIM_DURATION)
- .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mView.setVisibility(View.VISIBLE);
- }
- });
- } else {
- mView.setVisibility(View.VISIBLE);
- mView.setAlpha(1f);
- mView.setScaleY(1f);
- mView.setScaleX(1f);
- }
- }
- }
-}
diff --git a/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java b/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java
index 4f9ea39..5ee272b 100644
--- a/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java
+++ b/design/honeycomb-mr1/android/support/design/widget/ValueAnimatorCompatImplHoneycombMr1.java
@@ -113,4 +113,9 @@
public void end() {
mValueAnimator.end();
}
+
+ @Override
+ public long getDuration() {
+ return mValueAnimator.getDuration();
+ }
}
diff --git a/design/ics/android/support/design/widget/FloatingActionButtonIcs.java b/design/ics/android/support/design/widget/FloatingActionButtonIcs.java
new file mode 100644
index 0000000..4c256bc
--- /dev/null
+++ b/design/ics/android/support/design/widget/FloatingActionButtonIcs.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.support.annotation.Nullable;
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+
+class FloatingActionButtonIcs extends FloatingActionButtonEclairMr1 {
+
+ private boolean mIsHiding;
+
+ FloatingActionButtonIcs(VisibilityAwareImageButton view,
+ ShadowViewDelegate shadowViewDelegate) {
+ super(view, shadowViewDelegate);
+ }
+
+ @Override
+ boolean requirePreDrawListener() {
+ return true;
+ }
+
+ @Override
+ void onPreDraw() {
+ updateFromViewRotation(mView.getRotation());
+ }
+
+ @Override
+ void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
+ if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
+ // A hide animation is in progress, or we're already hidden. Skip the call
+ if (listener != null) {
+ listener.onHidden();
+ }
+ return;
+ }
+
+ if (!ViewCompat.isLaidOut(mView) || mView.isInEditMode()) {
+ // If the view isn't laid out, or we're in the editor, don't run the animation
+ mView.internalSetVisibility(View.GONE, fromUser);
+ if (listener != null) {
+ listener.onHidden();
+ }
+ } else {
+ mView.animate().cancel();
+ mView.animate()
+ .scaleX(0f)
+ .scaleY(0f)
+ .alpha(0f)
+ .setDuration(SHOW_HIDE_ANIM_DURATION)
+ .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
+ .setListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsHiding = true;
+ mCancelled = false;
+ mView.internalSetVisibility(View.VISIBLE, fromUser);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mIsHiding = false;
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsHiding = false;
+ if (!mCancelled) {
+ mView.internalSetVisibility(View.GONE, fromUser);
+ if (listener != null) {
+ listener.onHidden();
+ }
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
+ if (mIsHiding || mView.getVisibility() != View.VISIBLE) {
+ if (ViewCompat.isLaidOut(mView) && !mView.isInEditMode()) {
+ mView.animate().cancel();
+ if (mView.getVisibility() != View.VISIBLE) {
+ // If the view isn't visible currently, we'll animate it from a single pixel
+ mView.setAlpha(0f);
+ mView.setScaleY(0f);
+ mView.setScaleX(0f);
+ }
+ mView.animate()
+ .scaleX(1f)
+ .scaleY(1f)
+ .alpha(1f)
+ .setDuration(SHOW_HIDE_ANIM_DURATION)
+ .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mView.internalSetVisibility(View.VISIBLE, fromUser);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (listener != null) {
+ listener.onShown();
+ }
+ }
+ });
+ } else {
+ mView.internalSetVisibility(View.VISIBLE, fromUser);
+ mView.setAlpha(1f);
+ mView.setScaleY(1f);
+ mView.setScaleX(1f);
+ if (listener != null) {
+ listener.onShown();
+ }
+ }
+ }
+ }
+
+ private void updateFromViewRotation(float rotation) {
+ // Offset any View rotation
+ if (mShadowDrawable != null) {
+ mShadowDrawable.setRotation(-rotation);
+ }
+ if (mBorderDrawable != null) {
+ mBorderDrawable.setRotation(-rotation);
+ }
+ }
+}
diff --git a/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java b/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
index 554ecb8..8b90361 100644
--- a/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
+++ b/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
@@ -16,70 +16,17 @@
package android.support.design.widget;
-
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Outline;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
/**
- * Lollipop version of {@link CircularBorderDrawable} which accepts tint calls.
+ * Lollipop version of {@link CircularBorderDrawable}.
*/
class CircularBorderDrawableLollipop extends CircularBorderDrawable {
- private ColorStateList mTint;
- private PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_IN;
- private PorterDuffColorFilter mTintFilter;
-
- @Override
- public void draw(Canvas canvas) {
- boolean clearColorFilter;
- if (mTintFilter != null && mPaint.getColorFilter() == null) {
- mPaint.setColorFilter(mTintFilter);
- clearColorFilter = true;
- } else {
- clearColorFilter = false;
- }
-
- super.draw(canvas);
-
- if (clearColorFilter) {
- mPaint.setColorFilter(null);
- }
- }
-
- @Override
- public void setTintList(ColorStateList tint) {
- mTint = tint;
- mTintFilter = updateTintFilter(tint, mTintMode);
- invalidateSelf();
- }
-
- @Override
- public void setTintMode(PorterDuff.Mode tintMode) {
- mTintMode = tintMode;
- mTintFilter = updateTintFilter(mTint, tintMode);
- invalidateSelf();
- }
-
@Override
public void getOutline(Outline outline) {
copyBounds(mRect);
outline.setOval(mRect);
}
- /**
- * Ensures the tint filter is consistent with the current tint color and
- * mode.
- */
- private PorterDuffColorFilter updateTintFilter(ColorStateList tint, PorterDuff.Mode tintMode) {
- if (tint == null || tintMode == null) {
- return null;
- }
-
- final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
- return new PorterDuffColorFilter(color, tintMode);
- }
}
diff --git a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
index eb4360b..2b85845 100644
--- a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
+++ b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
@@ -22,39 +22,37 @@
import android.annotation.TargetApi;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Build;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
-import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-class FloatingActionButtonLollipop extends FloatingActionButtonHoneycombMr1 {
+class FloatingActionButtonLollipop extends FloatingActionButtonIcs {
- private Drawable mShapeDrawable;
- private RippleDrawable mRippleDrawable;
- private Drawable mBorderDrawable;
+ private final Interpolator mInterpolator;
+ private InsetDrawable mInsetDrawable;
- private Interpolator mInterpolator;
-
- FloatingActionButtonLollipop(View view, ShadowViewDelegate shadowViewDelegate) {
+ FloatingActionButtonLollipop(VisibilityAwareImageButton view,
+ ShadowViewDelegate shadowViewDelegate) {
super(view, shadowViewDelegate);
- if (!view.isInEditMode()) {
- mInterpolator = AnimationUtils.loadInterpolator(mView.getContext(),
- android.R.interpolator.fast_out_slow_in);
- }
+ mInterpolator = view.isInEditMode() ? null
+ : AnimationUtils.loadInterpolator(mView.getContext(),
+ android.R.interpolator.fast_out_slow_in);
}
@Override
- void setBackgroundDrawable(Drawable originalBackground, ColorStateList backgroundTint,
+ void setBackgroundDrawable(ColorStateList backgroundTint,
PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
- // Now we need to tint the original background with the tint
- mShapeDrawable = DrawableCompat.wrap(originalBackground.mutate());
+ // Now we need to tint the shape background with the tint
+ mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
if (backgroundTintMode != null) {
DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
@@ -72,37 +70,31 @@
mRippleDrawable = new RippleDrawable(ColorStateList.valueOf(rippleColor),
rippleContent, null);
+ mContentBackground = mRippleDrawable;
+
mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable);
- mShadowViewDelegate.setShadowPadding(0, 0, 0, 0);
- }
-
- @Override
- void setBackgroundTintList(ColorStateList tint) {
- DrawableCompat.setTintList(mShapeDrawable, tint);
- if (mBorderDrawable != null) {
- DrawableCompat.setTintList(mBorderDrawable, tint);
- }
- }
-
- @Override
- void setBackgroundTintMode(PorterDuff.Mode tintMode) {
- DrawableCompat.setTintMode(mShapeDrawable, tintMode);
}
@Override
void setRippleColor(int rippleColor) {
- mRippleDrawable.setColor(ColorStateList.valueOf(rippleColor));
+ if (mRippleDrawable instanceof RippleDrawable) {
+ ((RippleDrawable) mRippleDrawable).setColor(ColorStateList.valueOf(rippleColor));
+ } else {
+ super.setRippleColor(rippleColor);
+ }
}
@Override
- public void setElevation(float elevation) {
- ViewCompat.setElevation(mView, elevation);
+ public void onElevationChanged(float elevation) {
+ mView.setElevation(elevation);
+ if (mShadowViewDelegate.isCompatPaddingEnabled()) {
+ updatePadding();
+ }
}
@Override
- void setPressedTranslationZ(float translationZ) {
+ void onTranslationZChanged(float translationZ) {
StateListAnimator stateListAnimator = new StateListAnimator();
-
// Animate translationZ to our value when pressed or focused
stateListAnimator.addState(PRESSED_ENABLED_STATE_SET,
setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", translationZ)));
@@ -111,8 +103,32 @@
// Animate translationZ to 0 otherwise
stateListAnimator.addState(EMPTY_STATE_SET,
setupAnimator(ObjectAnimator.ofFloat(mView, "translationZ", 0f)));
-
mView.setStateListAnimator(stateListAnimator);
+
+ if (mShadowViewDelegate.isCompatPaddingEnabled()) {
+ updatePadding();
+ }
+ }
+
+ @Override
+ public float getElevation() {
+ return mView.getElevation();
+ }
+
+ @Override
+ void onCompatShadowChanged() {
+ updatePadding();
+ }
+
+ @Override
+ void onPaddingUpdated(Rect padding) {
+ if (mShadowViewDelegate.isCompatPaddingEnabled()) {
+ mInsetDrawable = new InsetDrawable(mRippleDrawable,
+ padding.left, padding.top, padding.right, padding.bottom);
+ mShadowViewDelegate.setBackgroundDrawable(mInsetDrawable);
+ } else {
+ mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable);
+ }
}
@Override
@@ -125,6 +141,11 @@
// no-op
}
+ @Override
+ boolean requirePreDrawListener() {
+ return false;
+ }
+
private Animator setupAnimator(Animator animator) {
animator.setInterpolator(mInterpolator);
return animator;
@@ -134,4 +155,18 @@
CircularBorderDrawable newCircularDrawable() {
return new CircularBorderDrawableLollipop();
}
+
+ void getPadding(Rect rect) {
+ if (mShadowViewDelegate.isCompatPaddingEnabled()) {
+ final float radius = mShadowViewDelegate.getRadius();
+ final float maxShadowSize = getElevation() + mPressedTranslationZ;
+ final int hPadding = (int) Math.ceil(
+ ShadowDrawableWrapper.calculateHorizontalPadding(maxShadowSize, radius, false));
+ final int vPadding = (int) Math.ceil(
+ ShadowDrawableWrapper.calculateVerticalPadding(maxShadowSize, radius, false));
+ rect.set(hPadding, vPadding, hPadding, vPadding);
+ } else {
+ rect.set(0, 0, 0, 0);
+ }
+ }
}
diff --git a/design/proguard-rules.pro b/design/proguard-rules.pro
index ea77945..96e2ee0 100644
--- a/design/proguard-rules.pro
+++ b/design/proguard-rules.pro
@@ -17,3 +17,6 @@
public <init>(android.content.Context, android.util.AttributeSet);
public <init>();
}
+
+# Make sure we keep annotations for CoordinatorLayout's DefaultBehavior
+-keepattributes *Annotation*
diff --git a/design/res-public/values/public_attrs.xml b/design/res-public/values/public_attrs.xml
index 30aa70a..8c8eb0d 100644
--- a/design/res-public/values/public_attrs.xml
+++ b/design/res-public/values/public_attrs.xml
@@ -25,6 +25,10 @@
<public type="attr" name="elevation"/>
<public type="attr" name="errorEnabled"/>
<public type="attr" name="errorTextAppearance"/>
+ <public type="attr" name="counterEnabled"/>
+ <public type="attr" name="counterMaxLength"/>
+ <public type="attr" name="counterTextAppearance"/>
+ <public type="attr" name="counterOverflowTextAppearance"/>
<public type="attr" name="expanded"/>
<public type="attr" name="expandedTitleGravity"/>
<public type="attr" name="expandedTitleMargin"/>
@@ -66,4 +70,5 @@
<public type="attr" name="title"/>
<public type="attr" name="titleEnabled"/>
<public type="attr" name="toolbarId"/>
+ <public type="attr" name="behavior_peekHeight"/>
</resources>
diff --git a/design/res/layout/design_layout_tab_icon.xml b/design/res/layout/design_layout_tab_icon.xml
index 6464d1f..5dcfa11 100644
--- a/design/res/layout/design_layout_tab_icon.xml
+++ b/design/res/layout/design_layout_tab_icon.xml
@@ -16,6 +16,6 @@
-->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"/>
\ No newline at end of file
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:scaleType="centerInside"/>
\ No newline at end of file
diff --git a/v17/preference-leanback/res/values/ids.xml b/design/res/layout/design_menu_item_action_area.xml
similarity index 74%
copy from v17/preference-leanback/res/values/ids.xml
copy to design/res/layout/design_menu_item_action_area.xml
index 20c1eda..ba8141d 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/design/res/layout/design_menu_item_action_area.xml
@@ -12,9 +12,8 @@
~ 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>
- <item name="transitionPosition" type="id" />
-</resources>
+ ~ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"/>
diff --git a/design/res/layout/design_navigation_item.xml b/design/res/layout/design_navigation_item.xml
index 3fcd74a..ccd42de 100644
--- a/design/res/layout/design_navigation_item.xml
+++ b/design/res/layout/design_navigation_item.xml
@@ -20,7 +20,5 @@
android:layout_height="?attr/listPreferredItemHeightSmall"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
- android:drawablePadding="@dimen/design_navigation_icon_padding"
- android:gravity="center_vertical|start"
- android:maxLines="1"
- android:textAppearance="@style/TextAppearance.AppCompat.Body2"/>
+ android:foreground="?attr/selectableItemBackground"
+ android:focusable="true"/>
diff --git a/design/res/layout/design_navigation_item_header.xml b/design/res/layout/design_navigation_item_header.xml
index 33fd199..8d03f69 100644
--- a/design/res/layout/design_navigation_item_header.xml
+++ b/design/res/layout/design_navigation_item_header.xml
@@ -15,6 +15,7 @@
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/navigation_header_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
diff --git a/design/res/layout/design_navigation_menu.xml b/design/res/layout/design_navigation_menu.xml
index 02b7aad..4d85081 100644
--- a/design/res/layout/design_navigation_menu.xml
+++ b/design/res/layout/design_navigation_menu.xml
@@ -16,11 +16,10 @@
-->
<android.support.design.internal.NavigationMenuView
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/design_navigation_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="@dimen/design_navigation_padding_top_default"
android:paddingBottom="@dimen/design_navigation_padding_bottom"
android:clipToPadding="false"
- android:divider="@null"
- android:scrollbars="vertical"
- android:listSelector="?attr/selectableItemBackground"/>
+ android:scrollbars="vertical"/>
diff --git a/design/res/layout/design_navigation_menu_item.xml b/design/res/layout/design_navigation_menu_item.xml
new file mode 100644
index 0000000..91104bb1
--- /dev/null
+++ b/design/res/layout/design_navigation_menu_item.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <CheckedTextView
+ android:id="@+id/design_menu_item_text"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:drawablePadding="@dimen/design_navigation_icon_padding"
+ android:gravity="center_vertical|start"
+ android:maxLines="1"
+ android:textAppearance="@style/TextAppearance.AppCompat.Body2"/>
+
+ <ViewStub
+ android:id="@+id/design_menu_item_action_area_stub"
+ android:inflatedId="@+id/design_menu_item_action_area"
+ android:layout="@layout/design_menu_item_action_area"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"/>
+
+</merge>
diff --git a/design/res/values-sw600dp/dimens.xml b/design/res/values-sw600dp/dimens.xml
index ebbc20e..8dada20 100644
--- a/design/res/values-sw600dp/dimens.xml
+++ b/design/res/values-sw600dp/dimens.xml
@@ -17,7 +17,7 @@
<resources>
- <dimen name="design_tab_min_width">160dp</dimen>
+ <dimen name="design_tab_scrollable_min_width">160dp</dimen>
<dimen name="design_snackbar_min_width">320dp</dimen>
<dimen name="design_snackbar_max_width">576dp</dimen>
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index 785308a..29ca0af 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -18,7 +18,6 @@
<declare-styleable name="FloatingActionButton">
<!-- Background for the FloatingActionButton -->
- <attr name="android:background"/>
<attr name="backgroundTint"/>
<attr name="backgroundTintMode"/>
@@ -35,6 +34,8 @@
<attr name="pressedTranslationZ" format="dimension"/>
<!-- The width of the border around the FAB. -->
<attr name="borderWidth" format="dimension"/>
+ <!-- Enable compat padding. -->
+ <attr name="useCompatPadding" format="boolean"/>
</declare-styleable>
<declare-styleable name="ScrimInsetsFrameLayout">
@@ -56,6 +57,12 @@
<attr name="headerLayout" format="reference"/>
</declare-styleable>
+ <declare-styleable name="ForegroundLinearLayout">
+ <attr name="android:foreground" />
+ <attr name="android:foregroundGravity" />
+ <attr name="foregroundInsidePadding" format="boolean" />
+ </declare-styleable>
+
<declare-styleable name="TabLayout">
<attr name="tabIndicatorColor" format="color"/>
<attr name="tabIndicatorHeight" format="dimension"/>
@@ -157,10 +164,20 @@
<attr name="hintTextAppearance" format="reference"/>
<!-- The hint to display in the floating label -->
<attr name="android:hint"/>
+ <!-- Whether the layout's floating label functionality is enabled -->
+ <attr name="hintEnabled" format="boolean"/>
<!-- Whether the layout is laid out as if an error will be displayed -->
<attr name="errorEnabled" format="boolean"/>
<!-- TextAppearance of any error message displayed -->
<attr name="errorTextAppearance" format="reference"/>
+ <!-- Whether the layout is laid out as if the character counter will be displayed -->
+ <attr name="counterEnabled" format="boolean"/>
+ <!-- The max length to display in the character counter -->
+ <attr name="counterMaxLength" format="integer" />
+ <!-- TextAppearance of the character counter -->
+ <attr name="counterTextAppearance" format="reference"/>
+ <!-- TextAppearance of the character counter when the text is longer than the max -->
+ <attr name="counterOverflowTextAppearance" format="reference"/>
<attr name="android:textColorHint"/>
<!-- Whether to animate hint state changes. -->
<attr name="hintAnimationEnabled" format="boolean"/>
@@ -201,6 +218,10 @@
reached the end of it's scroll range, the remainder of this view will be scrolled
into view. -->
<flag name="enterAlwaysCollapsed" value="0x8"/>
+
+ <!-- Upon a scroll ending, if the view is only partially visible then it will be
+ snapped and scrolled to it's closest edge. -->
+ <flag name="snap" value="0x10"/>
</attr>
<!-- An interpolator to use when scrolling this View. Only takes effect when View
@@ -316,5 +337,10 @@
<attr name="layout_collapseParallaxMultiplier" format="float"/>
</declare-styleable>
+ <declare-styleable name="BottomSheetBehavior_Params">
+ <!-- The height of the bottom sheet when it is collapsed. -->
+ <attr name="behavior_peekHeight" format="dimension"/>
+ </declare-styleable>
+
</resources>
diff --git a/design/res/values/dimens.xml b/design/res/values/dimens.xml
index c7f8cef..a0a536d 100644
--- a/design/res/values/dimens.xml
+++ b/design/res/values/dimens.xml
@@ -18,7 +18,7 @@
<dimen name="design_fab_elevation">6dp</dimen>
<dimen name="design_fab_translation_z_pressed">6dp</dimen>
- <dimen name="design_fab_content_size">24dp</dimen>
+ <dimen name="design_fab_image_size">24dp</dimen>
<dimen name="design_fab_size_normal">56dp</dimen>
<dimen name="design_fab_size_mini">40dp</dimen>
<dimen name="design_fab_border_width">0.5dp</dimen>
@@ -31,8 +31,10 @@
<dimen name="design_navigation_padding_top_default">0dp</dimen>
<dimen name="design_navigation_padding_bottom">8dp</dimen>
- <dimen name="design_tab_min_width">72dp</dimen>
+ <dimen name="design_tab_scrollable_min_width">72dp</dimen>
<dimen name="design_tab_max_width">264dp</dimen>
+ <dimen name="design_tab_text_size">14sp</dimen>
+ <dimen name="design_tab_text_size_2line">12sp</dimen>
<dimen name="design_snackbar_min_width">-1px</dimen>
<dimen name="design_snackbar_max_width">-1px</dimen>
diff --git a/design/res/values/strings.xml b/design/res/values/strings.xml
index 4c02de1..416d289 100644
--- a/design/res/values/strings.xml
+++ b/design/res/values/strings.xml
@@ -17,5 +17,7 @@
<resources>
<!-- The class name to the ScrollingChildBehavior required for AppBarLayout -->
<string name="appbar_scrolling_view_behavior" translatable="false">android.support.design.widget.AppBarLayout$ScrollingViewBehavior</string>
+ <!-- The text pattern for the character counter -->
+ <string name="character_counter_pattern" translatable="false">%1$d / %2$d</string>
</resources>
diff --git a/design/res/values/styles.xml b/design/res/values/styles.xml
index e75d805..24a9aa9 100644
--- a/design/res/values/styles.xml
+++ b/design/res/values/styles.xml
@@ -54,7 +54,7 @@
</style>
<style name="TextAppearance.Design.Tab" parent="TextAppearance.AppCompat.Button">
- <item name="android:textSize">14sp</item>
+ <item name="android:textSize">@dimen/design_tab_text_size</item>
<item name="android:textColor">?android:textColorSecondary</item>
<item name="textAllCaps">true</item>
</style>
@@ -62,6 +62,8 @@
<style name="Widget.Design.TextInputLayout" parent="android:Widget">
<item name="hintTextAppearance">@style/TextAppearance.Design.Hint</item>
<item name="errorTextAppearance">@style/TextAppearance.Design.Error</item>
+ <item name="counterTextAppearance">@style/TextAppearance.Design.Counter</item>
+ <item name="counterOverflowTextAppearance">@style/TextAppearance.Design.Counter.Overflow</item>
</style>
<style name="TextAppearance.Design.Hint" parent="TextAppearance.AppCompat.Caption">
@@ -72,6 +74,12 @@
<item name="android:textColor">@color/design_textinput_error_color</item>
</style>
+ <style name="TextAppearance.Design.Counter" parent="TextAppearance.AppCompat.Caption"/>
+
+ <style name="TextAppearance.Design.Counter.Overflow" parent="TextAppearance.AppCompat.Caption">
+ <item name="android:textColor">@color/design_textinput_error_color</item>
+ </style>
+
<style name="TextAppearance.Design.Snackbar.Message" parent="android:TextAppearance">
<item name="android:textSize">@dimen/design_snackbar_text_size</item>
<item name="android:textColor">?android:textColorPrimary</item>
diff --git a/design/src/android/support/design/internal/ForegroundLinearLayout.java b/design/src/android/support/design/internal/ForegroundLinearLayout.java
new file mode 100644
index 0000000..eff89e3
--- /dev/null
+++ b/design/src/android/support/design/internal/ForegroundLinearLayout.java
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+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.design.R;
+import android.support.v7.widget.LinearLayoutCompat;
+import android.util.AttributeSet;
+import android.view.Gravity;
+
+/**
+ * @hide
+ */
+public class ForegroundLinearLayout extends LinearLayoutCompat {
+
+ private Drawable mForeground;
+
+ private final Rect mSelfBounds = new Rect();
+
+ private final Rect mOverlayBounds = new Rect();
+
+ private int mForegroundGravity = Gravity.FILL;
+
+ protected boolean mForegroundInPadding = true;
+
+ boolean mForegroundBoundsChanged = false;
+
+ public ForegroundLinearLayout(Context context) {
+ this(context, null);
+ }
+
+ public ForegroundLinearLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ForegroundLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundLinearLayout,
+ defStyle, 0);
+
+ mForegroundGravity = a.getInt(
+ R.styleable.ForegroundLinearLayout_android_foregroundGravity, mForegroundGravity);
+
+ final Drawable d = a.getDrawable(R.styleable.ForegroundLinearLayout_android_foreground);
+ if (d != null) {
+ setForeground(d);
+ }
+
+ mForegroundInPadding = a.getBoolean(
+ R.styleable.ForegroundLinearLayout_foregroundInsidePadding, true);
+
+ a.recycle();
+ }
+
+ /**
+ * Describes how the foreground is positioned.
+ *
+ * @return foreground gravity.
+ * @see #setForegroundGravity(int)
+ */
+ public int getForegroundGravity() {
+ return mForegroundGravity;
+ }
+
+ /**
+ * Describes how the foreground is positioned. Defaults to START and TOP.
+ *
+ * @param foregroundGravity See {@link android.view.Gravity}
+ * @see #getForegroundGravity()
+ */
+ public void setForegroundGravity(int foregroundGravity) {
+ if (mForegroundGravity != foregroundGravity) {
+ if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
+ foregroundGravity |= Gravity.START;
+ }
+
+ if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
+ foregroundGravity |= Gravity.TOP;
+ }
+
+ mForegroundGravity = foregroundGravity;
+
+ if (mForegroundGravity == Gravity.FILL && mForeground != null) {
+ Rect padding = new Rect();
+ mForeground.getPadding(padding);
+ }
+
+ requestLayout();
+ }
+ }
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return super.verifyDrawable(who) || (who == mForeground);
+ }
+
+ @Override
+ public void jumpDrawablesToCurrentState() {
+ super.jumpDrawablesToCurrentState();
+ if (mForeground != null) {
+ mForeground.jumpToCurrentState();
+ }
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ if (mForeground != null && mForeground.isStateful()) {
+ mForeground.setState(getDrawableState());
+ }
+ }
+
+ /**
+ * Supply a Drawable that is to be rendered on top of all of the child
+ * views in the frame layout. Any padding in the Drawable will be taken
+ * into account by ensuring that the children are inset to be placed
+ * inside of the padding area.
+ *
+ * @param drawable The Drawable to be drawn on top of the children.
+ */
+ public void setForeground(Drawable drawable) {
+ if (mForeground != drawable) {
+ if (mForeground != null) {
+ mForeground.setCallback(null);
+ unscheduleDrawable(mForeground);
+ }
+
+ mForeground = drawable;
+
+ if (drawable != null) {
+ setWillNotDraw(false);
+ drawable.setCallback(this);
+ if (drawable.isStateful()) {
+ drawable.setState(getDrawableState());
+ }
+ if (mForegroundGravity == Gravity.FILL) {
+ Rect padding = new Rect();
+ drawable.getPadding(padding);
+ }
+ } else {
+ setWillNotDraw(true);
+ }
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
+ * Returns the drawable used as the foreground of this FrameLayout. The
+ * foreground drawable, if non-null, is always drawn on top of the children.
+ *
+ * @return A Drawable or null if no foreground was set.
+ */
+ public Drawable getForeground() {
+ return mForeground;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ mForegroundBoundsChanged |= changed;
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mForegroundBoundsChanged = true;
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ super.draw(canvas);
+
+ if (mForeground != null) {
+ final Drawable foreground = mForeground;
+
+ if (mForegroundBoundsChanged) {
+ mForegroundBoundsChanged = false;
+ final Rect selfBounds = mSelfBounds;
+ final Rect overlayBounds = mOverlayBounds;
+
+ final int w = getRight() - getLeft();
+ final int h = getBottom() - getTop();
+
+ if (mForegroundInPadding) {
+ selfBounds.set(0, 0, w, h);
+ } else {
+ selfBounds.set(getPaddingLeft(), getPaddingTop(),
+ w - getPaddingRight(), h - getPaddingBottom());
+ }
+
+ Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
+ foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
+ foreground.setBounds(overlayBounds);
+ }
+
+ foreground.draw(canvas);
+ }
+ }
+
+ @Override
+ public void drawableHotspotChanged(float x, float y) {
+ super.drawableHotspotChanged(x, y);
+ if (mForeground != null) {
+ mForeground.setHotspot(x, y);
+ }
+ }
+
+}
diff --git a/design/src/android/support/design/internal/NavigationMenu.java b/design/src/android/support/design/internal/NavigationMenu.java
index 4335631..2821d36 100644
--- a/design/src/android/support/design/internal/NavigationMenu.java
+++ b/design/src/android/support/design/internal/NavigationMenu.java
@@ -17,9 +17,9 @@
package android.support.design.internal;
import android.content.Context;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.SubMenuBuilder;
import android.view.SubMenu;
/**
diff --git a/design/src/android/support/design/internal/NavigationMenuItemView.java b/design/src/android/support/design/internal/NavigationMenuItemView.java
index 7813163..0423345 100644
--- a/design/src/android/support/design/internal/NavigationMenuItemView.java
+++ b/design/src/android/support/design/internal/NavigationMenuItemView.java
@@ -25,21 +25,31 @@
import android.support.design.R;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.widget.TextViewCompat;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuView;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuView;
import android.util.AttributeSet;
import android.util.TypedValue;
-import android.widget.TextView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewStub;
+import android.widget.CheckedTextView;
+import android.widget.FrameLayout;
/**
* @hide
*/
-public class NavigationMenuItemView extends TextView implements MenuView.ItemView {
+public class NavigationMenuItemView extends ForegroundLinearLayout implements MenuView.ItemView {
private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
- private int mIconSize;
+ private final int mIconSize;
+
+ private final CheckedTextView mTextView;
+
+ private FrameLayout mActionArea;
+
private MenuItemImpl mItemData;
+
private ColorStateList mIconTintList;
public NavigationMenuItemView(Context context) {
@@ -52,8 +62,12 @@
public NavigationMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ setOrientation(HORIZONTAL);
+ LayoutInflater.from(context).inflate(R.layout.design_navigation_menu_item, this, true);
mIconSize = context.getResources().getDimensionPixelSize(
R.dimen.design_navigation_icon_size);
+ mTextView = (CheckedTextView) findViewById(R.id.design_menu_item_text);
+ mTextView.setDuplicateParentStateEnabled(true);
}
@Override
@@ -71,6 +85,25 @@
setEnabled(itemData.isEnabled());
setTitle(itemData.getTitle());
setIcon(itemData.getIcon());
+ setActionView(itemData.getActionView());
+ }
+
+ public void recycle() {
+ if (mActionArea != null) {
+ mActionArea.removeAllViews();
+ }
+ mTextView.setCompoundDrawables(null, null, null, null);
+ }
+
+ private void setActionView(View actionView) {
+ if (mActionArea == null) {
+ mActionArea = (FrameLayout) ((ViewStub) findViewById(
+ R.id.design_menu_item_action_area_stub)).inflate();
+ }
+ mActionArea.removeAllViews();
+ if (actionView != null) {
+ mActionArea.addView(actionView);
+ }
}
private StateListDrawable createDefaultBackground() {
@@ -91,7 +124,7 @@
@Override
public void setTitle(CharSequence title) {
- setText(title);
+ mTextView.setText(title);
}
@Override
@@ -102,6 +135,7 @@
@Override
public void setChecked(boolean checked) {
refreshDrawableState();
+ mTextView.setChecked(checked);
}
@Override
@@ -111,11 +145,12 @@
@Override
public void setIcon(Drawable icon) {
if (icon != null) {
- icon = DrawableCompat.wrap(icon.getConstantState().newDrawable()).mutate();
+ Drawable.ConstantState state = icon.getConstantState();
+ icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate();
icon.setBounds(0, 0, mIconSize, mIconSize);
DrawableCompat.setTintList(icon, mIconTintList);
}
- TextViewCompat.setCompoundDrawablesRelative(this, icon, null, null, null);
+ TextViewCompat.setCompoundDrawablesRelative(mTextView, icon, null, null, null);
}
@Override
@@ -144,4 +179,13 @@
setIcon(mItemData.getIcon());
}
}
+
+ public void setTextAppearance(Context context, int textAppearance) {
+ mTextView.setTextAppearance(context, textAppearance);
+ }
+
+ public void setTextColor(ColorStateList colors) {
+ mTextView.setTextColor(colors);
+ }
+
}
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
index e523c38..959c0e7 100644
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ b/design/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -28,19 +28,18 @@
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.design.R;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
+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.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -49,13 +48,13 @@
/**
* @hide
*/
-public class NavigationMenuPresenter implements MenuPresenter, AdapterView.OnItemClickListener {
+public class NavigationMenuPresenter implements MenuPresenter {
private static final String STATE_HIERARCHY = "android:menu:list";
private static final String STATE_ADAPTER = "android:menu:adapter";
private NavigationMenuView mMenuView;
- private LinearLayout mHeader;
+ private LinearLayout mHeaderLayout;
private Callback mCallback;
private MenuBuilder mMenu;
@@ -100,11 +99,10 @@
if (mAdapter == null) {
mAdapter = new NavigationMenuAdapter();
}
- mHeader = (LinearLayout) mLayoutInflater.inflate(R.layout.design_navigation_item_header,
- mMenuView, false);
- mMenuView.addHeaderView(mHeader, null, false);
+ mHeaderLayout = (LinearLayout) mLayoutInflater
+ .inflate(R.layout.design_navigation_item_header,
+ mMenuView, false);
mMenuView.setAdapter(mAdapter);
- mMenuView.setOnItemClickListener(this);
}
return mMenuView;
}
@@ -112,7 +110,7 @@
@Override
public void updateMenuView(boolean cleared) {
if (mAdapter != null) {
- mAdapter.notifyDataSetChanged();
+ mAdapter.update();
}
}
@@ -184,44 +182,37 @@
}
}
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- int positionInAdapter = position - mMenuView.getHeaderViewsCount();
- if (positionInAdapter >= 0) {
- setUpdateSuspended(true);
- MenuItemImpl item = mAdapter.getItem(positionInAdapter).getMenuItem();
- if (item != null && item.isCheckable()) {
- mAdapter.setCheckedItem(item);
- }
- mMenu.performItemAction(item, this, 0);
- setUpdateSuspended(false);
- updateMenuView(false);
- }
- }
-
public void setCheckedItem(MenuItemImpl item) {
mAdapter.setCheckedItem(item);
}
public View inflateHeaderView(@LayoutRes int res) {
- View view = mLayoutInflater.inflate(res, mHeader, false);
+ View view = mLayoutInflater.inflate(res, mHeaderLayout, false);
addHeaderView(view);
return view;
}
public void addHeaderView(@NonNull View view) {
- mHeader.addView(view);
+ mHeaderLayout.addView(view);
// The padding on top should be cleared.
mMenuView.setPadding(0, 0, 0, mMenuView.getPaddingBottom());
}
public void removeHeaderView(@NonNull View view) {
- mHeader.removeView(view);
- if (mHeader.getChildCount() == 0) {
+ mHeaderLayout.removeView(view);
+ if (mHeaderLayout.getChildCount() == 0) {
mMenuView.setPadding(0, mPaddingTopDefault, 0, mMenuView.getPaddingBottom());
}
}
+ public int getHeaderCount() {
+ return mHeaderLayout.getChildCount();
+ }
+
+ public View getHeaderView(int index) {
+ return mHeaderLayout.getChildAt(index);
+ }
+
@Nullable
public ColorStateList getItemTintList() {
return mIconTintList;
@@ -262,13 +253,77 @@
}
}
- private class NavigationMenuAdapter extends BaseAdapter {
+ private abstract static class ViewHolder extends RecyclerView.ViewHolder {
+
+ public ViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ }
+
+ private static class NormalViewHolder extends ViewHolder {
+
+ public NormalViewHolder(LayoutInflater inflater, ViewGroup parent,
+ View.OnClickListener listener) {
+ super(inflater.inflate(R.layout.design_navigation_item, parent, false));
+ itemView.setOnClickListener(listener);
+ }
+
+ }
+
+ private static class SubheaderViewHolder extends ViewHolder {
+
+ public SubheaderViewHolder(LayoutInflater inflater, ViewGroup parent) {
+ super(inflater.inflate(R.layout.design_navigation_item_subheader, parent, false));
+ }
+
+ }
+
+ private static class SeparatorViewHolder extends ViewHolder {
+
+ public SeparatorViewHolder(LayoutInflater inflater, ViewGroup parent) {
+ super(inflater.inflate(R.layout.design_navigation_item_separator, parent, false));
+ }
+
+ }
+
+ private static class HeaderViewHolder extends ViewHolder {
+
+ public HeaderViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ }
+
+ /**
+ * Handles click events for the menu items. The items has to be {@link NavigationMenuItemView}.
+ */
+ private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ NavigationMenuItemView itemView = (NavigationMenuItemView) v;
+ setUpdateSuspended(true);
+ MenuItemImpl item = itemView.getItemData();
+ boolean result = mMenu.performItemAction(item, NavigationMenuPresenter.this, 0);
+ if (item != null && item.isCheckable() && result) {
+ mAdapter.setCheckedItem(item);
+ }
+ setUpdateSuspended(false);
+ updateMenuView(false);
+ }
+
+ };
+
+ private class NavigationMenuAdapter extends RecyclerView.Adapter<ViewHolder> {
private static final String STATE_CHECKED_ITEM = "android:menu:checked";
+ private static final String STATE_ACTION_VIEWS = "android:menu:action_views";
private static final int VIEW_TYPE_NORMAL = 0;
private static final int VIEW_TYPE_SUBHEADER = 1;
private static final int VIEW_TYPE_SEPARATOR = 2;
+ private static final int VIEW_TYPE_HEADER = 3;
private final ArrayList<NavigationMenuItem> mItems = new ArrayList<>();
private MenuItemImpl mCheckedItem;
@@ -280,48 +335,53 @@
}
@Override
- public int getCount() {
- return mItems.size();
- }
-
- @Override
- public NavigationMenuItem getItem(int position) {
- return mItems.get(position);
- }
-
- @Override
public long getItemId(int position) {
return position;
}
@Override
- public int getViewTypeCount() {
- return 3;
+ public int getItemCount() {
+ return mItems.size();
}
@Override
public int getItemViewType(int position) {
- NavigationMenuItem item = getItem(position);
- if (item.isSeparator()) {
+ NavigationMenuItem item = mItems.get(position);
+ if (item instanceof NavigationMenuSeparatorItem) {
return VIEW_TYPE_SEPARATOR;
- } else if (item.getMenuItem().hasSubMenu()) {
- return VIEW_TYPE_SUBHEADER;
- } else {
- return VIEW_TYPE_NORMAL;
+ } else if (item instanceof NavigationMenuHeaderItem) {
+ return VIEW_TYPE_HEADER;
+ } else if (item instanceof NavigationMenuTextItem) {
+ NavigationMenuTextItem textItem = (NavigationMenuTextItem) item;
+ if (textItem.getMenuItem().hasSubMenu()) {
+ return VIEW_TYPE_SUBHEADER;
+ } else {
+ return VIEW_TYPE_NORMAL;
+ }
}
+ throw new RuntimeException("Unknown item type.");
}
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- NavigationMenuItem item = getItem(position);
- int viewType = getItemViewType(position);
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_NORMAL:
- if (convertView == null) {
- convertView = mLayoutInflater.inflate(R.layout.design_navigation_item,
- parent, false);
- }
- NavigationMenuItemView itemView = (NavigationMenuItemView) convertView;
+ return new NormalViewHolder(mLayoutInflater, parent, mOnClickListener);
+ case VIEW_TYPE_SUBHEADER:
+ return new SubheaderViewHolder(mLayoutInflater, parent);
+ case VIEW_TYPE_SEPARATOR:
+ return new SeparatorViewHolder(mLayoutInflater, parent);
+ case VIEW_TYPE_HEADER:
+ return new HeaderViewHolder(mHeaderLayout);
+ }
+ return null;
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ switch (getItemViewType(position)) {
+ case VIEW_TYPE_NORMAL: {
+ NavigationMenuItemView itemView = (NavigationMenuItemView) holder.itemView;
itemView.setIconTintList(mIconTintList);
if (mTextAppearanceSet) {
itemView.setTextAppearance(itemView.getContext(), mTextAppearance);
@@ -331,42 +391,40 @@
}
itemView.setBackgroundDrawable(mItemBackground != null ?
mItemBackground.getConstantState().newDrawable() : null);
+ NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
itemView.initialize(item.getMenuItem(), 0);
break;
- case VIEW_TYPE_SUBHEADER:
- if (convertView == null) {
- convertView = mLayoutInflater.inflate(
- R.layout.design_navigation_item_subheader, parent, false);
- }
- TextView subHeader = (TextView) convertView;
+ }
+ case VIEW_TYPE_SUBHEADER: {
+ TextView subHeader = (TextView) holder.itemView;
+ NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
subHeader.setText(item.getMenuItem().getTitle());
break;
- case VIEW_TYPE_SEPARATOR:
- if (convertView == null) {
- convertView = mLayoutInflater.inflate(
- R.layout.design_navigation_item_separator, parent, false);
- }
- convertView.setPadding(0, item.getPaddingTop(), 0,
+ }
+ case VIEW_TYPE_SEPARATOR: {
+ NavigationMenuSeparatorItem item =
+ (NavigationMenuSeparatorItem) mItems.get(position);
+ holder.itemView.setPadding(0, item.getPaddingTop(), 0,
item.getPaddingBottom());
break;
+ }
+ case VIEW_TYPE_HEADER: {
+ break;
+ }
}
- return convertView;
+
}
@Override
- public boolean areAllItemsEnabled() {
- return false;
+ public void onViewRecycled(ViewHolder holder) {
+ if (holder instanceof NormalViewHolder) {
+ ((NavigationMenuItemView) holder.itemView).recycle();
+ }
}
- @Override
- public boolean isEnabled(int position) {
- return getItem(position).isEnabled();
- }
-
- @Override
- public void notifyDataSetChanged() {
+ public void update() {
prepareMenuItems();
- super.notifyDataSetChanged();
+ notifyDataSetChanged();
}
/**
@@ -379,6 +437,8 @@
}
mUpdateSuspended = true;
mItems.clear();
+ mItems.add(new NavigationMenuHeaderItem());
+
int currentGroupId = -1;
int currentGroupStart = 0;
boolean currentGroupHasIcon = false;
@@ -394,9 +454,9 @@
SubMenu subMenu = item.getSubMenu();
if (subMenu.hasVisibleItems()) {
if (i != 0) {
- mItems.add(NavigationMenuItem.separator(mPaddingSeparator, 0));
+ mItems.add(new NavigationMenuSeparatorItem(mPaddingSeparator, 0));
}
- mItems.add(NavigationMenuItem.of(item));
+ mItems.add(new NavigationMenuTextItem(item));
boolean subMenuHasIcon = false;
int subMenuStart = mItems.size();
for (int j = 0, size = subMenu.size(); j < size; j++) {
@@ -411,7 +471,7 @@
if (item.isChecked()) {
setCheckedItem(item);
}
- mItems.add(NavigationMenuItem.of(subMenuItem));
+ mItems.add(new NavigationMenuTextItem(subMenuItem));
}
}
if (subMenuHasIcon) {
@@ -425,7 +485,7 @@
currentGroupHasIcon = item.getIcon() != null;
if (i != 0) {
currentGroupStart++;
- mItems.add(NavigationMenuItem.separator(
+ mItems.add(new NavigationMenuSeparatorItem(
mPaddingSeparator, mPaddingSeparator));
}
} else if (!currentGroupHasIcon && item.getIcon() != null) {
@@ -435,7 +495,7 @@
if (currentGroupHasIcon && item.getIcon() == null) {
item.setIcon(android.R.color.transparent);
}
- mItems.add(NavigationMenuItem.of(item));
+ mItems.add(new NavigationMenuTextItem(item));
currentGroupId = groupId;
}
}
@@ -444,7 +504,8 @@
private void appendTransparentIconIfMissing(int startIndex, int endIndex) {
for (int i = startIndex; i < endIndex; i++) {
- MenuItem item = mItems.get(i).getMenuItem();
+ NavigationMenuTextItem textItem = (NavigationMenuTextItem) mItems.get(i);
+ MenuItem item = textItem.getMenuItem();
if (item.getIcon() == null) {
if (mTransparentIcon == null) {
mTransparentIcon = new ColorDrawable(android.R.color.transparent);
@@ -470,6 +531,20 @@
if (mCheckedItem != null) {
state.putInt(STATE_CHECKED_ITEM, mCheckedItem.getItemId());
}
+ // Store the states of the action views.
+ SparseArray<ParcelableSparseArray> actionViewStates = new SparseArray<>();
+ for (NavigationMenuItem navigationMenuItem : mItems) {
+ if (navigationMenuItem instanceof NavigationMenuTextItem) {
+ MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem();
+ View actionView = item != null ? item.getActionView() : null;
+ if (actionView != null) {
+ ParcelableSparseArray container = new ParcelableSparseArray();
+ actionView.saveHierarchyState(container);
+ actionViewStates.put(item.getItemId(), container);
+ }
+ }
+ }
+ state.putSparseParcelableArray(STATE_ACTION_VIEWS, actionViewStates);
return state;
}
@@ -478,15 +553,29 @@
if (checkedItem != 0) {
mUpdateSuspended = true;
for (NavigationMenuItem item : mItems) {
- MenuItemImpl menuItem = item.getMenuItem();
- if (menuItem != null && menuItem.getItemId() == checkedItem) {
- setCheckedItem(menuItem);
- break;
+ if (item instanceof NavigationMenuTextItem) {
+ MenuItemImpl menuItem = ((NavigationMenuTextItem) item).getMenuItem();
+ if (menuItem != null && menuItem.getItemId() == checkedItem) {
+ setCheckedItem(menuItem);
+ break;
+ }
}
}
mUpdateSuspended = false;
prepareMenuItems();
}
+ // Restore the states of the action views.
+ SparseArray<ParcelableSparseArray> actionViewStates = state
+ .getSparseParcelableArray(STATE_ACTION_VIEWS);
+ for (NavigationMenuItem navigationMenuItem : mItems) {
+ if (navigationMenuItem instanceof NavigationMenuTextItem) {
+ MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem();
+ View actionView = item != null ? item.getActionView() : null;
+ if (actionView != null) {
+ actionView.restoreHierarchyState(actionViewStates.get(item.getItemId()));
+ }
+ }
+ }
}
public void setUpdateSuspended(boolean updateSuspended) {
@@ -496,37 +585,42 @@
}
/**
- * Wraps {@link MenuItemImpl}. This allows separators to be counted as items in list.
+ * Unified data model for all sorts of navigation menu items.
*/
- private static class NavigationMenuItem {
+ private interface NavigationMenuItem {
+ }
- /** The item; null for separators */
+ /**
+ * Normal or subheader items.
+ */
+ private static class NavigationMenuTextItem implements NavigationMenuItem {
+
private final MenuItemImpl mMenuItem;
- /** Padding top; used only for separators */
+ private NavigationMenuTextItem(MenuItemImpl item) {
+ mMenuItem = item;
+ }
+
+ public MenuItemImpl getMenuItem() {
+ return mMenuItem;
+ }
+
+ }
+
+ /**
+ * Separator items.
+ */
+ private static class NavigationMenuSeparatorItem implements NavigationMenuItem {
+
private final int mPaddingTop;
- /** Padding bottom; used only for separators */
private final int mPaddingBottom;
- private NavigationMenuItem(MenuItemImpl item, int paddingTop, int paddingBottom) {
- mMenuItem = item;
+ public NavigationMenuSeparatorItem(int paddingTop, int paddingBottom) {
mPaddingTop = paddingTop;
mPaddingBottom = paddingBottom;
}
- public static NavigationMenuItem of(MenuItemImpl item) {
- return new NavigationMenuItem(item, 0, 0);
- }
-
- public static NavigationMenuItem separator(int paddingTop, int paddingBottom) {
- return new NavigationMenuItem(null, paddingTop, paddingBottom);
- }
-
- public boolean isSeparator() {
- return mMenuItem == null;
- }
-
public int getPaddingTop() {
return mPaddingTop;
}
@@ -535,15 +629,13 @@
return mPaddingBottom;
}
- public MenuItemImpl getMenuItem() {
- return mMenuItem;
- }
+ }
- public boolean isEnabled() {
- // Separators and subheaders never respond to click
- return mMenuItem != null && !mMenuItem.hasSubMenu() && mMenuItem.isEnabled();
- }
-
+ /**
+ * Header (not subheader) items.
+ */
+ private static class NavigationMenuHeaderItem implements NavigationMenuItem {
+ // The actual content is hold by NavigationMenuPresenter#mHeaderLayout.
}
}
diff --git a/design/src/android/support/design/internal/NavigationMenuView.java b/design/src/android/support/design/internal/NavigationMenuView.java
index 054b800..c7c90c3 100644
--- a/design/src/android/support/design/internal/NavigationMenuView.java
+++ b/design/src/android/support/design/internal/NavigationMenuView.java
@@ -17,15 +17,16 @@
package android.support.design.internal;
import android.content.Context;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuView;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuView;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
-import android.widget.ListView;
/**
* @hide
*/
-public class NavigationMenuView extends ListView implements MenuView {
+public class NavigationMenuView extends RecyclerView implements MenuView {
public NavigationMenuView(Context context) {
this(context, null);
@@ -37,6 +38,7 @@
public NavigationMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
}
@Override
diff --git a/design/src/android/support/design/internal/NavigationSubMenu.java b/design/src/android/support/design/internal/NavigationSubMenu.java
index ae59412..f17536f 100644
--- a/design/src/android/support/design/internal/NavigationSubMenu.java
+++ b/design/src/android/support/design/internal/NavigationSubMenu.java
@@ -17,10 +17,9 @@
package android.support.design.internal;
import android.content.Context;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.view.MenuItem;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.SubMenuBuilder;
/**
* This is a {@link SubMenuBuilder} that it notifies the parent {@link NavigationMenu} of its menu
@@ -35,35 +34,9 @@
}
@Override
- public MenuItem add(CharSequence title) {
- MenuItem item = super.add(title);
- notifyParent();
- return item;
- }
-
- @Override
- public MenuItem add(int titleRes) {
- MenuItem item = super.add(titleRes);
- notifyParent();
- return item;
- }
-
- @Override
- public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
- MenuItem item = super.add(groupId, itemId, order, title);
- notifyParent();
- return item;
- }
-
- @Override
- public MenuItem add(int groupId, int itemId, int order, int titleRes) {
- MenuItem item = super.add(groupId, itemId, order, titleRes);
- notifyParent();
- return item;
- }
-
- private void notifyParent() {
- ((MenuBuilder) getParentMenu()).onItemsChanged(true);
+ public void onItemsChanged(boolean structureChanged) {
+ super.onItemsChanged(structureChanged);
+ ((MenuBuilder) getParentMenu()).onItemsChanged(structureChanged);
}
}
diff --git a/design/src/android/support/design/internal/ParcelableSparseArray.java b/design/src/android/support/design/internal/ParcelableSparseArray.java
new file mode 100644
index 0000000..588950b
--- /dev/null
+++ b/design/src/android/support/design/internal/ParcelableSparseArray.java
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package android.support.design.internal;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
+import android.util.SparseArray;
+
+/**
+ * @hide
+ */
+public class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable {
+
+ public ParcelableSparseArray() {
+ super();
+ }
+
+ public ParcelableSparseArray(Parcel source, ClassLoader loader) {
+ super();
+ int size = source.readInt();
+ int[] keys = new int[size];
+ source.readIntArray(keys);
+ Parcelable[] values = source.readParcelableArray(loader);
+ for (int i = 0; i < size; ++i) {
+ put(keys[i], values[i]);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ int size = size();
+ int[] keys = new int[size];
+ Parcelable[] values = new Parcelable[size];
+ for (int i = 0; i < size; ++i) {
+ keys[i] = keyAt(i);
+ values[i] = valueAt(i);
+ }
+ parcel.writeInt(size);
+ parcel.writeIntArray(keys);
+ parcel.writeParcelableArray(values, flags);
+ }
+
+ public static final Parcelable.Creator<ParcelableSparseArray> CREATOR =
+ ParcelableCompat
+ .newCreator(new ParcelableCompatCreatorCallbacks<ParcelableSparseArray>() {
+ @Override
+ public ParcelableSparseArray createFromParcel(Parcel source,
+ ClassLoader loader) {
+ return new ParcelableSparseArray(source, loader);
+ }
+
+ @Override
+ public ParcelableSparseArray[] newArray(int size) {
+ return new ParcelableSparseArray[size];
+ }
+ });
+}
diff --git a/design/src/android/support/design/widget/AppBarLayout.java b/design/src/android/support/design/widget/AppBarLayout.java
index 53e96ba..eb7a962 100644
--- a/design/src/android/support/design/widget/AppBarLayout.java
+++ b/design/src/android/support/design/widget/AppBarLayout.java
@@ -21,15 +21,15 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.design.R;
-import android.support.v4.view.MotionEventCompat;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.WindowInsetsCompat;
-import android.support.v4.widget.ScrollerCompat;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.LinearLayout;
@@ -142,6 +142,8 @@
super(context, attrs);
setOrientation(VERTICAL);
+ ThemeUtils.checkAppCompatTheme(context);
+
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
0, R.style.Widget_Design_AppBarLayout);
mTargetElevation = a.getDimensionPixelSize(R.styleable.AppBarLayout_elevation, 0);
@@ -194,13 +196,15 @@
}
@Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ invalidateScrollRanges();
+ }
+
+ @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
-
- // Invalidate the scroll ranges
- mTotalScrollRange = INVALID_SCROLL_RANGE;
- mDownPreScrollRange = INVALID_SCROLL_RANGE;
- mDownPreScrollRange = INVALID_SCROLL_RANGE;
+ invalidateScrollRanges();
mHaveChildWithInterpolator = false;
for (int i = 0, z = getChildCount(); i < z; i++) {
@@ -215,6 +219,13 @@
}
}
+ private void invalidateScrollRanges() {
+ // Invalidate the scroll ranges
+ mTotalScrollRange = INVALID_SCROLL_RANGE;
+ mDownPreScrollRange = INVALID_SCROLL_RANGE;
+ mDownScrollRange = INVALID_SCROLL_RANGE;
+ }
+
@Override
public void setOrientation(int orientation) {
if (orientation != VERTICAL) {
@@ -283,7 +294,7 @@
return new LayoutParams(p);
}
- final boolean hasChildWithInterpolator() {
+ private boolean hasChildWithInterpolator() {
return mHaveChildWithInterpolator;
}
@@ -301,9 +312,7 @@
for (int i = 0, z = getChildCount(); i < z; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- final int childHeight = ViewCompat.isLaidOut(child)
- ? child.getHeight()
- : child.getMeasuredHeight();
+ final int childHeight = child.getMeasuredHeight();
final int flags = lp.mScrollFlags;
if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
@@ -323,25 +332,24 @@
break;
}
}
- final int top = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
- return mTotalScrollRange = (range - top);
+ return mTotalScrollRange = Math.max(0, range - getTopInset());
}
- final boolean hasScrollableChildren() {
+ private boolean hasScrollableChildren() {
return getTotalScrollRange() != 0;
}
/**
* Return the scroll range when scrolling up from a nested pre-scroll.
*/
- final int getUpNestedPreScrollRange() {
+ private int getUpNestedPreScrollRange() {
return getTotalScrollRange();
}
/**
* Return the scroll range when scrolling down from a nested pre-scroll.
*/
- final int getDownNestedPreScrollRange() {
+ private int getDownNestedPreScrollRange() {
if (mDownPreScrollRange != INVALID_SCROLL_RANGE) {
// If we already have a valid value, return it
return mDownPreScrollRange;
@@ -351,9 +359,7 @@
for (int i = getChildCount() - 1; i >= 0; i--) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- final int childHeight = ViewCompat.isLaidOut(child)
- ? child.getHeight()
- : child.getMeasuredHeight();
+ final int childHeight = child.getMeasuredHeight();
final int flags = lp.mScrollFlags;
if ((flags & LayoutParams.FLAG_QUICK_RETURN) == LayoutParams.FLAG_QUICK_RETURN) {
@@ -363,6 +369,9 @@
if ((flags & LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED) != 0) {
// If they're set to enter collapsed, use the minimum height
range += ViewCompat.getMinimumHeight(child);
+ } else if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
+ // Only enter by the amount of the collapsed height
+ range += childHeight - ViewCompat.getMinimumHeight(child);
} else {
// Else use the full height
range += childHeight;
@@ -373,13 +382,13 @@
break;
}
}
- return mDownPreScrollRange = range;
+ return mDownPreScrollRange = Math.max(0, range - getTopInset());
}
/**
* Return the scroll range when scrolling down from a nested scroll.
*/
- final int getDownNestedScrollRange() {
+ private int getDownNestedScrollRange() {
if (mDownScrollRange != INVALID_SCROLL_RANGE) {
// If we already have a valid value, return it
return mDownScrollRange;
@@ -389,9 +398,7 @@
for (int i = 0, z = getChildCount(); i < z; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- int childHeight = ViewCompat.isLaidOut(child)
- ? child.getHeight()
- : child.getMeasuredHeight();
+ int childHeight = child.getMeasuredHeight();
childHeight += lp.topMargin + lp.bottomMargin;
final int flags = lp.mScrollFlags;
@@ -402,9 +409,10 @@
if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
// For a collapsing exit scroll, we to take the collapsed height into account.
- // We also return the range straight away since later views can't scroll
+ // We also break the range straight away since later views can't scroll
// beneath us
- return range - ViewCompat.getMinimumHeight(child);
+ range -= ViewCompat.getMinimumHeight(child) + getTopInset();
+ break;
}
} else {
// As soon as a view doesn't have the scroll flag, we end the range calculation.
@@ -412,7 +420,7 @@
break;
}
}
- return mDownScrollRange = range;
+ return mDownScrollRange = Math.max(0, range);
}
final int getMinimumHeightForVisibleOverlappingContent() {
@@ -454,14 +462,18 @@
return mTargetElevation;
}
- int getPendingAction() {
+ private int getPendingAction() {
return mPendingAction;
}
- void resetPendingAction() {
+ private void resetPendingAction() {
mPendingAction = PENDING_ACTION_NONE;
}
+ private int getTopInset() {
+ return mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
+ }
+
private void setWindowInsets(WindowInsetsCompat insets) {
// Invalidate the total scroll range...
mTotalScrollRange = INVALID_SCROLL_RANGE;
@@ -484,7 +496,8 @@
SCROLL_FLAG_SCROLL,
SCROLL_FLAG_EXIT_UNTIL_COLLAPSED,
SCROLL_FLAG_ENTER_ALWAYS,
- SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED
+ SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED,
+ SCROLL_FLAG_SNAP
})
@Retention(RetentionPolicy.SOURCE)
public @interface ScrollFlags {}
@@ -524,9 +537,18 @@
public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 0x8;
/**
- * Internal flag which allows quick checking of 'quick return'
+ * Upon a scroll ending, if the view is only partially visible then it will be snapped
+ * and scrolled to it's closest edge. For example, if the view only has it's bottom 25%
+ * displayed, it will be scrolled off screen completely. Conversely, if it's bottom 75%
+ * is visible then it will be scrolled fully into view.
+ */
+ public static final int SCROLL_FLAG_SNAP = 0x10;
+
+ /**
+ * Internal flags which allows quick checking features
*/
static final int FLAG_QUICK_RETURN = SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS;
+ static final int FLAG_SNAP = SCROLL_FLAG_SCROLL | SCROLL_FLAG_SNAP;
int mScrollFlags = SCROLL_FLAG_SCROLL;
Interpolator mScrollInterpolator;
@@ -574,8 +596,8 @@
* Set the scrolling flags.
*
* @param flags bitwise int of {@link #SCROLL_FLAG_SCROLL},
- * {@link #SCROLL_FLAG_EXIT_UNTIL_COLLAPSED}, {@link #SCROLL_FLAG_ENTER_ALWAYS}
- * and {@link #SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED}.
+ * {@link #SCROLL_FLAG_EXIT_UNTIL_COLLAPSED}, {@link #SCROLL_FLAG_ENTER_ALWAYS},
+ * {@link #SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED} and {@link #SCROLL_FLAG_SNAP }.
*
* @see #getScrollFlags()
*
@@ -626,15 +648,30 @@
* The default {@link Behavior} for {@link AppBarLayout}. Implements the necessary nested
* scroll handling with offsetting.
*/
- public static class Behavior extends ViewOffsetBehavior<AppBarLayout> {
- private static final int INVALID_POINTER = -1;
+ public static class Behavior extends HeaderBehavior<AppBarLayout> {
+ private static final int ANIMATE_OFFSET_DIPS_PER_SECOND = 300;
private static final int INVALID_POSITION = -1;
+ /**
+ * Callback to allow control over any {@link AppBarLayout} dragging.
+ */
+ public static abstract class DragCallback {
+ /**
+ * Allows control over whether the given {@link AppBarLayout} can be dragged or not.
+ *
+ * <p>Dragging is defined as a direct touch on the AppBarLayout with movement. This
+ * call does not affect any nested scrolling.</p>
+ *
+ * @return true if we are in a position to scroll the AppBarLayout via a drag, false
+ * if not.
+ */
+ public abstract boolean canDrag(@NonNull AppBarLayout appBarLayout);
+ }
+
private int mOffsetDelta;
private boolean mSkipNestedPreScroll;
- private Runnable mFlingRunnable;
- private ScrollerCompat mScroller;
+ private boolean mWasNestedFlung;
private ValueAnimatorCompat mAnimator;
@@ -642,12 +679,8 @@
private boolean mOffsetToChildIndexOnLayoutIsMinHeight;
private float mOffsetToChildIndexOnLayoutPerc;
- private boolean mIsBeingDragged;
- private int mActivePointerId = INVALID_POINTER;
- private int mLastMotionY;
- private int mTouchSlop = -1;
-
private WeakReference<View> mLastNestedScrollingChildRef;
+ private DragCallback mOnDragCallback;
public Behavior() {}
@@ -711,173 +744,85 @@
}
@Override
- public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
+ public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl,
View target) {
- // Reset the skip flag
+ if (!mWasNestedFlung) {
+ // If we haven't been flung then let's see if the current view has been set to snap
+ snapToChildIfNeeded(coordinatorLayout, abl);
+ }
+
+ // Reset the flags
mSkipNestedPreScroll = false;
+ mWasNestedFlung = false;
// Keep a reference to the previous nested scrolling child
mLastNestedScrollingChildRef = new WeakReference<>(target);
}
@Override
- public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child,
- MotionEvent ev) {
- if (mTouchSlop < 0) {
- mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
- }
-
- final int action = ev.getAction();
-
- // Shortcut since we're being dragged
- if (action == MotionEvent.ACTION_MOVE && mIsBeingDragged) {
- return true;
- }
-
- switch (MotionEventCompat.getActionMasked(ev)) {
- case MotionEvent.ACTION_MOVE: {
- final int activePointerId = mActivePointerId;
- if (activePointerId == INVALID_POINTER) {
- // If we don't have a valid id, the touch down wasn't on content.
- break;
- }
- final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
- if (pointerIndex == -1) {
- break;
- }
-
- final int y = (int) MotionEventCompat.getY(ev, pointerIndex);
- final int yDiff = Math.abs(y - mLastMotionY);
- if (yDiff > mTouchSlop) {
- mIsBeingDragged = true;
- mLastMotionY = y;
- }
- break;
- }
-
- case MotionEvent.ACTION_DOWN: {
- mIsBeingDragged = false;
- final int x = (int) ev.getX();
- final int y = (int) ev.getY();
- if (parent.isPointInChildBounds(child, x, y) && canDragAppBarLayout()) {
- mLastMotionY = y;
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- }
- break;
- }
-
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- mIsBeingDragged = false;
- mActivePointerId = INVALID_POINTER;
- break;
- }
-
- return mIsBeingDragged;
- }
-
- @Override
- public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
- if (mTouchSlop < 0) {
- mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
- }
-
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
- switch (MotionEventCompat.getActionMasked(ev)) {
- case MotionEvent.ACTION_DOWN:
- if (parent.isPointInChildBounds(child, x, y) && canDragAppBarLayout()) {
- mLastMotionY = y;
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- } else {
- return false;
- }
- break;
- case MotionEvent.ACTION_MOVE:
- final int activePointerIndex = MotionEventCompat.findPointerIndex(ev,
- mActivePointerId);
- if (activePointerIndex == -1) {
- return false;
- }
-
- y = (int) MotionEventCompat.getY(ev, activePointerIndex);
-
- int dy = mLastMotionY - y;
- if (!mIsBeingDragged && Math.abs(dy) > mTouchSlop) {
- mIsBeingDragged = true;
- if (dy > 0) {
- dy -= mTouchSlop;
- } else {
- dy += mTouchSlop;
- }
- }
-
- if (mIsBeingDragged) {
- mLastMotionY = y;
- // We're being dragged so scroll the ABL
- scroll(parent, child, dy, -child.getDownNestedScrollRange(), 0);
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mIsBeingDragged = false;
- mActivePointerId = INVALID_POINTER;
- break;
- }
-
- return true;
- }
-
- @Override
public boolean onNestedFling(final CoordinatorLayout coordinatorLayout,
final AppBarLayout child, View target, float velocityX, float velocityY,
boolean consumed) {
+ boolean flung = false;
+
if (!consumed) {
// It has been consumed so let's fling ourselves
- return fling(coordinatorLayout, child, -child.getTotalScrollRange(), 0, -velocityY);
+ flung = fling(coordinatorLayout, child, -child.getTotalScrollRange(),
+ 0, -velocityY);
} else {
// If we're scrolling up and the child also consumed the fling. We'll fake scroll
// upto our 'collapsed' offset
- int targetScroll;
if (velocityY < 0) {
// We're scrolling down
- targetScroll = -child.getTotalScrollRange()
+ final int targetScroll = -child.getTotalScrollRange()
+ child.getDownNestedPreScrollRange();
-
- if (getTopBottomOffsetForScrollingSibling() > targetScroll) {
- // If we're currently expanded more than the target scroll, we'll return false
- // now. This is so that we don't 'scroll' the wrong way.
- return false;
+ if (getTopBottomOffsetForScrollingSibling() < targetScroll) {
+ // If we're currently not expanded more than the target scroll, we'll
+ // animate a fling
+ animateOffsetTo(coordinatorLayout, child, targetScroll);
+ flung = true;
}
} else {
// We're scrolling up
- targetScroll = -child.getUpNestedPreScrollRange();
-
- if (getTopBottomOffsetForScrollingSibling() < targetScroll) {
- // If we're currently expanded less than the target scroll, we'll return
- // false now. This is so that we don't 'scroll' the wrong way.
- return false;
+ final int targetScroll = -child.getUpNestedPreScrollRange();
+ if (getTopBottomOffsetForScrollingSibling() > targetScroll) {
+ // If we're currently not expanded less than the target scroll, we'll
+ // animate a fling
+ animateOffsetTo(coordinatorLayout, child, targetScroll);
+ flung = true;
}
}
-
- if (getTopBottomOffsetForScrollingSibling() != targetScroll) {
- animateOffsetTo(coordinatorLayout, child, targetScroll);
- return true;
- }
}
- return false;
+ mWasNestedFlung = flung;
+ return flung;
+ }
+
+ /**
+ * Set a callback to control any {@link AppBarLayout} dragging.
+ *
+ * @param callback the callback to use, or {@code null} to use the default behavior.
+ */
+ public void setDragCallback(@Nullable DragCallback callback) {
+ mOnDragCallback = callback;
}
private void animateOffsetTo(final CoordinatorLayout coordinatorLayout,
- final AppBarLayout child, int offset) {
+ final AppBarLayout child, final int offset) {
+ final int currentOffset = getTopBottomOffsetForScrollingSibling();
+ if (currentOffset == offset) {
+ if (mAnimator != null && mAnimator.isRunning()) {
+ mAnimator.cancel();
+ }
+ return;
+ }
+
if (mAnimator == null) {
mAnimator = ViewUtils.createAnimator();
mAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
mAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimatorCompat animator) {
- setAppBarTopBottomOffset(coordinatorLayout, child,
+ setHeaderTopBottomOffset(coordinatorLayout, child,
animator.getAnimatedIntValue());
}
});
@@ -885,52 +830,45 @@
mAnimator.cancel();
}
- mAnimator.setIntValues(getTopBottomOffsetForScrollingSibling(), offset);
+ // Set the duration based on the amount of dips we're travelling in
+ final float distanceDp = Math.abs(currentOffset - offset) /
+ coordinatorLayout.getResources().getDisplayMetrics().density;
+ mAnimator.setDuration(Math.round(distanceDp * 1000 / ANIMATE_OFFSET_DIPS_PER_SECOND));
+
+ mAnimator.setIntValues(currentOffset, offset);
mAnimator.start();
}
- private boolean fling(CoordinatorLayout coordinatorLayout, AppBarLayout layout, int minOffset,
- int maxOffset, float velocityY) {
- if (mFlingRunnable != null) {
- layout.removeCallbacks(mFlingRunnable);
+ private View getChildOnOffset(AppBarLayout abl, final int offset) {
+ for (int i = 0, count = abl.getChildCount(); i < count; i++) {
+ View child = abl.getChildAt(i);
+ if (child.getTop() <= -offset && child.getBottom() >= -offset) {
+ return child;
+ }
}
-
- if (mScroller == null) {
- mScroller = ScrollerCompat.create(layout.getContext());
- }
-
- mScroller.fling(
- 0, getTopBottomOffsetForScrollingSibling(), // curr
- 0, Math.round(velocityY), // velocity.
- 0, 0, // x
- minOffset, maxOffset); // y
-
- if (mScroller.computeScrollOffset()) {
- mFlingRunnable = new FlingRunnable(coordinatorLayout, layout);
- ViewCompat.postOnAnimation(layout, mFlingRunnable);
- return true;
- } else {
- mFlingRunnable = null;
- return false;
- }
+ return null;
}
- private class FlingRunnable implements Runnable {
- private final CoordinatorLayout mParent;
- private final AppBarLayout mLayout;
+ private void snapToChildIfNeeded(CoordinatorLayout coordinatorLayout, AppBarLayout abl) {
+ final int offset = getTopBottomOffsetForScrollingSibling();
+ final View offsetChild = getChildOnOffset(abl, offset);
+ if (offsetChild != null) {
+ final LayoutParams lp = (LayoutParams) offsetChild.getLayoutParams();
+ if ((lp.getScrollFlags() & LayoutParams.FLAG_SNAP) == LayoutParams.FLAG_SNAP) {
+ // We're set the snap, so animate the offset to the nearest edge
+ int childTop = -offsetChild.getTop();
+ int childBottom = -offsetChild.getBottom();
- FlingRunnable(CoordinatorLayout parent, AppBarLayout layout) {
- mParent = parent;
- mLayout = layout;
- }
+ // If the view is set only exit until it is collapsed, we'll abide by that
+ if ((lp.getScrollFlags() & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED)
+ == LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) {
+ childBottom += ViewCompat.getMinimumHeight(offsetChild);
+ }
- @Override
- public void run() {
- if (mLayout != null && mScroller != null && mScroller.computeScrollOffset()) {
- setAppBarTopBottomOffset(mParent, mLayout, mScroller.getCurrY());
-
- // Post ourselves so that we run on the next animation
- ViewCompat.postOnAnimation(mLayout, this);
+ final int newOffset = offset < (childBottom + childTop) / 2
+ ? childBottom : childTop;
+ animateOffsetTo(coordinatorLayout, abl,
+ MathUtils.constrain(newOffset, -abl.getTotalScrollRange(), 0));
}
}
}
@@ -948,17 +886,15 @@
if (animate) {
animateOffsetTo(parent, abl, offset);
} else {
- setAppBarTopBottomOffset(parent, abl, offset);
+ setHeaderTopBottomOffset(parent, abl, offset);
}
} else if ((pendingAction & PENDING_ACTION_EXPANDED) != 0) {
if (animate) {
animateOffsetTo(parent, abl, 0);
} else {
- setAppBarTopBottomOffset(parent, abl, 0);
+ setHeaderTopBottomOffset(parent, abl, 0);
}
}
- // Finally reset the pending state
- abl.resetPendingAction();
} else if (mOffsetToChildIndexOnLayout >= 0) {
View child = abl.getChildAt(mOffsetToChildIndexOnLayout);
int offset = -child.getBottom();
@@ -968,45 +904,70 @@
offset += Math.round(child.getHeight() * mOffsetToChildIndexOnLayoutPerc);
}
setTopAndBottomOffset(offset);
- mOffsetToChildIndexOnLayout = INVALID_POSITION;
}
+ // Finally reset any pending states
+ abl.resetPendingAction();
+ mOffsetToChildIndexOnLayout = INVALID_POSITION;
+
+ // We may have changed size, so let's constrain the top and bottom offset correctly,
+ // just in case we're out of the bounds
+ setTopAndBottomOffset(
+ MathUtils.constrain(getTopAndBottomOffset(), -abl.getTotalScrollRange(), 0));
+
// Make sure we update the elevation
dispatchOffsetUpdates(abl);
return handled;
}
- private int scroll(CoordinatorLayout coordinatorLayout, AppBarLayout appBarLayout,
- int dy, int minOffset, int maxOffset) {
- return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout,
- getTopBottomOffsetForScrollingSibling() - dy, minOffset, maxOffset);
- }
-
- private boolean canDragAppBarLayout() {
- if (mLastNestedScrollingChildRef != null) {
- final View view = mLastNestedScrollingChildRef.get();
- return view != null && view.isShown() && !ViewCompat.canScrollVertically(view, -1);
+ @Override
+ boolean canDragView(AppBarLayout view) {
+ if (mOnDragCallback != null) {
+ // If there is a drag callback set, it's in control
+ return mOnDragCallback.canDrag(view);
}
- return false;
+
+ // Else we'll use the default behaviour of seeing if it can scroll down
+ if (mLastNestedScrollingChildRef != null) {
+ // If we have a reference to a scrolling view, check it
+ final View scrollingView = mLastNestedScrollingChildRef.get();
+ return scrollingView != null && scrollingView.isShown()
+ && !ViewCompat.canScrollVertically(scrollingView, -1);
+ } else {
+ // Otherwise we assume that the scrolling view hasn't been scrolled and can drag.
+ return true;
+ }
}
- final int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
- AppBarLayout appBarLayout, int newOffset) {
- return setAppBarTopBottomOffset(coordinatorLayout, appBarLayout, newOffset,
- Integer.MIN_VALUE, Integer.MAX_VALUE);
+ @Override
+ void onFlingFinished(CoordinatorLayout parent, AppBarLayout layout) {
+ // At the end of a manual fling, check to see if we need to snap to the edge-child
+ snapToChildIfNeeded(parent, layout);
}
- final int setAppBarTopBottomOffset(CoordinatorLayout coordinatorLayout,
- AppBarLayout appBarLayout, int newOffset, int minOffset, int maxOffset) {
+ @Override
+ int getMaxDragOffset(AppBarLayout view) {
+ return -view.getDownNestedScrollRange();
+ }
+
+ @Override
+ int getScrollRangeForDragFling(AppBarLayout view) {
+ return view.getTotalScrollRange();
+ }
+
+ @Override
+ int setHeaderTopBottomOffset(CoordinatorLayout coordinatorLayout,
+ AppBarLayout header, int newOffset, int minOffset, int maxOffset) {
final int curOffset = getTopBottomOffsetForScrollingSibling();
int consumed = 0;
- if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
+ if (minOffset != 0 && curOffset >= minOffset
+ && curOffset <= maxOffset) {
// If we have some scrolling range, and we're currently within the min and max
// offsets, calculate a new offset
newOffset = MathUtils.constrain(newOffset, minOffset, maxOffset);
-
+ AppBarLayout appBarLayout = (AppBarLayout) header;
if (curOffset != newOffset) {
final int interpolatedOffset = appBarLayout.hasChildWithInterpolator()
? interpolateOffset(appBarLayout, newOffset)
@@ -1072,6 +1033,10 @@
}
}
+ if (ViewCompat.getFitsSystemWindows(child)) {
+ childScrollableHeight -= layout.getTopInset();
+ }
+
if (childScrollableHeight > 0) {
final int offsetForView = absOffset - child.getTop();
final int interpolatedDiff = Math.round(childScrollableHeight *
@@ -1091,7 +1056,8 @@
return offset;
}
- final int getTopBottomOffsetForScrollingSibling() {
+ @Override
+ int getTopBottomOffsetForScrollingSibling() {
return getTopAndBottomOffset() + mOffsetDelta;
}
@@ -1134,12 +1100,12 @@
}
}
- protected static class SavedState extends View.BaseSavedState {
+ protected static class SavedState extends BaseSavedState {
int firstVisibleChildIndex;
float firstVisibileChildPercentageShown;
boolean firstVisibileChildAtMinimumHeight;
- public SavedState(Parcel source) {
+ public SavedState(Parcel source, ClassLoader loader) {
super(source);
firstVisibleChildIndex = source.readInt();
firstVisibileChildPercentageShown = source.readFloat();
@@ -1159,17 +1125,17 @@
}
public static final Parcelable.Creator<SavedState> CREATOR =
- new Parcelable.Creator<SavedState>() {
+ ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
@Override
- public SavedState createFromParcel(Parcel source) {
- return new SavedState(source);
+ public SavedState createFromParcel(Parcel source, ClassLoader loader) {
+ return new SavedState(source, loader);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
- };
+ });
}
}
@@ -1177,7 +1143,7 @@
* Behavior which should be used by {@link View}s which can scroll vertically and support
* nested scrolling to automatically scroll any {@link AppBarLayout} siblings.
*/
- public static class ScrollingViewBehavior extends ViewOffsetBehavior<View> {
+ public static class ScrollingViewBehavior extends HeaderScrollingViewBehavior {
private int mOverlayTop;
public ScrollingViewBehavior() {}
@@ -1199,78 +1165,64 @@
}
@Override
- public boolean onMeasureChild(CoordinatorLayout parent, View child,
- int parentWidthMeasureSpec, int widthUsed,
- int parentHeightMeasureSpec, int heightUsed) {
- final int childLpHeight = child.getLayoutParams().height;
- if (childLpHeight == LayoutParams.MATCH_PARENT
- || childLpHeight == LayoutParams.WRAP_CONTENT) {
- // If the child's height is set to match_parent/wrap_content then measure it
- // with the maximum visible height
+ public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
+ // First lay out the child as normal
+ super.onLayoutChild(parent, child, layoutDirection);
- final List<View> dependencies = parent.getDependencies(child);
- if (dependencies.isEmpty()) {
- // If we don't have any dependencies, return false
- return false;
- }
-
- final AppBarLayout appBar = findFirstAppBarLayout(dependencies);
- if (appBar != null && ViewCompat.isLaidOut(appBar)) {
- if (ViewCompat.getFitsSystemWindows(appBar)) {
- // If the AppBarLayout is fitting system windows then we need to also,
- // otherwise we'll get CoL's compatible layout functionality
- ViewCompat.setFitsSystemWindows(child, true);
- }
-
- int availableHeight = MeasureSpec.getSize(parentHeightMeasureSpec);
- if (availableHeight == 0) {
- // If the measure spec doesn't specify a size, use the current height
- availableHeight = parent.getHeight();
- }
- final int height = availableHeight - appBar.getMeasuredHeight()
- + appBar.getTotalScrollRange();
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
- childLpHeight == LayoutParams.MATCH_PARENT
- ? MeasureSpec.EXACTLY
- : MeasureSpec.AT_MOST);
-
- // Now measure the scrolling child with the correct height
- parent.onMeasureChild(child, parentWidthMeasureSpec,
- widthUsed, heightMeasureSpec, heightUsed);
-
- return true;
+ // Now offset us correctly to be in the correct position. This is important for things
+ // like activity transitions which rely on accurate positioning after the first layout.
+ final List<View> dependencies = parent.getDependencies(child);
+ for (int i = 0, z = dependencies.size(); i < z; i++) {
+ if (updateOffset(parent, child, dependencies.get(i))) {
+ // If we updated the offset, break out of the loop now
+ break;
}
}
- return false;
+ return true;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
View dependency) {
+ updateOffset(parent, child, dependency);
+ return false;
+ }
+
+ private boolean updateOffset(CoordinatorLayout parent, View child, View dependency) {
final CoordinatorLayout.Behavior behavior =
((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();
if (behavior instanceof Behavior) {
// Offset the child so that it is below the app-bar (with any overlap)
-
- final int appBarOffset = ((Behavior) behavior)
- .getTopBottomOffsetForScrollingSibling();
- final int expandedMax = dependency.getHeight() - mOverlayTop;
- final int collapsedMin = parent.getHeight() - child.getHeight();
-
- if (mOverlayTop != 0 && dependency instanceof AppBarLayout) {
- // If we have an overlap top, and the dependency is an AppBarLayout, we control
- // the offset ourselves based on the appbar's scroll progress. This is so that
- // the scroll happens sequentially rather than linearly
- final int scrollRange = ((AppBarLayout) dependency).getTotalScrollRange();
- setTopAndBottomOffset(AnimationUtils.lerp(expandedMax, collapsedMin,
- Math.abs(appBarOffset) / (float) scrollRange));
- } else {
- setTopAndBottomOffset(dependency.getHeight() - mOverlayTop + appBarOffset);
- }
+ final int offset = ((Behavior) behavior).getTopBottomOffsetForScrollingSibling();
+ setTopAndBottomOffset(dependency.getHeight() + offset
+ - getOverlapForOffset(dependency, offset));
+ return true;
}
return false;
}
+ private int getOverlapForOffset(final View dependency, final int offset) {
+ if (mOverlayTop != 0 && dependency instanceof AppBarLayout) {
+ final AppBarLayout abl = (AppBarLayout) dependency;
+ final int totalScrollRange = abl.getTotalScrollRange();
+ final int preScrollDown = abl.getDownNestedPreScrollRange();
+
+ if (preScrollDown != 0 && (totalScrollRange + offset) <= preScrollDown) {
+ // If we're in a pre-scroll down. Don't use the offset at all.
+ return 0;
+ } else {
+ final int availScrollRange = totalScrollRange - preScrollDown;
+ if (availScrollRange != 0) {
+ // Else we'll use a interpolated ratio of the overlap, depending on offset
+ final float percScrolled = offset / (float) availScrollRange;
+ return MathUtils.constrain(
+ Math.round((1f + percScrolled) * mOverlayTop), 0, mOverlayTop);
+ }
+ }
+ }
+ return mOverlayTop;
+ }
+
/**
* Set the distance that this view should overlap any {@link AppBarLayout}.
*
@@ -1287,14 +1239,24 @@
return mOverlayTop;
}
- private static AppBarLayout findFirstAppBarLayout(List<View> views) {
+ @Override
+ View findFirstDependency(List<View> views) {
for (int i = 0, z = views.size(); i < z; i++) {
View view = views.get(i);
if (view instanceof AppBarLayout) {
- return (AppBarLayout) view;
+ return view;
}
}
return null;
}
+
+ @Override
+ int getScrollRange(View v) {
+ if (v instanceof AppBarLayout) {
+ return ((AppBarLayout) v).getTotalScrollRange();
+ } else {
+ return super.getScrollRange(v);
+ }
+ }
}
}
diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
new file mode 100644
index 0000000..cd24414
--- /dev/null
+++ b/design/src/android/support/design/widget/BottomSheetBehavior.java
@@ -0,0 +1,417 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.IntDef;
+import android.support.design.R;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.ViewDragHelper;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+
+
+/**
+ * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as
+ * a bottom sheet.
+ */
+public class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
+
+ /**
+ * The bottom sheet is dragging.
+ */
+ public static final int STATE_DRAGGING = 1;
+
+ /**
+ * The bottom sheet is settling.
+ */
+ public static final int STATE_SETTLING = 2;
+
+ /**
+ * The bottom sheet is expanded.
+ */
+ public static final int STATE_EXPANDED = 3;
+
+ /**
+ * The bottom sheet is collapsed.
+ */
+ public static final int STATE_COLLAPSED = 4;
+
+ /** @hide */
+ @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {}
+
+ private int mPeekHeight;
+
+ private int mMinOffset;
+
+ private int mMaxOffset;
+
+ @State
+ private int mState = STATE_COLLAPSED;
+
+ private ViewDragHelper mViewDragHelper;
+
+ private boolean mIgnoreEvents;
+
+ private int mLastNestedScrollDy;
+
+ private int mParentHeight;
+
+ private WeakReference<V> mViewRef;
+
+ /**
+ * Default constructor for instantiating BottomSheetBehaviors.
+ */
+ public BottomSheetBehavior() {
+ }
+
+ /**
+ * Default constructor for inflating BottomSheetBehaviors from layout.
+ *
+ * @param context The {@link Context}.
+ * @param attrs The {@link AttributeSet}.
+ */
+ public BottomSheetBehavior(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.BottomSheetBehavior_Params);
+ setPeekHeight(a.getDimensionPixelSize(
+ R.styleable.BottomSheetBehavior_Params_behavior_peekHeight, 0));
+ a.recycle();
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
+ return new SavedState(super.onSaveInstanceState(parent, child), mState);
+ }
+
+ @Override
+ public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
+ SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(parent, child, ss.getSuperState());
+ mState = ss.state;
+ // Intermediate states are restored as collapsed state
+ if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
+ mState = STATE_COLLAPSED;
+ }
+ }
+
+ @Override
+ public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
+ // First let the parent lay it out
+ parent.onLayoutChild(child, layoutDirection);
+ // Offset the bottom sheet
+ mParentHeight = parent.getHeight();
+ mMinOffset = Math.max(0, mParentHeight - child.getHeight());
+ mMaxOffset = mParentHeight - mPeekHeight;
+ if (mState == STATE_EXPANDED) {
+ ViewCompat.offsetTopAndBottom(child, mMinOffset);
+ } else {
+ ViewCompat.offsetTopAndBottom(child, mMaxOffset);
+ mState = STATE_COLLAPSED;
+ }
+ if (mViewDragHelper == null) {
+ mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
+ }
+ mViewRef = new WeakReference<>(child);
+ return true;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
+ int action = MotionEventCompat.getActionMasked(event);
+ switch (action) {
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ // Reset the ignore flag
+ if (mIgnoreEvents) {
+ mIgnoreEvents = false;
+ return false;
+ }
+ break;
+ case MotionEvent.ACTION_DOWN:
+ mIgnoreEvents = !parent.isPointInChildBounds(child,
+ (int) event.getX(), (int) event.getY());
+ break;
+ }
+ return !mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event);
+ }
+
+ @Override
+ public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
+ mViewDragHelper.processTouchEvent(event);
+ return true;
+ }
+
+ @Override
+ public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child,
+ View directTargetChild, View target, int nestedScrollAxes) {
+ mLastNestedScrollDy = 0;
+ return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
+ }
+
+ @Override
+ public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
+ int dy, int[] consumed) {
+ int currentTop = child.getTop();
+ int newTop = currentTop - dy;
+ if (dy > 0) { // Scrolling up
+ if (newTop < mMinOffset) {
+ consumed[1] = currentTop - mMinOffset;
+ child.offsetTopAndBottom(-consumed[1]);
+ setStateInternal(STATE_EXPANDED);
+ } else {
+ consumed[1] = dy;
+ child.offsetTopAndBottom(-dy);
+ setStateInternal(STATE_DRAGGING);
+ }
+ } else if (dy < 0) { // Scrolling down
+ if (!ViewCompat.canScrollVertically(target, -1)) {
+ if (newTop > mMaxOffset) {
+ consumed[1] = currentTop - mMaxOffset;
+ child.offsetTopAndBottom(-consumed[1]);
+ setStateInternal(STATE_COLLAPSED);
+ } else {
+ consumed[1] = dy;
+ child.offsetTopAndBottom(-dy);
+ setStateInternal(STATE_DRAGGING);
+ }
+ }
+ }
+ mLastNestedScrollDy = dy;
+ }
+
+ @Override
+ public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
+ if (mLastNestedScrollDy == 0 || child.getTop() == mMinOffset) {
+ return;
+ }
+ int top;
+ int targetState;
+ if (mLastNestedScrollDy > 0) {
+ top = mMinOffset;
+ targetState = STATE_EXPANDED;
+ } else {
+ top = mMaxOffset;
+ targetState = STATE_COLLAPSED;
+ }
+ setStateInternal(STATE_SETTLING);
+ if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
+ ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));
+ }
+ }
+
+ /**
+ * Sets the height of the bottom sheet when it is collapsed.
+ *
+ * @param peekHeight The height of the collapsed bottom sheet in pixels.
+ * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight
+ */
+ public final void setPeekHeight(int peekHeight) {
+ mPeekHeight = Math.max(0, peekHeight);
+ mMaxOffset = mParentHeight - peekHeight;
+ }
+
+ /**
+ * Gets the height of the bottom sheet when it is collapsed.
+ *
+ * @return The height of the collapsed bottom sheet.
+ * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight
+ */
+ public final int getPeekHeight() {
+ return mPeekHeight;
+ }
+
+ /**
+ * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
+ * animation.
+ *
+ * @param state Either {@link #STATE_COLLAPSED} or {@link #STATE_EXPANDED}.
+ */
+ public final void setState(@State int state) {
+ V child = mViewRef.get();
+ if (child == null) {
+ return;
+ }
+ int top;
+ if (state == STATE_COLLAPSED) {
+ top = mMaxOffset;
+ } else if (state == STATE_EXPANDED) {
+ top = mMinOffset;
+ } else {
+ throw new IllegalArgumentException("Illegal state argument: " + state);
+ }
+ setStateInternal(STATE_SETTLING);
+ if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
+ ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
+ }
+ }
+
+ /**
+ * Gets the current state of the bottom sheet.
+ *
+ * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING},
+ * and {@link #STATE_SETTLING}.
+ */
+ @State
+ public final int getState() {
+ return mState;
+ }
+
+ private void setStateInternal(@State int state) {
+ if (mState == state) {
+ return;
+ }
+ mState = state;
+ // TODO: Invoke listeners.
+ }
+
+ private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
+
+ @Override
+ public boolean tryCaptureView(View child, int pointerId) {
+ return true;
+ }
+
+ @Override
+ public void onViewDragStateChanged(int state) {
+ if (state == ViewDragHelper.STATE_DRAGGING) {
+ setStateInternal(STATE_DRAGGING);
+ }
+ }
+
+ @Override
+ public void onViewReleased(View releasedChild, float xvel, float yvel) {
+ int top;
+ @State int targetState;
+ if (yvel < 0) {
+ top = mMinOffset;
+ targetState = STATE_EXPANDED;
+ } else {
+ top = mMaxOffset;
+ targetState = STATE_COLLAPSED;
+ }
+ setStateInternal(STATE_SETTLING);
+ if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {
+ ViewCompat.postOnAnimation(releasedChild,
+ new SettleRunnable(releasedChild, targetState));
+ }
+ }
+
+ @Override
+ public int clampViewPositionVertical(View child, int top, int dy) {
+ return MathUtils.constrain(top, mMinOffset, mMaxOffset);
+ }
+
+ @Override
+ public int clampViewPositionHorizontal(View child, int left, int dx) {
+ return child.getLeft();
+ }
+ };
+
+ private class SettleRunnable implements Runnable {
+
+ private final View mView;
+
+ @State
+ private final int mTargetState;
+
+ SettleRunnable(View view, @State int targetState) {
+ mView = view;
+ mTargetState = targetState;
+ }
+
+ @Override
+ public void run() {
+ if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
+ ViewCompat.postOnAnimation(mView, this);
+ } else {
+ setStateInternal(mTargetState);
+ }
+ }
+ }
+
+ protected static class SavedState extends View.BaseSavedState {
+
+ @State
+ final int state;
+
+ public SavedState(Parcel source) {
+ super(source);
+ //noinspection ResourceType
+ state = source.readInt();
+ }
+
+ public SavedState(Parcelable superState, @State int state) {
+ super(superState);
+ this.state = state;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ super.writeToParcel(out, flags);
+ out.writeInt(state);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ @Override
+ public SavedState createFromParcel(Parcel source) {
+ return new SavedState(source);
+ }
+
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+ /*
+ * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}.
+ *
+ * @param view The {@link View} with {@link BottomSheetBehavior}.
+ * @return The {@link BottomSheetBehavior} associated with the {@code view}.
+ */
+ @SuppressWarnings("unchecked")
+ public static <V extends View> BottomSheetBehavior<V> from(V view) {
+ ViewGroup.LayoutParams params = view.getLayoutParams();
+ if (!(params instanceof CoordinatorLayout.LayoutParams)) {
+ throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
+ }
+ CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
+ .getBehavior();
+ if (!(behavior instanceof BottomSheetBehavior)) {
+ throw new IllegalArgumentException(
+ "The view is not associated with BottomSheetBehavior");
+ }
+ return (BottomSheetBehavior<V>) behavior;
+ }
+
+}
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
index 082c316..9a38c7d 100644
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ b/design/src/android/support/design/widget/CollapsingTextHelper.java
@@ -72,6 +72,9 @@
private float mCollapsedDrawX;
private float mCurrentDrawX;
private float mCurrentDrawY;
+ private Typeface mCollapsedTypeface;
+ private Typeface mExpandedTypeface;
+ private Typeface mCurrentTypeface;
private CharSequence mText;
private CharSequence mTextToDraw;
@@ -93,6 +96,12 @@
private Interpolator mPositionInterpolator;
private Interpolator mTextSizeInterpolator;
+ private float mCollapsedShadowRadius, mCollapsedShadowDx, mCollapsedShadowDy;
+ private int mCollapsedShadowColor;
+
+ private float mExpandedShadowRadius, mExpandedShadowDx, mExpandedShadowDy;
+ private int mExpandedShadowColor;
+
public CollapsingTextHelper(View view) {
mView = view;
@@ -195,8 +204,16 @@
mCollapsedTextSize = a.getDimensionPixelSize(
R.styleable.TextAppearance_android_textSize, (int) mCollapsedTextSize);
}
+ mCollapsedShadowColor = a.getInt(R.styleable.TextAppearance_android_shadowColor, 0);
+ mCollapsedShadowDx = a.getFloat(R.styleable.TextAppearance_android_shadowDx, 0);
+ mCollapsedShadowDy = a.getFloat(R.styleable.TextAppearance_android_shadowDy, 0);
+ mCollapsedShadowRadius = a.getFloat(R.styleable.TextAppearance_android_shadowRadius, 0);
a.recycle();
+ if (Build.VERSION.SDK_INT >= 16) {
+ mCollapsedTypeface = readFontFamilyTypeface(resId);
+ }
+
recalculate();
}
@@ -210,23 +227,58 @@
mExpandedTextSize = a.getDimensionPixelSize(
R.styleable.TextAppearance_android_textSize, (int) mExpandedTextSize);
}
+ mExpandedShadowColor = a.getInt(R.styleable.TextAppearance_android_shadowColor, 0);
+ mExpandedShadowDx = a.getFloat(R.styleable.TextAppearance_android_shadowDx, 0);
+ mExpandedShadowDy = a.getFloat(R.styleable.TextAppearance_android_shadowDy, 0);
+ mExpandedShadowRadius = a.getFloat(R.styleable.TextAppearance_android_shadowRadius, 0);
a.recycle();
+ if (Build.VERSION.SDK_INT >= 16) {
+ mExpandedTypeface = readFontFamilyTypeface(resId);
+ }
+
recalculate();
}
- void setTypeface(Typeface typeface) {
- if (typeface == null) {
- typeface = Typeface.DEFAULT;
+ private Typeface readFontFamilyTypeface(int resId) {
+ final TypedArray a = mView.getContext().obtainStyledAttributes(resId,
+ new int[]{android.R.attr.fontFamily});
+ try {
+ final String family = a.getString(0);
+ if (family != null) {
+ return Typeface.create(family, Typeface.NORMAL);
+ }
+ } finally {
+ a.recycle();
}
- if (mTextPaint.getTypeface() != typeface) {
- mTextPaint.setTypeface(typeface);
+ return null;
+ }
+
+ void setCollapsedTypeface(Typeface typeface) {
+ if (mCollapsedTypeface != typeface) {
+ mCollapsedTypeface = typeface;
recalculate();
}
}
- Typeface getTypeface() {
- return mTextPaint.getTypeface();
+ void setExpandedTypeface(Typeface typeface) {
+ if (mExpandedTypeface != typeface) {
+ mExpandedTypeface = typeface;
+ recalculate();
+ }
+ }
+
+ void setTypefaces(Typeface typeface) {
+ mCollapsedTypeface = mExpandedTypeface = typeface;
+ recalculate();
+ }
+
+ Typeface getCollapsedTypeface() {
+ return mCollapsedTypeface != null ? mCollapsedTypeface : Typeface.DEFAULT;
+ }
+
+ Typeface getExpandedTypeface() {
+ return mExpandedTypeface != null ? mExpandedTypeface : Typeface.DEFAULT;
}
/**
@@ -258,8 +310,10 @@
}
private void calculateCurrentOffsets() {
- final float fraction = mExpandedFraction;
+ calculateOffsets(mExpandedFraction);
+ }
+ private void calculateOffsets(final float fraction) {
interpolateBounds(fraction);
mCurrentDrawX = lerp(mExpandedDrawX, mCollapsedDrawX, fraction,
mPositionInterpolator);
@@ -277,12 +331,20 @@
mTextPaint.setColor(mCollapsedTextColor);
}
+ mTextPaint.setShadowLayer(
+ lerp(mExpandedShadowRadius, mCollapsedShadowRadius, fraction, null),
+ lerp(mExpandedShadowDx, mCollapsedShadowDx, fraction, null),
+ lerp(mExpandedShadowDy, mCollapsedShadowDy, fraction, null),
+ blendColors(mExpandedShadowColor, mCollapsedShadowColor, fraction));
+
ViewCompat.postInvalidateOnAnimation(mView);
}
private void calculateBaseOffsets() {
+ final float currentTextSize = mCurrentTextSize;
+
// We then calculate the collapsed text size, using the same logic
- mTextPaint.setTextSize(mCollapsedTextSize);
+ calculateUsingTextSize(mCollapsedTextSize);
float width = mTextToDraw != null ?
mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()) : 0;
final int collapsedAbsGravity = GravityCompat.getAbsoluteGravity(mCollapsedTextGravity,
@@ -314,7 +376,7 @@
break;
}
- mTextPaint.setTextSize(mExpandedTextSize);
+ calculateUsingTextSize(mExpandedTextSize);
width = mTextToDraw != null
? mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()) : 0;
final int expandedAbsGravity = GravityCompat.getAbsoluteGravity(mExpandedTextGravity,
@@ -348,6 +410,8 @@
// The bounds have changed so we need to clear the texture
clearTexture();
+ // Now reset the text size back to the original
+ setInterpolatedTextSize(currentTextSize);
}
private void interpolateBounds(float fraction) {
@@ -417,47 +481,8 @@
: TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR).isRtl(text, 0, text.length());
}
- private void setInterpolatedTextSize(final float textSize) {
- if (mText == null) return;
-
- final float availableWidth;
- final float newTextSize;
- boolean updateDrawText = false;
-
- if (isClose(textSize, mCollapsedTextSize)) {
- availableWidth = mCollapsedBounds.width();
- newTextSize = mCollapsedTextSize;
- mScale = 1f;
- } else {
- availableWidth = mExpandedBounds.width();
- newTextSize = mExpandedTextSize;
-
- if (isClose(textSize, mExpandedTextSize)) {
- // If we're close to the expanded text size, snap to it and use a scale of 1
- mScale = 1f;
- } else {
- // Else, we'll scale down from the expanded text size
- mScale = textSize / mExpandedTextSize;
- }
- }
-
- if (availableWidth > 0) {
- updateDrawText = (mCurrentTextSize != newTextSize) || mBoundsChanged;
- mCurrentTextSize = newTextSize;
- mBoundsChanged = false;
- }
-
- if (mTextToDraw == null || updateDrawText) {
- mTextPaint.setTextSize(mCurrentTextSize);
-
- // If we don't currently have text to draw, or the text size has changed, ellipsize...
- final CharSequence title = TextUtils.ellipsize(mText, mTextPaint,
- availableWidth, TextUtils.TruncateAt.END);
- if (mTextToDraw == null || !mTextToDraw.equals(title)) {
- mTextToDraw = title;
- }
- mIsRtl = calculateIsRtl(mTextToDraw);
- }
+ private void setInterpolatedTextSize(float textSize) {
+ calculateUsingTextSize(textSize);
// Use our texture if the scale isn't 1.0
mUseTexture = USE_SCALING_TEXTURE && mScale != 1f;
@@ -470,21 +495,72 @@
ViewCompat.postInvalidateOnAnimation(mView);
}
+ private void calculateUsingTextSize(final float textSize) {
+ if (mText == null) return;
+
+ final float availableWidth;
+ final float newTextSize;
+ boolean updateDrawText = false;
+
+ if (isClose(textSize, mCollapsedTextSize)) {
+ availableWidth = mCollapsedBounds.width();
+ newTextSize = mCollapsedTextSize;
+ mScale = 1f;
+ if (mCurrentTypeface != mCollapsedTypeface) {
+ mCurrentTypeface = mCollapsedTypeface;
+ updateDrawText = true;
+ }
+ } else {
+ availableWidth = mExpandedBounds.width();
+ newTextSize = mExpandedTextSize;
+ if (mCurrentTypeface != mExpandedTypeface) {
+ mCurrentTypeface = mExpandedTypeface;
+ updateDrawText = true;
+ }
+
+ if (isClose(textSize, mExpandedTextSize)) {
+ // If we're close to the expanded text size, snap to it and use a scale of 1
+ mScale = 1f;
+ } else {
+ // Else, we'll scale down from the expanded text size
+ mScale = textSize / mExpandedTextSize;
+ }
+ }
+
+ if (availableWidth > 0) {
+ updateDrawText = (mCurrentTextSize != newTextSize) || mBoundsChanged || updateDrawText;
+ mCurrentTextSize = newTextSize;
+ mBoundsChanged = false;
+ }
+
+ if (mTextToDraw == null || updateDrawText) {
+ mTextPaint.setTextSize(mCurrentTextSize);
+ mTextPaint.setTypeface(mCurrentTypeface);
+
+ // If we don't currently have text to draw, or the text size has changed, ellipsize...
+ final CharSequence title = TextUtils.ellipsize(mText, mTextPaint,
+ availableWidth, TextUtils.TruncateAt.END);
+ if (!TextUtils.equals(title, mTextToDraw)) {
+ mTextToDraw = title;
+ mIsRtl = calculateIsRtl(mTextToDraw);
+ }
+ }
+ }
+
private void ensureExpandedTexture() {
if (mExpandedTitleTexture != null || mExpandedBounds.isEmpty()
|| TextUtils.isEmpty(mTextToDraw)) {
return;
}
- mTextPaint.setTextSize(mExpandedTextSize);
- mTextPaint.setColor(mExpandedTextColor);
+ calculateOffsets(0f);
mTextureAscent = mTextPaint.ascent();
mTextureDescent = mTextPaint.descent();
final int w = Math.round(mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()));
final int h = Math.round(mTextureDescent - mTextureAscent);
- if (w <= 0 && h <= 0) {
+ if (w <= 0 || h <= 0) {
return; // If the width or height are 0, return
}
diff --git a/design/src/android/support/design/widget/CollapsingToolbarLayout.java b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
index 230a1d0..62fef07 100644
--- a/design/src/android/support/design/widget/CollapsingToolbarLayout.java
+++ b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
@@ -20,12 +20,14 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.design.R;
@@ -94,14 +96,15 @@
private Toolbar mToolbar;
private View mDummyView;
- private int mExpandedMarginLeft;
+ private int mExpandedMarginStart;
private int mExpandedMarginTop;
- private int mExpandedMarginRight;
+ private int mExpandedMarginEnd;
private int mExpandedMarginBottom;
private final Rect mTmpRect = new Rect();
private final CollapsingTextHelper mCollapsingTextHelper;
private boolean mCollapsingTitleEnabled;
+ private boolean mDrawCollapsingTitle;
private Drawable mContentScrim;
private Drawable mStatusBarScrim;
@@ -126,6 +129,8 @@
public CollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ ThemeUtils.checkAppCompatTheme(context);
+
mCollapsingTextHelper = new CollapsingTextHelper(this);
mCollapsingTextHelper.setTextSizeInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
@@ -140,28 +145,16 @@
a.getInt(R.styleable.CollapsingToolbarLayout_collapsedTitleGravity,
GravityCompat.START | Gravity.CENTER_VERTICAL));
- mExpandedMarginLeft = mExpandedMarginTop = mExpandedMarginRight = mExpandedMarginBottom =
+ mExpandedMarginStart = mExpandedMarginTop = mExpandedMarginEnd = mExpandedMarginBottom =
a.getDimensionPixelSize(R.styleable.CollapsingToolbarLayout_expandedTitleMargin, 0);
- final boolean isRtl = ViewCompat.getLayoutDirection(this)
- == ViewCompat.LAYOUT_DIRECTION_RTL;
if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginStart)) {
- final int marginStart = a.getDimensionPixelSize(
+ mExpandedMarginStart = a.getDimensionPixelSize(
R.styleable.CollapsingToolbarLayout_expandedTitleMarginStart, 0);
- if (isRtl) {
- mExpandedMarginRight = marginStart;
- } else {
- mExpandedMarginLeft = marginStart;
- }
}
if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginEnd)) {
- final int marginEnd = a.getDimensionPixelSize(
+ mExpandedMarginEnd = a.getDimensionPixelSize(
R.styleable.CollapsingToolbarLayout_expandedTitleMarginEnd, 0);
- if (isRtl) {
- mExpandedMarginLeft = marginEnd;
- } else {
- mExpandedMarginRight = marginEnd;
- }
}
if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginTop)) {
mExpandedMarginTop = a.getDimensionPixelSize(
@@ -192,7 +185,6 @@
mCollapsingTextHelper.setCollapsedTextAppearance(
a.getResourceId(
R.styleable.CollapsingToolbarLayout_collapsedTitleTextAppearance, 0));
-
}
setContentScrim(a.getDrawable(R.styleable.CollapsingToolbarLayout_contentScrim));
@@ -254,7 +246,7 @@
}
// Let the collapsing text helper draw it's text
- if (mCollapsingTitleEnabled) {
+ if (mCollapsingTitleEnabled && mDrawCollapsingTitle) {
mCollapsingTextHelper.draw(canvas);
}
@@ -360,6 +352,31 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
+ // Update the collapsed bounds by getting it's transformed bounds. This needs to be done
+ // before the children are offset below
+ if (mCollapsingTitleEnabled && mDummyView != null) {
+ // We only draw the title if the dummy view is being displayed (Toolbar removes
+ // views if there is no space)
+ mDrawCollapsingTitle = mDummyView.isShown();
+
+ if (mDrawCollapsingTitle) {
+ ViewGroupUtils.getDescendantRect(this, mDummyView, mTmpRect);
+ mCollapsingTextHelper.setCollapsedBounds(mTmpRect.left, bottom - mTmpRect.height(),
+ mTmpRect.right, bottom);
+
+ final boolean isRtl = ViewCompat.getLayoutDirection(this)
+ == ViewCompat.LAYOUT_DIRECTION_RTL;
+ // Update the expanded bounds
+ mCollapsingTextHelper.setExpandedBounds(
+ isRtl ? mExpandedMarginEnd : mExpandedMarginStart,
+ mTmpRect.bottom + mExpandedMarginTop,
+ right - left - (isRtl ? mExpandedMarginStart : mExpandedMarginEnd),
+ bottom - top - mExpandedMarginBottom);
+ // Now recalculate using the new bounds
+ mCollapsingTextHelper.recalculate();
+ }
+ }
+
// Update our child view offset helpers
for (int i = 0, z = getChildCount(); i < z; i++) {
final View child = getChildAt(i);
@@ -376,21 +393,6 @@
getViewOffsetHelper(child).onViewLayout();
}
- // Update the collapsed bounds by getting it's transformed bounds
- if (mCollapsingTitleEnabled && mDummyView != null) {
- ViewGroupUtils.getDescendantRect(this, mDummyView, mTmpRect);
- mCollapsingTextHelper.setCollapsedBounds(mTmpRect.left, bottom - mTmpRect.height(),
- mTmpRect.right, bottom);
- // Update the expanded bounds
- mCollapsingTextHelper.setExpandedBounds(
- mExpandedMarginLeft,
- mTmpRect.bottom + mExpandedMarginTop,
- right - left - mExpandedMarginRight,
- bottom - top - mExpandedMarginBottom);
-
- mCollapsingTextHelper.recalculate();
- }
-
// Finally, set our minimum height to enable proper AppBarLayout collapsing
if (mToolbar != null) {
if (mCollapsingTitleEnabled && TextUtils.isEmpty(mCollapsingTextHelper.getText())) {
@@ -462,25 +464,38 @@
return mCollapsingTitleEnabled;
}
- private void showScrim() {
- if (!mScrimsAreShown) {
- if (ViewCompat.isLaidOut(this) && !isInEditMode()) {
- animateScrim(255);
- } else {
- setScrimAlpha(255);
- }
- mScrimsAreShown = true;
- }
+ /**
+ * Set whether the content scrim and/or status bar scrim should be shown or not. Any change
+ * in the vertical scroll may overwrite this value. Any visibility change will be animated if
+ * this view has already been laid out.
+ *
+ * @param shown whether the scrims should be shown
+ *
+ * @see #getStatusBarScrim()
+ * @see #getContentScrim()
+ */
+ public void setScrimsShown(boolean shown) {
+ setScrimsShown(shown, ViewCompat.isLaidOut(this) && !isInEditMode());
}
- private void hideScrim() {
- if (mScrimsAreShown) {
- if (ViewCompat.isLaidOut(this) && !isInEditMode()) {
- animateScrim(0);
+ /**
+ * Set whether the content scrim and/or status bar scrim should be shown or not. Any change
+ * in the vertical scroll may overwrite this value.
+ *
+ * @param shown whether the scrims should be shown
+ * @param animate whether to animate the visibility change
+ *
+ * @see #getStatusBarScrim()
+ * @see #getContentScrim()
+ */
+ public void setScrimsShown(boolean shown, boolean animate) {
+ if (mScrimsAreShown != shown) {
+ if (animate) {
+ animateScrim(shown ? 0xFF : 0x0);
} else {
- setScrimAlpha(0);
+ setScrimAlpha(shown ? 0xFF : 0x0);
}
- mScrimsAreShown = false;
+ mScrimsAreShown = shown;
}
}
@@ -489,7 +504,10 @@
if (mScrimAnimator == null) {
mScrimAnimator = ViewUtils.createAnimator();
mScrimAnimator.setDuration(SCRIM_ANIMATION_DURATION);
- mScrimAnimator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+ mScrimAnimator.setInterpolator(
+ targetAlpha > mScrimAlpha
+ ? AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR
+ : AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR);
mScrimAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimatorCompat animator) {
@@ -529,11 +547,14 @@
if (mContentScrim != null) {
mContentScrim.setCallback(null);
}
-
- mContentScrim = drawable;
- drawable.setBounds(0, 0, getWidth(), getHeight());
- drawable.setCallback(this);
- drawable.mutate().setAlpha(mScrimAlpha);
+ if (drawable != null) {
+ mContentScrim = drawable.mutate();
+ drawable.setBounds(0, 0, getWidth(), getHeight());
+ drawable.setCallback(this);
+ drawable.setAlpha(mScrimAlpha);
+ } else {
+ mContentScrim = null;
+ }
ViewCompat.postInvalidateOnAnimation(this);
}
}
@@ -660,7 +681,7 @@
* @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_collapsedTitleGravity
*/
public void setCollapsedTitleGravity(int gravity) {
- mCollapsingTextHelper.setExpandedTextGravity(gravity);
+ mCollapsingTextHelper.setCollapsedTextGravity(gravity);
}
/**
@@ -712,6 +733,147 @@
}
/**
+ * Set the typeface to use for the collapsed title.
+ *
+ * @param typeface typeface to use, or {@code null} to use the default.
+ */
+ public void setCollapsedTitleTypeface(@Nullable Typeface typeface) {
+ mCollapsingTextHelper.setCollapsedTypeface(typeface);
+ }
+
+ /**
+ * Returns the typeface used for the collapsed title.
+ */
+ @NonNull
+ public Typeface getCollapsedTitleTypeface() {
+ return mCollapsingTextHelper.getCollapsedTypeface();
+ }
+
+ /**
+ * Set the typeface to use for the expanded title.
+ *
+ * @param typeface typeface to use, or {@code null} to use the default.
+ */
+ public void setExpandedTitleTypeface(@Nullable Typeface typeface) {
+ mCollapsingTextHelper.setExpandedTypeface(typeface);
+ }
+
+ /**
+ * Returns the typeface used for the expanded title.
+ */
+ @NonNull
+ public Typeface getExpandedTitleTypeface() {
+ return mCollapsingTextHelper.getExpandedTypeface();
+ }
+
+ /**
+ * Sets the expanded title margins.
+ *
+ * @param start the starting title margin in pixels
+ * @param top the top title margin in pixels
+ * @param end the ending title margin in pixels
+ * @param bottom the bottom title margin in pixels
+ *
+ * @see #getExpandedTitleMarginStart()
+ * @see #getExpandedTitleMarginTop()
+ * @see #getExpandedTitleMarginEnd()
+ * @see #getExpandedTitleMarginBottom()
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMargin
+ */
+ public void setExpandedTitleMargin(int start, int top, int end, int bottom) {
+ mExpandedMarginStart = start;
+ mExpandedMarginTop = top;
+ mExpandedMarginEnd = end;
+ mExpandedMarginBottom = bottom;
+ requestLayout();
+ }
+
+ /**
+ * @return the starting expanded title margin in pixels
+ *
+ * @see #setExpandedTitleMarginStart(int)
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginStart
+ */
+ public int getExpandedTitleMarginStart() {
+ return mExpandedMarginStart;
+ }
+
+ /**
+ * Sets the starting expanded title margin in pixels.
+ *
+ * @param margin the starting title margin in pixels
+ * @see #getExpandedTitleMarginStart()
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginStart
+ */
+ public void setExpandedTitleMarginStart(int margin) {
+ mExpandedMarginStart = margin;
+ requestLayout();
+ }
+
+ /**
+ * @return the top expanded title margin in pixels
+ * @see #setExpandedTitleMarginTop(int)
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginTop
+ */
+ public int getExpandedTitleMarginTop() {
+ return mExpandedMarginTop;
+ }
+
+ /**
+ * Sets the top expanded title margin in pixels.
+ *
+ * @param margin the top title margin in pixels
+ * @see #getExpandedTitleMarginTop()
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginTop
+ */
+ public void setExpandedTitleMarginTop(int margin) {
+ mExpandedMarginTop = margin;
+ requestLayout();
+ }
+
+ /**
+ * @return the ending expanded title margin in pixels
+ * @see #setExpandedTitleMarginEnd(int)
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginEnd
+ */
+ public int getExpandedTitleMarginEnd() {
+ return mExpandedMarginEnd;
+ }
+
+ /**
+ * Sets the ending expanded title margin in pixels.
+ *
+ * @param margin the ending title margin in pixels
+ * @see #getExpandedTitleMarginEnd()
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginEnd
+ */
+ public void setExpandedTitleMarginEnd(int margin) {
+ mExpandedMarginEnd = margin;
+ requestLayout();
+ }
+
+ /**
+ * @return the bottom expanded title margin in pixels
+ * @see #setExpandedTitleMarginBottom(int)
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginBottom
+ */
+ public int getExpandedTitleMarginBottom() {
+ return mExpandedMarginBottom;
+ }
+
+ /**
+ * Sets the bottom expanded title margin in pixels.
+ *
+ * @param margin the bottom title margin in pixels
+ * @see #getExpandedTitleMarginBottom()
+ * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginBottom
+ */
+ public void setExpandedTitleMarginBottom(int margin) {
+ mExpandedMarginBottom = margin;
+ requestLayout();
+ }
+
+ /**
* The additional offset used to define when to trigger the scrim visibility change.
*/
final int getScrimTriggerOffset() {
@@ -878,11 +1040,7 @@
// Show or hide the scrims if needed
if (mContentScrim != null || mStatusBarScrim != null) {
- if (getHeight() + verticalOffset < getScrimTriggerOffset() + insetTop) {
- showScrim();
- } else {
- hideScrim();
- }
+ setScrimsShown(getHeight() + verticalOffset < getScrimTriggerOffset() + insetTop);
}
if (mStatusBarScrim != null && insetTop > 0) {
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index 708a123..3d16ac9 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -31,6 +31,8 @@
import android.os.SystemClock;
import android.support.design.R;
import android.support.v4.content.ContextCompat;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.NestedScrollingParent;
@@ -85,7 +87,12 @@
*/
public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent {
static final String TAG = "CoordinatorLayout";
- static final String WIDGET_PACKAGE_NAME = CoordinatorLayout.class.getPackage().getName();
+ static final String WIDGET_PACKAGE_NAME;
+
+ static {
+ final Package pkg = CoordinatorLayout.class.getPackage();
+ WIDGET_PACKAGE_NAME = pkg != null ? pkg.getName() : null;
+ }
private static final int TYPE_ON_INTERCEPT = 0;
private static final int TYPE_ON_TOUCH = 1;
@@ -168,6 +175,8 @@
public CoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ ThemeUtils.checkAppCompatTheme(context);
+
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CoordinatorLayout,
defStyleAttr, R.style.Widget_Design_CoordinatorLayout);
final int keylineArrayRes = a.getResourceId(R.styleable.CoordinatorLayout_keylines, 0);
@@ -499,8 +508,10 @@
// Fully qualified package name.
fullName = name;
} else {
- // Assume stock behavior in this package.
- fullName = WIDGET_PACKAGE_NAME + '.' + name;
+ // Assume stock behavior in this package (if we have one)
+ fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)
+ ? (WIDGET_PACKAGE_NAME + '.' + name)
+ : name;
}
try {
@@ -546,26 +557,18 @@
}
private void prepareChildren() {
- final int childCount = getChildCount();
-
- boolean resortRequired = mDependencySortedChildren.size() != childCount;
-
- for (int i = 0; i < childCount; i++) {
+ mDependencySortedChildren.clear();
+ for (int i = 0, count = getChildCount(); i < count; i++) {
final View child = getChildAt(i);
- final LayoutParams lp = getResolvedLayoutParams(child);
- if (!resortRequired && lp.isDirty(this, child)) {
- resortRequired = true;
- }
- lp.findAnchorView(this, child);
- }
- if (resortRequired) {
- mDependencySortedChildren.clear();
- for (int i = 0; i < childCount; i++) {
- mDependencySortedChildren.add(getChildAt(i));
- }
- Collections.sort(mDependencySortedChildren, mLayoutDependencyComparator);
+ final LayoutParams lp = getResolvedLayoutParams(child);
+ lp.findAnchorView(this, child);
+
+ mDependencySortedChildren.add(child);
}
+ // We need to use a selection sort here to make sure that every item is compared
+ // against each other
+ selectionSort(mDependencySortedChildren, mLayoutDependencyComparator);
}
/**
@@ -1143,15 +1146,23 @@
}
}
- void dispatchDependentViewRemoved(View removedChild) {
- final int childCount = getChildCount();
+ void dispatchDependentViewRemoved(View view) {
+ final int childCount = mDependencySortedChildren.size();
+ boolean viewSeen = false;
for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- final Behavior b = lp.getBehavior();
-
- if (b != null && b.layoutDependsOn(this, child, removedChild)) {
- b.onDependentViewRemoved(this, child, removedChild);
+ final View child = mDependencySortedChildren.get(i);
+ if (child == view) {
+ // We've seen our view, which means that any Views after this could be dependent
+ viewSeen = true;
+ continue;
+ }
+ if (viewSeen) {
+ CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)
+ child.getLayoutParams();
+ CoordinatorLayout.Behavior b = lp.getBehavior();
+ if (b != null && lp.dependsOn(this, child, view)) {
+ b.onDependentViewRemoved(this, child, view);
+ }
}
}
}
@@ -2246,10 +2257,6 @@
/**
* Get the id of this view's anchor.
*
- * <p>The view with this id must be a descendant of the CoordinatorLayout containing
- * the child view this LayoutParams belongs to. It may not be the child view with
- * this LayoutParams or a descendant of it.</p>
- *
* @return A {@link View#getId() view id} or {@link View#NO_ID} if there is no anchor
*/
public int getAnchorId() {
@@ -2257,7 +2264,7 @@
}
/**
- * Get the id of this view's anchor.
+ * Set the id of this view's anchor.
*
* <p>The view with this id must be a descendant of the CoordinatorLayout containing
* the child view this LayoutParams belongs to. It may not be the child view with
@@ -2454,9 +2461,18 @@
* Determine the anchor view for the child view this LayoutParams is assigned to.
* Assumes mAnchorId is valid.
*/
- private void resolveAnchorView(View forChild, CoordinatorLayout parent) {
+ private void resolveAnchorView(final View forChild, final CoordinatorLayout parent) {
mAnchorView = parent.findViewById(mAnchorId);
if (mAnchorView != null) {
+ if (mAnchorView == parent) {
+ if (parent.isInEditMode()) {
+ mAnchorView = mAnchorDirectChild = null;
+ return;
+ }
+ throw new IllegalStateException(
+ "View can not be anchored to the the parent CoordinatorLayout");
+ }
+
View directChild = mAnchorView;
for (ViewParent p = mAnchorView.getParent();
p != parent && p != null;
@@ -2586,7 +2602,7 @@
protected static class SavedState extends BaseSavedState {
SparseArray<Parcelable> behaviorStates;
- public SavedState(Parcel source) {
+ public SavedState(Parcel source, ClassLoader loader) {
super(source);
final int size = source.readInt();
@@ -2594,8 +2610,7 @@
final int[] ids = new int[size];
source.readIntArray(ids);
- final Parcelable[] states = source.readParcelableArray(
- CoordinatorLayout.class.getClassLoader());
+ final Parcelable[] states = source.readParcelableArray(loader);
behaviorStates = new SparseArray<>(size);
for (int i = 0; i < size; i++) {
@@ -2626,17 +2641,50 @@
}
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Parcelable.Creator<SavedState>() {
- @Override
- public SavedState createFromParcel(Parcel source) {
- return new SavedState(source);
- }
+ public static final Parcelable.Creator<SavedState> CREATOR
+ = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
+ @Override
+ public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+ return new SavedState(in, loader);
+ }
- @Override
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ });
+ }
+
+ private static void selectionSort(final List<View> list, final Comparator<View> comparator) {
+ if (list == null || list.size() < 2) {
+ return;
+ }
+
+ final View[] array = new View[list.size()];
+ list.toArray(array);
+ final int count = array.length;
+
+ for (int i = 0; i < count; i++) {
+ int min = i;
+
+ for (int j = i + 1; j < count; j++) {
+ if (comparator.compare(array[j], array[min]) < 0) {
+ min = j;
+ }
+ }
+
+ if (i != min) {
+ // We have a different min so swap the items
+ final View minItem = array[min];
+ array[min] = array[i];
+ array[i] = minItem;
+ }
+ }
+
+ // Finally add the array back into the collection
+ list.clear();
+ for (int i = 0; i < count; i++) {
+ list.add(array[i]);
+ }
}
}
diff --git a/design/src/android/support/design/widget/DrawableUtils.java b/design/src/android/support/design/widget/DrawableUtils.java
new file mode 100644
index 0000000..1c46e6b2
--- /dev/null
+++ b/design/src/android/support/design/widget/DrawableUtils.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.os.Build;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Caution. Gross hacks ahead.
+ */
+class DrawableUtils {
+
+ private static final String LOG_TAG = "DrawableUtils";
+
+ private static Method sSetConstantStateMethod;
+ private static boolean sSetConstantStateMethodFetched;
+
+ private static Field sDrawableContainerStateField;
+ private static boolean sDrawableContainerStateFieldFetched;
+
+ private DrawableUtils() {}
+
+ static boolean setContainerConstantState(DrawableContainer drawable,
+ Drawable.ConstantState constantState) {
+ if (Build.VERSION.SDK_INT >= 9) {
+ // We can use getDeclaredMethod() on v9+
+ return setContainerConstantStateV9(drawable, constantState);
+ } else {
+ // Else we'll just have to set the field directly
+ return setContainerConstantStateV7(drawable, constantState);
+ }
+ }
+
+ private static boolean setContainerConstantStateV9(DrawableContainer drawable,
+ Drawable.ConstantState constantState) {
+ if (!sSetConstantStateMethodFetched) {
+ try {
+ sSetConstantStateMethod = DrawableContainer.class.getDeclaredMethod(
+ "setConstantState", DrawableContainer.DrawableContainerState.class);
+ sSetConstantStateMethod.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ Log.e(LOG_TAG, "Could not fetch setConstantState(). Oh well.");
+ }
+ sSetConstantStateMethodFetched = true;
+ }
+ if (sSetConstantStateMethod != null) {
+ try {
+ sSetConstantStateMethod.invoke(drawable, constantState);
+ return true;
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not invoke setConstantState(). Oh well.");
+ }
+ }
+ return false;
+ }
+
+ private static boolean setContainerConstantStateV7(DrawableContainer drawable,
+ Drawable.ConstantState constantState) {
+ if (!sDrawableContainerStateFieldFetched) {
+ try {
+ sDrawableContainerStateField = DrawableContainer.class
+ .getDeclaredField("mDrawableContainerStateField");
+ sDrawableContainerStateField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ Log.e(LOG_TAG, "Could not fetch mDrawableContainerStateField. Oh well.");
+ }
+ sDrawableContainerStateFieldFetched = true;
+ }
+ if (sDrawableContainerStateField != null) {
+ try {
+ sDrawableContainerStateField.set(drawable, constantState);
+ return true;
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not set mDrawableContainerStateField. Oh well.");
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index 9a7b727..998fc2f 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -28,8 +28,10 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.R;
+import android.support.design.widget.FloatingActionButtonImpl.InternalVisibilityChangedListener;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@@ -53,7 +55,30 @@
* @attr ref android.support.design.R.styleable#FloatingActionButton_fabSize
*/
@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)
-public class FloatingActionButton extends ImageView {
+public class FloatingActionButton extends VisibilityAwareImageButton {
+
+ private static final String LOG_TAG = "FloatingActionButton";
+
+ /**
+ * Callback to be invoked when the visibility of a FloatingActionButton changes.
+ */
+ public abstract static class OnVisibilityChangedListener {
+ /**
+ * Called when a FloatingActionButton has been
+ * {@link #show(OnVisibilityChangedListener) shown}.
+ *
+ * @param fab the FloatingActionButton that was shown.
+ */
+ public void onShown(FloatingActionButton fab) {}
+
+ /**
+ * Called when a FloatingActionButton has been
+ * {@link #hide(OnVisibilityChangedListener) hidden}.
+ *
+ * @param fab the FloatingActionButton that was hidden.
+ */
+ public void onHidden(FloatingActionButton fab) {}
+ }
// These values must match those in the attrs declaration
private static final int SIZE_MINI = 1;
@@ -65,8 +90,9 @@
private int mBorderWidth;
private int mRippleColor;
private int mSize;
- private int mContentPadding;
+ private int mImagePadding;
+ private boolean mCompatPadding;
private final Rect mShadowPadding;
private final FloatingActionButtonImpl mImpl;
@@ -82,12 +108,13 @@
public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ ThemeUtils.checkAppCompatTheme(context);
+
mShadowPadding = new Rect();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.FloatingActionButton, defStyleAttr,
R.style.Widget_Design_FloatingActionButton);
- Drawable background = a.getDrawable(R.styleable.FloatingActionButton_android_background);
mBackgroundTint = a.getColorStateList(R.styleable.FloatingActionButton_backgroundTint);
mBackgroundTintMode = parseTintMode(a.getInt(
R.styleable.FloatingActionButton_backgroundTintMode, -1), null);
@@ -97,6 +124,7 @@
final float elevation = a.getDimension(R.styleable.FloatingActionButton_elevation, 0f);
final float pressedTranslationZ = a.getDimension(
R.styleable.FloatingActionButton_pressedTranslationZ, 0f);
+ mCompatPadding = a.getBoolean(R.styleable.FloatingActionButton_useCompatPadding, false);
a.recycle();
final ShadowViewDelegate delegate = new ShadowViewDelegate() {
@@ -108,36 +136,38 @@
@Override
public void setShadowPadding(int left, int top, int right, int bottom) {
mShadowPadding.set(left, top, right, bottom);
-
- setPadding(left + mContentPadding, top + mContentPadding,
- right + mContentPadding, bottom + mContentPadding);
+ setPadding(left + mImagePadding, top + mImagePadding,
+ right + mImagePadding, bottom + mImagePadding);
}
@Override
public void setBackgroundDrawable(Drawable background) {
FloatingActionButton.super.setBackgroundDrawable(background);
}
+
+ @Override
+ public boolean isCompatPaddingEnabled() {
+ return mCompatPadding;
+ }
};
final int sdk = Build.VERSION.SDK_INT;
if (sdk >= 21) {
mImpl = new FloatingActionButtonLollipop(this, delegate);
- } else if (sdk >= 12) {
- mImpl = new FloatingActionButtonHoneycombMr1(this, delegate);
+ } else if (sdk >= 14) {
+ mImpl = new FloatingActionButtonIcs(this, delegate);
} else {
mImpl = new FloatingActionButtonEclairMr1(this, delegate);
}
- final int maxContentSize = (int) getResources().getDimension(
- R.dimen.design_fab_content_size);
- mContentPadding = (getSizeDimension() - maxContentSize) / 2;
+ final int maxImageSize = (int) getResources().getDimension(R.dimen.design_fab_image_size);
+ mImagePadding = (getSizeDimension() - maxImageSize) / 2;
- mImpl.setBackgroundDrawable(background, mBackgroundTint,
- mBackgroundTintMode, mRippleColor, mBorderWidth);
+ mImpl.setBackgroundDrawable(mBackgroundTint, mBackgroundTintMode,
+ mRippleColor, mBorderWidth);
mImpl.setElevation(elevation);
mImpl.setPressedTranslationZ(pressedTranslationZ);
-
- setClickable(true);
+ mImpl.updatePadding();
}
@Override
@@ -163,6 +193,8 @@
* When running on devices with KitKat or below, we draw a fill rather than a ripple.
*
* @param color ARGB color to use for the ripple.
+ *
+ * @attr ref android.support.design.R.styleable#FloatingActionButton_rippleColor
*/
public void setRippleColor(@ColorInt int color) {
if (mRippleColor != color) {
@@ -196,7 +228,6 @@
}
}
-
/**
* Return the blending mode used to apply the tint to the background
* drawable, if specified.
@@ -227,19 +258,40 @@
}
@Override
- public void setBackgroundDrawable(@NonNull Drawable background) {
- if (mImpl != null) {
- mImpl.setBackgroundDrawable(
- background, mBackgroundTint, mBackgroundTintMode, mRippleColor, mBorderWidth);
- }
+ public void setBackgroundDrawable(Drawable background) {
+ Log.i(LOG_TAG, "Setting a custom background is not supported.");
+ }
+
+ @Override
+ public void setBackgroundResource(int resid) {
+ Log.i(LOG_TAG, "Setting a custom background is not supported.");
+ }
+
+ @Override
+ public void setBackgroundColor(int color) {
+ Log.i(LOG_TAG, "Setting a custom background is not supported.");
}
/**
* Shows the button.
- * <p>This method will animate it the button show if the view has already been laid out.</p>
+ * <p>This method will animate the button show if the view has already been laid out.</p>
*/
public void show() {
- mImpl.show();
+ show(null);
+ }
+
+ /**
+ * Shows the button.
+ * <p>This method will animate the button show if the view has already been laid out.</p>
+ *
+ * @param listener the listener to notify when this view is shown
+ */
+ public void show(@Nullable final OnVisibilityChangedListener listener) {
+ show(listener, true);
+ }
+
+ private void show(OnVisibilityChangedListener listener, boolean fromUser) {
+ mImpl.show(wrapOnVisibilityChangedListener(listener), fromUser);
}
/**
@@ -247,7 +299,71 @@
* <p>This method will animate the button hide if the view has already been laid out.</p>
*/
public void hide() {
- mImpl.hide();
+ hide(null);
+ }
+
+ /**
+ * Hides the button.
+ * <p>This method will animate the button hide if the view has already been laid out.</p>
+ *
+ * @param listener the listener to notify when this view is hidden
+ */
+ public void hide(@Nullable OnVisibilityChangedListener listener) {
+ hide(listener, true);
+ }
+
+ private void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) {
+ mImpl.hide(wrapOnVisibilityChangedListener(listener), fromUser);
+ }
+
+ /**
+ * Set whether FloatingActionButton should add inner padding on platforms Lollipop and after,
+ * to ensure consistent dimensions on all platforms.
+ *
+ * @param useCompatPadding true if FloatingActionButton is adding inner padding on platforms
+ * Lollipop and after, to ensure consistent dimensions on all platforms.
+ *
+ * @attr ref android.support.design.R.styleable#FloatingActionButton_useCompatPadding
+ * @see #getUseCompatPadding()
+ */
+ public void setUseCompatPadding(boolean useCompatPadding) {
+ if (mCompatPadding != useCompatPadding) {
+ mCompatPadding = useCompatPadding;
+ mImpl.onCompatShadowChanged();
+ }
+ }
+
+ /**
+ * Returns whether FloatingActionButton will add inner padding on platforms Lollipop and after.
+ *
+ * @return true if FloatingActionButton is adding inner padding on platforms Lollipop and after,
+ * to ensure consistent dimensions on all platforms.
+ *
+ * @attr ref android.support.design.R.styleable#FloatingActionButton_useCompatPadding
+ * @see #setUseCompatPadding(boolean)
+ */
+ public boolean getUseCompatPadding() {
+ return mCompatPadding;
+ }
+
+ @Nullable
+ private InternalVisibilityChangedListener wrapOnVisibilityChangedListener(
+ @Nullable final OnVisibilityChangedListener listener) {
+ if (listener == null) {
+ return null;
+ }
+
+ return new InternalVisibilityChangedListener() {
+ @Override
+ public void onShown() {
+ listener.onShown(FloatingActionButton.this);
+ }
+
+ @Override
+ public void onHidden() {
+ listener.onHidden(FloatingActionButton.this);
+ }
+ };
}
final int getSizeDimension() {
@@ -261,6 +377,18 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mImpl.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mImpl.onDetachedFromWindow();
+ }
+
+ @Override
protected void drawableStateChanged() {
super.drawableStateChanged();
mImpl.onDrawableStateChanged(getDrawableState());
@@ -273,6 +401,33 @@
mImpl.jumpDrawableToCurrentState();
}
+ /**
+ * Return in {@code rect} the bounds of the actual floating action button content in view-local
+ * coordinates. This is defined as anything within any visible shadow.
+ *
+ * @return true if this view actually has been laid out and has a content rect, else false.
+ */
+ public boolean getContentRect(@NonNull Rect rect) {
+ if (ViewCompat.isLaidOut(this)) {
+ rect.set(0, 0, getWidth(), getHeight());
+ rect.left += mShadowPadding.left;
+ rect.top += mShadowPadding.top;
+ rect.right -= mShadowPadding.right;
+ rect.bottom -= mShadowPadding.bottom;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the FloatingActionButton's background, minus any compatible shadow implementation.
+ */
+ @NonNull
+ public Drawable getContentBackground() {
+ return mImpl.getContentBackground();
+ }
+
private static int resolveAdjustedSize(int desiredSize, int measureSpec) {
int result = desiredSize;
int specMode = MeasureSpec.getMode(measureSpec);
@@ -324,6 +479,8 @@
// because we can use view translation properties which greatly simplifies the code.
private static final boolean SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11;
+ private ValueAnimatorCompat mFabTranslationYAnimator;
+ private float mFabTranslationY;
private Rect mTmpRect;
@Override
@@ -346,24 +503,6 @@
return false;
}
- @Override
- public void onDependentViewRemoved(CoordinatorLayout parent, FloatingActionButton child,
- View dependency) {
- if (dependency instanceof Snackbar.SnackbarLayout) {
- // If the removed view is a SnackbarLayout, we will animate back to our normal
- // position
- if (ViewCompat.getTranslationY(child) != 0f) {
- ViewCompat.animate(child)
- .translationY(0f)
- .scaleX(1f)
- .scaleY(1f)
- .alpha(1f)
- .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
- .setListener(null);
- }
- }
- }
-
private boolean updateFabVisibility(CoordinatorLayout parent,
AppBarLayout appBarLayout, FloatingActionButton child) {
final CoordinatorLayout.LayoutParams lp =
@@ -374,6 +513,11 @@
return false;
}
+ if (child.getUserSetVisibility() != VISIBLE) {
+ // The view isn't set to be visible so skip changing it's visibility
+ return false;
+ }
+
if (mTmpRect == null) {
mTmpRect = new Rect();
}
@@ -384,22 +528,57 @@
if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
// If the anchor's bottom is below the seam, we'll animate our FAB out
- child.hide();
+ child.hide(null, false);
} else {
// Else, we'll animate our FAB back in
- child.show();
+ child.show(null, false);
}
return true;
}
private void updateFabTranslationForSnackbar(CoordinatorLayout parent,
- FloatingActionButton fab, View snackbar) {
+ final FloatingActionButton fab, View snackbar) {
if (fab.getVisibility() != View.VISIBLE) {
return;
}
- final float translationY = getFabTranslationYForSnackbar(parent, fab);
- ViewCompat.setTranslationY(fab, translationY);
+ final float targetTransY = getFabTranslationYForSnackbar(parent, fab);
+ if (mFabTranslationY == targetTransY) {
+ // We're already at (or currently animating to) the target value, return...
+ return;
+ }
+
+ final float currentTransY = ViewCompat.getTranslationY(fab);
+
+ // Make sure that any current animation is cancelled
+ if (mFabTranslationYAnimator != null && mFabTranslationYAnimator.isRunning()) {
+ mFabTranslationYAnimator.cancel();
+ }
+
+ if (Math.abs(currentTransY - targetTransY) > (fab.getHeight() * 0.667f)) {
+ // If the FAB will be travelling by more than 2/3 of it's height, let's animate
+ // it instead
+ if (mFabTranslationYAnimator == null) {
+ mFabTranslationYAnimator = ViewUtils.createAnimator();
+ mFabTranslationYAnimator.setInterpolator(
+ AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
+ mFabTranslationYAnimator.setUpdateListener(
+ new ValueAnimatorCompat.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimatorCompat animator) {
+ ViewCompat.setTranslationY(fab,
+ animator.getAnimatedFloatValue());
+ }
+ });
+ }
+ mFabTranslationYAnimator.setFloatValues(currentTransY, targetTransY);
+ mFabTranslationYAnimator.start();
+ } else {
+ // Now update the translation Y
+ ViewCompat.setTranslationY(fab, targetTransY);
+ }
+
+ mFabTranslationY = targetTransY;
}
private float getFabTranslationYForSnackbar(CoordinatorLayout parent,
@@ -470,4 +649,27 @@
}
}
}
+
+ /**
+ * Returns the backward compatible elevation of the FloatingActionButton.
+ *
+ * @return the backward compatible elevation in pixels.
+ * @attr ref android.support.design.R.styleable#FloatingActionButton_elevation
+ * @see #setFloatingActionButtonElevation(float)
+ */
+ public float getFloatingActionButtonElevation() {
+ return mImpl.getElevation();
+ }
+
+ /**
+ * Updates the backward compatible elevation of the FloatingActionButton.
+ *
+ * @param elevation The backward compatible elevation in pixels.
+ * @attr ref android.support.design.R.styleable#FloatingActionButton_elevation
+ * @see #getFloatingActionButtonElevation()
+ * @see #setUseCompatPadding(boolean)
+ */
+ public void setFloatingActionButtonElevation(float elevation) {
+ mImpl.setElevation(elevation);
+ }
}
diff --git a/design/src/android/support/design/widget/HeaderBehavior.java b/design/src/android/support/design/widget/HeaderBehavior.java
new file mode 100644
index 0000000..9924d48
--- /dev/null
+++ b/design/src/android/support/design/widget/HeaderBehavior.java
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.support.design.widget.CoordinatorLayout.Behavior;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.VelocityTrackerCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.ScrollerCompat;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+/**
+ * The {@link Behavior} for a view that sits vertically above scrolling a view.
+ * See {@link HeaderScrollingViewBehavior}.
+ */
+abstract class HeaderBehavior<V extends View> extends ViewOffsetBehavior<V> {
+
+ private static final int INVALID_POINTER = -1;
+
+ private Runnable mFlingRunnable;
+ private ScrollerCompat mScroller;
+
+ private boolean mIsBeingDragged;
+ private int mActivePointerId = INVALID_POINTER;
+ private int mLastMotionY;
+ private int mTouchSlop = -1;
+ private VelocityTracker mVelocityTracker;
+
+ public HeaderBehavior() {}
+
+ public HeaderBehavior(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
+ if (mTouchSlop < 0) {
+ mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
+ }
+
+ final int action = ev.getAction();
+
+ // Shortcut since we're being dragged
+ if (action == MotionEvent.ACTION_MOVE && mIsBeingDragged) {
+ return true;
+ }
+
+ switch (MotionEventCompat.getActionMasked(ev)) {
+ case MotionEvent.ACTION_DOWN: {
+ mIsBeingDragged = false;
+ final int x = (int) ev.getX();
+ final int y = (int) ev.getY();
+ if (canDragView(child) && parent.isPointInChildBounds(child, x, y)) {
+ mLastMotionY = y;
+ mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
+ ensureVelocityTracker();
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_MOVE: {
+ final int activePointerId = mActivePointerId;
+ if (activePointerId == INVALID_POINTER) {
+ // If we don't have a valid id, the touch down wasn't on content.
+ break;
+ }
+ final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
+ if (pointerIndex == -1) {
+ break;
+ }
+
+ final int y = (int) MotionEventCompat.getY(ev, pointerIndex);
+ final int yDiff = Math.abs(y - mLastMotionY);
+ if (yDiff > mTouchSlop) {
+ mIsBeingDragged = true;
+ mLastMotionY = y;
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ mIsBeingDragged = false;
+ mActivePointerId = INVALID_POINTER;
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ break;
+ }
+ }
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(ev);
+ }
+
+ return mIsBeingDragged;
+ }
+
+ @Override
+ public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
+ if (mTouchSlop < 0) {
+ mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
+ }
+
+ switch (MotionEventCompat.getActionMasked(ev)) {
+ case MotionEvent.ACTION_DOWN: {
+ final int x = (int) ev.getX();
+ final int y = (int) ev.getY();
+
+ if (parent.isPointInChildBounds(child, x, y) && canDragView(child)) {
+ mLastMotionY = y;
+ mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
+ ensureVelocityTracker();
+ } else {
+ return false;
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_MOVE: {
+ final int activePointerIndex = MotionEventCompat.findPointerIndex(ev,
+ mActivePointerId);
+ if (activePointerIndex == -1) {
+ return false;
+ }
+
+ final int y = (int) MotionEventCompat.getY(ev, activePointerIndex);
+ int dy = mLastMotionY - y;
+
+ if (!mIsBeingDragged && Math.abs(dy) > mTouchSlop) {
+ mIsBeingDragged = true;
+ if (dy > 0) {
+ dy -= mTouchSlop;
+ } else {
+ dy += mTouchSlop;
+ }
+ }
+
+ if (mIsBeingDragged) {
+ mLastMotionY = y;
+ // We're being dragged so scroll the ABL
+ scroll(parent, child, dy, getMaxDragOffset(child), 0);
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_UP:
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(ev);
+ mVelocityTracker.computeCurrentVelocity(1000);
+ float yvel = VelocityTrackerCompat.getYVelocity(mVelocityTracker,
+ mActivePointerId);
+ fling(parent, child, -getScrollRangeForDragFling(child), 0, yvel);
+ }
+ // $FALLTHROUGH
+ case MotionEvent.ACTION_CANCEL: {
+ mIsBeingDragged = false;
+ mActivePointerId = INVALID_POINTER;
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ break;
+ }
+ }
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(ev);
+ }
+
+ return true;
+ }
+
+ int setHeaderTopBottomOffset(CoordinatorLayout parent, V header, int newOffset) {
+ return setHeaderTopBottomOffset(parent, header, newOffset,
+ Integer.MIN_VALUE, Integer.MAX_VALUE);
+ }
+
+ int setHeaderTopBottomOffset(CoordinatorLayout parent, V header, int newOffset,
+ int minOffset, int maxOffset) {
+ final int curOffset = getTopAndBottomOffset();
+ int consumed = 0;
+
+ if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
+ // If we have some scrolling range, and we're currently within the min and max
+ // offsets, calculate a new offset
+ newOffset = MathUtils.constrain(newOffset, minOffset, maxOffset);
+
+ if (curOffset != newOffset) {
+ setTopAndBottomOffset(newOffset);
+ // Update how much dy we have consumed
+ consumed = curOffset - newOffset;
+ }
+ }
+
+ return consumed;
+ }
+
+ int getTopBottomOffsetForScrollingSibling() {
+ return getTopAndBottomOffset();
+ }
+
+ final int scroll(CoordinatorLayout coordinatorLayout, V header,
+ int dy, int minOffset, int maxOffset) {
+ return setHeaderTopBottomOffset(coordinatorLayout, header,
+ getTopBottomOffsetForScrollingSibling() - dy, minOffset, maxOffset);
+ }
+
+ final boolean fling(CoordinatorLayout coordinatorLayout, V layout, int minOffset,
+ int maxOffset, float velocityY) {
+ if (mFlingRunnable != null) {
+ layout.removeCallbacks(mFlingRunnable);
+ mFlingRunnable = null;
+ }
+
+ if (mScroller == null) {
+ mScroller = ScrollerCompat.create(layout.getContext());
+ }
+
+ mScroller.fling(
+ 0, getTopAndBottomOffset(), // curr
+ 0, Math.round(velocityY), // velocity.
+ 0, 0, // x
+ minOffset, maxOffset); // y
+
+ if (mScroller.computeScrollOffset()) {
+ mFlingRunnable = new FlingRunnable(coordinatorLayout, layout);
+ ViewCompat.postOnAnimation(layout, mFlingRunnable);
+ return true;
+ } else {
+ onFlingFinished(coordinatorLayout, layout);
+ return false;
+ }
+ }
+
+ /**
+ * Called when a fling has finished, or the fling was initiated but there wasn't enough
+ * velocity to start it.
+ */
+ void onFlingFinished(CoordinatorLayout parent, V layout) {
+ // no-op
+ }
+
+ /**
+ * Return true if the view can be dragged.
+ */
+ boolean canDragView(V view) {
+ return false;
+ }
+
+ /**
+ * Returns the maximum px offset when {@code view} is being dragged.
+ */
+ int getMaxDragOffset(V view) {
+ return -view.getHeight();
+ }
+
+ int getScrollRangeForDragFling(V view) {
+ return view.getHeight();
+ }
+
+ private void ensureVelocityTracker() {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ }
+
+ private class FlingRunnable implements Runnable {
+ private final CoordinatorLayout mParent;
+ private final V mLayout;
+
+ FlingRunnable(CoordinatorLayout parent, V layout) {
+ mParent = parent;
+ mLayout = layout;
+ }
+
+ @Override
+ public void run() {
+ if (mLayout != null && mScroller != null) {
+ if (mScroller.computeScrollOffset()) {
+ setHeaderTopBottomOffset(mParent, mLayout, mScroller.getCurrY());
+ // Post ourselves so that we run on the next animation
+ ViewCompat.postOnAnimation(mLayout, this);
+ } else {
+ onFlingFinished(mParent, mLayout);
+ }
+ }
+ }
+ }
+}
diff --git a/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java b/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java
new file mode 100644
index 0000000..ac24ca2
--- /dev/null
+++ b/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.support.design.widget.CoordinatorLayout.Behavior;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+/**
+ * The {@link Behavior} for a scrolling view that is positioned vertically below another view.
+ * See {@link HeaderBehavior}.
+ */
+abstract class HeaderScrollingViewBehavior extends ViewOffsetBehavior<View> {
+
+ public HeaderScrollingViewBehavior() {}
+
+ public HeaderScrollingViewBehavior(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onMeasureChild(CoordinatorLayout parent, View child,
+ int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec,
+ int heightUsed) {
+ final int childLpHeight = child.getLayoutParams().height;
+ if (childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
+ || childLpHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ // If the menu's height is set to match_parent/wrap_content then measure it
+ // with the maximum visible height
+
+ final List<View> dependencies = parent.getDependencies(child);
+ if (dependencies.isEmpty()) {
+ // If we don't have any dependencies, return false
+ return false;
+ }
+
+ final View header = findFirstDependency(dependencies);
+ if (header != null && ViewCompat.isLaidOut(header)) {
+ if (ViewCompat.getFitsSystemWindows(header)) {
+ // If the header is fitting system windows then we need to also,
+ // otherwise we'll get CoL's compatible layout functionality
+ ViewCompat.setFitsSystemWindows(child, true);
+ }
+
+ int availableHeight = View.MeasureSpec.getSize(parentHeightMeasureSpec);
+ if (availableHeight == 0) {
+ // If the measure spec doesn't specify a size, use the current height
+ availableHeight = parent.getHeight();
+ }
+
+ final int height = availableHeight - header.getMeasuredHeight()
+ + getScrollRange(header);
+ final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height,
+ childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
+ ? View.MeasureSpec.EXACTLY
+ : View.MeasureSpec.AT_MOST);
+
+ // Now measure the scrolling menu with the correct height
+ parent.onMeasureChild(child, parentWidthMeasureSpec,
+ widthUsed, heightMeasureSpec, heightUsed);
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ abstract View findFirstDependency(List<View> views);
+
+ int getScrollRange(View v) {
+ return v.getMeasuredHeight();
+ }
+}
\ No newline at end of file
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
index 4e325fa..57882db 100644
--- a/design/src/android/support/design/widget/NavigationView.java
+++ b/design/src/android/support/design/widget/NavigationView.java
@@ -34,10 +34,12 @@
import android.support.design.internal.NavigationMenuPresenter;
import android.support.design.internal.ScrimInsetsFrameLayout;
import android.support.v4.content.ContextCompat;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.ViewCompat;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Menu;
@@ -95,6 +97,8 @@
public NavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ ThemeUtils.checkAppCompatTheme(context);
+
// Create the menu
mMenu = new NavigationMenu(context);
@@ -265,6 +269,26 @@
}
/**
+ * Gets the number of headers in this NavigationView.
+ *
+ * @return A positive integer representing the number of headers.
+ */
+ public int getHeaderCount() {
+ return mPresenter.getHeaderCount();
+ }
+
+ /**
+ * Gets the header view at the specified position.
+ *
+ * @param index The position at which to get the view from.
+ * @return The header view the specified position or null if the position does not exist in this
+ * NavigationView.
+ */
+ public View getHeaderView(int index) {
+ return mPresenter.getHeaderView(index);
+ }
+
+ /**
* Returns the tint which is applied to our item's icons.
*
* @see #setItemIconTintList(ColorStateList)
@@ -414,9 +438,9 @@
public static class SavedState extends BaseSavedState {
public Bundle menuState;
- public SavedState(Parcel in) {
+ public SavedState(Parcel in, ClassLoader loader) {
super(in);
- menuState = in.readBundle();
+ menuState = in.readBundle(loader);
}
public SavedState(Parcelable superState) {
@@ -430,17 +454,17 @@
}
public static final Parcelable.Creator<SavedState> CREATOR
- = new Parcelable.Creator<SavedState>() {
+ = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
@Override
- public SavedState createFromParcel(Parcel parcel) {
- return new SavedState(parcel);
+ public SavedState createFromParcel(Parcel parcel, ClassLoader loader) {
+ return new SavedState(parcel, loader);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
- };
+ });
}
}
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index b04c706..a328d98 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -169,18 +169,21 @@
});
}
- private final ViewGroup mParent;
+ private final ViewGroup mTargetParent;
private final Context mContext;
private final SnackbarLayout mView;
private int mDuration;
private Callback mCallback;
private Snackbar(ViewGroup parent) {
- mParent = parent;
+ mTargetParent = parent;
mContext = parent.getContext();
+ ThemeUtils.checkAppCompatTheme(mContext);
+
LayoutInflater inflater = LayoutInflater.from(mContext);
- mView = (SnackbarLayout) inflater.inflate(R.layout.design_layout_snackbar, mParent, false);
+ mView = (SnackbarLayout) inflater.inflate(
+ R.layout.design_layout_snackbar, mTargetParent, false);
}
/**
@@ -401,10 +404,18 @@
}
/**
- * Return whether this Snackbar is currently being shown.
+ * Return whether this {@link Snackbar} is currently being shown.
*/
public boolean isShown() {
- return mView.isShown();
+ return SnackbarManager.getInstance().isCurrent(mManagerCallback);
+ }
+
+ /**
+ * Returns whether this {@link Snackbar} is currently being shown, or is queued to be
+ * shown next.
+ */
+ public boolean isShownOrQueued() {
+ return SnackbarManager.getInstance().isCurrentOrNext(mManagerCallback);
}
private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
@@ -454,9 +465,30 @@
((CoordinatorLayout.LayoutParams) lp).setBehavior(behavior);
}
- mParent.addView(mView);
+ mTargetParent.addView(mView);
}
+ mView.setOnAttachStateChangeListener(new SnackbarLayout.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {}
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (isShownOrQueued()) {
+ // If we haven't already been dismissed then this event is coming from a
+ // non-user initiated action. Hence we need to make sure that we callback
+ // and keep our state up to date. We need to post the call since removeView()
+ // will call through to onDetachedFromWindow and thus overflow.
+ sHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onViewHidden(Callback.DISMISS_EVENT_MANUAL);
+ }
+ });
+ }
+ }
+ });
+
if (ViewCompat.isLaidOut(mView)) {
// If the view is already laid out, animate it now
animateViewIn();
@@ -475,7 +507,8 @@
private void animateViewIn() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
ViewCompat.setTranslationY(mView, mView.getHeight());
- ViewCompat.animate(mView).translationY(0f)
+ ViewCompat.animate(mView)
+ .translationY(0f)
.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
.setDuration(ANIMATION_DURATION)
.setListener(new ViewPropertyAnimatorListenerAdapter() {
@@ -494,7 +527,8 @@
}
}).start();
} else {
- Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.design_snackbar_in);
+ Animation anim = AnimationUtils.loadAnimation(mView.getContext(),
+ R.anim.design_snackbar_in);
anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
anim.setDuration(ANIMATION_DURATION);
anim.setAnimationListener(new Animation.AnimationListener() {
@@ -518,7 +552,8 @@
private void animateViewOut(final int event) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- ViewCompat.animate(mView).translationY(mView.getHeight())
+ ViewCompat.animate(mView)
+ .translationY(mView.getHeight())
.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR)
.setDuration(ANIMATION_DURATION)
.setListener(new ViewPropertyAnimatorListenerAdapter() {
@@ -561,14 +596,17 @@
}
private void onViewHidden(int event) {
- // First remove the view from the parent
- mParent.removeView(mView);
+ // First tell the SnackbarManager that it has been dismissed
+ SnackbarManager.getInstance().onDismissed(mManagerCallback);
// Now call the dismiss listener (if available)
if (mCallback != null) {
mCallback.onDismissed(this, event);
}
- // Finally, tell the SnackbarManager that it has been dismissed
- SnackbarManager.getInstance().onDismissed(mManagerCallback);
+ // Lastly, remove the view from the parent (if attached)
+ final ViewParent parent = mView.getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(mView);
+ }
}
/**
@@ -600,10 +638,16 @@
private int mMaxInlineActionWidth;
interface OnLayoutChangeListener {
- public void onLayoutChange(View view, int left, int top, int right, int bottom);
+ void onLayoutChange(View view, int left, int top, int right, int bottom);
+ }
+
+ interface OnAttachStateChangeListener {
+ void onViewAttachedToWindow(View v);
+ void onViewDetachedFromWindow(View v);
}
private OnLayoutChangeListener mOnLayoutChangeListener;
+ private OnAttachStateChangeListener mOnAttachStateChangeListener;
public SnackbarLayout(Context context) {
this(context, null);
@@ -627,6 +671,9 @@
// in the layout since older versions of the Android do not inflate includes with
// the correct Context.
LayoutInflater.from(context).inflate(R.layout.design_layout_snackbar_include, this);
+
+ ViewCompat.setAccessibilityLiveRegion(this,
+ ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
}
@Override
@@ -710,10 +757,30 @@
}
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mOnAttachStateChangeListener != null) {
+ mOnAttachStateChangeListener.onViewAttachedToWindow(this);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mOnAttachStateChangeListener != null) {
+ mOnAttachStateChangeListener.onViewDetachedFromWindow(this);
+ }
+ }
+
void setOnLayoutChangeListener(OnLayoutChangeListener onLayoutChangeListener) {
mOnLayoutChangeListener = onLayoutChangeListener;
}
+ void setOnAttachStateChangeListener(OnAttachStateChangeListener listener) {
+ mOnAttachStateChangeListener = listener;
+ }
+
private boolean updateViewsWithinLayout(final int orientation,
final int messagePadTop, final int messagePadBottom) {
boolean changed = false;
@@ -743,6 +810,11 @@
final class Behavior extends SwipeDismissBehavior<SnackbarLayout> {
@Override
+ public boolean canSwipeDismissView(View child) {
+ return child instanceof SnackbarLayout;
+ }
+
+ @Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, SnackbarLayout child,
MotionEvent event) {
// We want to make sure that we disable any Snackbar timeouts if the user is
diff --git a/design/src/android/support/design/widget/SnackbarManager.java b/design/src/android/support/design/widget/SnackbarManager.java
index 253ee92..be2f024 100644
--- a/design/src/android/support/design/widget/SnackbarManager.java
+++ b/design/src/android/support/design/widget/SnackbarManager.java
@@ -69,7 +69,7 @@
public void show(int duration, Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
// Means that the callback is already in the queue. We'll just update the duration
mCurrentSnackbar.duration = duration;
@@ -78,7 +78,7 @@
mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
scheduleTimeoutLocked(mCurrentSnackbar);
return;
- } else if (isNextSnackbar(callback)) {
+ } else if (isNextSnackbarLocked(callback)) {
// We'll just update the duration
mNextSnackbar.duration = duration;
} else {
@@ -101,9 +101,9 @@
public void dismiss(Callback callback, int event) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
cancelSnackbarLocked(mCurrentSnackbar, event);
- } else if (isNextSnackbar(callback)) {
+ } else if (isNextSnackbarLocked(callback)) {
cancelSnackbarLocked(mNextSnackbar, event);
}
}
@@ -115,7 +115,7 @@
*/
public void onDismissed(Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
// If the callback is from a Snackbar currently show, remove it and show a new one
mCurrentSnackbar = null;
if (mNextSnackbar != null) {
@@ -131,7 +131,7 @@
*/
public void onShown(Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
scheduleTimeoutLocked(mCurrentSnackbar);
}
}
@@ -139,7 +139,7 @@
public void cancelTimeout(Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
}
}
@@ -147,12 +147,24 @@
public void restoreTimeout(Callback callback) {
synchronized (mLock) {
- if (isCurrentSnackbar(callback)) {
+ if (isCurrentSnackbarLocked(callback)) {
scheduleTimeoutLocked(mCurrentSnackbar);
}
}
}
+ public boolean isCurrent(Callback callback) {
+ synchronized (mLock) {
+ return isCurrentSnackbarLocked(callback);
+ }
+ }
+
+ public boolean isCurrentOrNext(Callback callback) {
+ synchronized (mLock) {
+ return isCurrentSnackbarLocked(callback) || isNextSnackbarLocked(callback);
+ }
+ }
+
private static class SnackbarRecord {
private final WeakReference<Callback> callback;
private int duration;
@@ -191,11 +203,11 @@
return false;
}
- private boolean isCurrentSnackbar(Callback callback) {
+ private boolean isCurrentSnackbarLocked(Callback callback) {
return mCurrentSnackbar != null && mCurrentSnackbar.isSnackbar(callback);
}
- private boolean isNextSnackbar(Callback callback) {
+ private boolean isNextSnackbarLocked(Callback callback) {
return mNextSnackbar != null && mNextSnackbar.isSnackbar(callback);
}
diff --git a/design/src/android/support/design/widget/SwipeDismissBehavior.java b/design/src/android/support/design/widget/SwipeDismissBehavior.java
index fc29201..e059fe5 100644
--- a/design/src/android/support/design/widget/SwipeDismissBehavior.java
+++ b/design/src/android/support/design/widget/SwipeDismissBehavior.java
@@ -17,6 +17,7 @@
package android.support.design.widget;
import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
@@ -198,13 +199,27 @@
return false;
}
+ /**
+ * Called when the user's input indicates that they want to swipe the given view.
+ *
+ * @param view View the user is attempting to swipe
+ * @return true if the view can be dismissed via swiping, false otherwise
+ */
+ public boolean canSwipeDismissView(@NonNull View view) {
+ return true;
+ }
+
private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
private int mOriginalCapturedViewLeft;
@Override
public boolean tryCaptureView(View child, int pointerId) {
- mOriginalCapturedViewLeft = child.getLeft();
- return true;
+ return canSwipeDismissView(child);
+ }
+
+ @Override
+ public void onViewCaptured(View capturedChild, int activePointerId) {
+ mOriginalCapturedViewLeft = capturedChild.getLeft();
}
@Override
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 7eee77b..fe1a105 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -19,7 +19,9 @@
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
@@ -32,14 +34,18 @@
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.R;
+import android.support.v4.util.Pools;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPager;
+import android.support.v4.widget.TextViewCompat;
import android.support.v7.app.ActionBar;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v7.widget.AppCompatDrawableManager;
+import android.text.Layout;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -81,20 +87,16 @@
* notified when any tab's selection state has been changed.
* <p>
* If you're using a {@link android.support.v4.view.ViewPager} together
- * with this layout, you can use {@link #setTabsFromPagerAdapter(PagerAdapter)} which will populate
- * the tabs using the given {@link PagerAdapter}'s page titles. You should also use a
- * {@link TabLayoutOnPageChangeListener} to forward the scroll and selection changes to this
- * layout like so:
- * <pre>
- * ViewPager viewPager = ...;
- * TabLayout tabLayout = ...;
- * viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(tabLayout));
- * </pre>
+ * with this layout, you can use {@link #setupWithViewPager(ViewPager)} to link the two together.
+ * This layout will be automatically populated from the {@link PagerAdapter}'s page titles.</p>
*
* @see <a href="http://www.google.com/design/spec/components/tabs.html">Tabs</a>
*/
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
+ 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
@@ -102,6 +104,8 @@
private static final int ANIMATION_DURATION = 300;
+ private static final Pools.Pool<Tab> sTabPool = new Pools.SynchronizedPool<>(16);
+
/**
* Scrollable tabs display a subset of tabs at any given moment, and can contain longer tab
* labels and a larger number of tabs. They are best used for browsing contexts in touch
@@ -193,12 +197,15 @@
private int mTabTextAppearance;
private ColorStateList mTabTextColors;
+ private float mTabTextSize;
+ private float mTabTextMultiLineSize;
private final int mTabBackgroundResId;
- private final int mTabMinWidth;
private int mTabMaxWidth = Integer.MAX_VALUE;
+ private final int mRequestedTabMinWidth;
private final int mRequestedTabMaxWidth;
+ private final int mScrollableTabMinWidth;
private int mContentInsetStart;
@@ -209,7 +216,14 @@
private View.OnClickListener mTabClickListener;
private ValueAnimatorCompat mScrollAnimator;
- private ValueAnimatorCompat mIndicatorAnimator;
+
+ private ViewPager mViewPager;
+ private PagerAdapter mPagerAdapter;
+ private DataSetObserver mPagerAdapterObserver;
+ private TabLayoutOnPageChangeListener mPageChangeListener;
+
+ // Pool we use as a simple RecyclerBin
+ private final Pools.Pool<TabView> mTabViewPool = new Pools.SimplePool<>(12);
public TabLayout(Context context) {
this(context, null);
@@ -222,10 +236,10 @@
public TabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ ThemeUtils.checkAppCompatTheme(context);
+
// Disable the Scroll Bar
setHorizontalScrollBarEnabled(false);
- // Set us to fill the View port
- setFillViewport(true);
// Add the TabStrip
mTabStrip = new SlidingTabStrip(context);
@@ -238,9 +252,6 @@
a.getDimensionPixelSize(R.styleable.TabLayout_tabIndicatorHeight, 0));
mTabStrip.setSelectedIndicatorColor(a.getColor(R.styleable.TabLayout_tabIndicatorColor, 0));
- mTabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,
- R.style.TextAppearance_Design_Tab);
-
mTabPaddingStart = mTabPaddingTop = mTabPaddingEnd = mTabPaddingBottom = a
.getDimensionPixelSize(R.styleable.TabLayout_tabPadding, 0);
mTabPaddingStart = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingStart,
@@ -252,8 +263,18 @@
mTabPaddingBottom = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingBottom,
mTabPaddingBottom);
- // Text colors come from the text appearance first
- mTabTextColors = loadTextColorFromTextAppearance(mTabTextAppearance);
+ mTabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,
+ R.style.TextAppearance_Design_Tab);
+
+ // Text colors/sizes come from the text appearance first
+ final TypedArray ta = context.obtainStyledAttributes(mTabTextAppearance,
+ R.styleable.TextAppearance);
+ try {
+ mTabTextSize = ta.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, 0);
+ mTabTextColors = ta.getColorStateList(R.styleable.TextAppearance_android_textColor);
+ } finally {
+ ta.recycle();
+ }
if (a.hasValue(R.styleable.TabLayout_tabTextColor)) {
// If we have an explicit text color set, use it instead
@@ -268,14 +289,21 @@
mTabTextColors = createColorStateList(mTabTextColors.getDefaultColor(), selected);
}
- mTabMinWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMinWidth, 0);
- mRequestedTabMaxWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMaxWidth, 0);
+ mRequestedTabMinWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMinWidth,
+ INVALID_WIDTH);
+ mRequestedTabMaxWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMaxWidth,
+ INVALID_WIDTH);
mTabBackgroundResId = a.getResourceId(R.styleable.TabLayout_tabBackground, 0);
mContentInsetStart = a.getDimensionPixelSize(R.styleable.TabLayout_tabContentStart, 0);
mMode = a.getInt(R.styleable.TabLayout_tabMode, MODE_FIXED);
mTabGravity = a.getInt(R.styleable.TabLayout_tabGravity, GRAVITY_FILL);
a.recycle();
+ // TODO add attr for these
+ final Resources res = getResources();
+ mTabTextMultiLineSize = res.getDimensionPixelSize(R.dimen.design_tab_text_size_2line);
+ mScrollableTabMinWidth = res.getDimensionPixelSize(R.dimen.design_tab_scrollable_min_width);
+
// Now apply the tab mode and gravity
applyModeAndGravity();
}
@@ -309,20 +337,30 @@
* @param updateSelectedText Whether to update the text's selected state.
*/
public void setScrollPosition(int position, float positionOffset, boolean updateSelectedText) {
- if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
- return;
- }
- if (position < 0 || position >= mTabStrip.getChildCount()) {
+ setScrollPosition(position, positionOffset, updateSelectedText, true);
+ }
+
+ private void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
+ boolean updateIndicatorPosition) {
+ final int roundedPosition = Math.round(position + positionOffset);
+ if (roundedPosition < 0 || roundedPosition >= mTabStrip.getChildCount()) {
return;
}
- // Set the indicator position and update the scroll to match
- mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);
+ // Set the indicator position, if enabled
+ if (updateIndicatorPosition) {
+ mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);
+ }
+
+ // Now update the scroll position, canceling any running animation
+ if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
+ mScrollAnimator.cancel();
+ }
scrollTo(calculateScrollXForTab(position, positionOffset), 0);
- // Update the 'selected state' view as we scroll
+ // Update the 'selected state' view as we scroll, if enabled
if (updateSelectedText) {
- setSelectedTabView(Math.round(position + positionOffset));
+ setSelectedTabView(roundedPosition);
}
}
@@ -407,7 +445,8 @@
*/
@NonNull
public Tab newTab() {
- return new Tab(this);
+ final Tab poolTab = sTabPool.acquire();
+ return poolTab != null ? poolTab : new Tab(this);
}
/**
@@ -460,9 +499,10 @@
final int selectedTabPosition = mSelectedTab != null ? mSelectedTab.getPosition() : 0;
removeTabViewAt(position);
- Tab removedTab = mTabs.remove(position);
+ final Tab removedTab = mTabs.remove(position);
if (removedTab != null) {
- removedTab.setPosition(Tab.INVALID_POSITION);
+ removedTab.reset();
+ sTabPool.release(removedTab);
}
final int newTabCount = mTabs.size();
@@ -480,12 +520,15 @@
*/
public void removeAllTabs() {
// Remove all the views
- mTabStrip.removeAllViews();
+ for (int i = mTabStrip.getChildCount() - 1; i >= 0; i--) {
+ removeTabViewAt(i);
+ }
- for (Iterator<Tab> i = mTabs.iterator(); i.hasNext(); ) {
- Tab tab = i.next();
- tab.setPosition(Tab.INVALID_POSITION);
+ for (final Iterator<Tab> i = mTabs.iterator(); i.hasNext();) {
+ final Tab tab = i.next();
i.remove();
+ tab.reset();
+ sTabPool.release(tab);
}
mSelectedTab = null;
@@ -571,57 +614,102 @@
/**
* The one-stop shop for setting up this {@link TabLayout} with a {@link ViewPager}.
*
- * <p>This method will:
- * <ul>
- * <li>Add a {@link ViewPager.OnPageChangeListener} that will forward events to
- * this TabLayout.</li>
- * <li>Populate the TabLayout's tabs from the ViewPager's {@link PagerAdapter}.</li>
- * <li>Set our {@link TabLayout.OnTabSelectedListener} which will forward
- * selected events to the ViewPager</li>
- * </ul>
- * </p>
+ * <p>This method will link the given ViewPager and this TabLayout together so that any
+ * changes in one are automatically reflected in the other. This includes adapter changes,
+ * scroll state changes, and clicks. The tabs displayed in this layout will be populated
+ * from the ViewPager adapter's page titles.</p>
*
- * @see #setTabsFromPagerAdapter(PagerAdapter)
- * @see TabLayoutOnPageChangeListener
- * @see ViewPagerOnTabSelectedListener
+ * <p>After this method is called, you will not need this method again unless you want
+ * to change the linked ViewPager.</p>
+ *
+ * <p>If the given ViewPager is non-null, it needs to already have a
+ * {@link PagerAdapter} set.</p>
+ *
+ * @param viewPager The ViewPager to link, or {@code null} to clear any previous link.
*/
- public void setupWithViewPager(@NonNull ViewPager viewPager) {
- final PagerAdapter adapter = viewPager.getAdapter();
- if (adapter == null) {
- throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
+ public void setupWithViewPager(@Nullable final ViewPager viewPager) {
+ if (mViewPager != null && mPageChangeListener != null) {
+ // If we've already been setup with a ViewPager, remove us from it
+ mViewPager.removeOnPageChangeListener(mPageChangeListener);
}
- // First we'll add Tabs, using the adapter's page titles
- setTabsFromPagerAdapter(adapter);
-
- // Now we'll add our page change listener to the ViewPager
- viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(this));
-
- // Now we'll add a tab selected listener to set ViewPager's current item
- setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
-
- // Make sure we reflect the currently set ViewPager item
- if (adapter.getCount() > 0) {
- final int curItem = viewPager.getCurrentItem();
- if (getSelectedTabPosition() != curItem) {
- selectTab(getTabAt(curItem));
+ if (viewPager != null) {
+ final PagerAdapter adapter = viewPager.getAdapter();
+ if (adapter == null) {
+ throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
}
+
+ mViewPager = viewPager;
+
+ // Add our custom OnPageChangeListener to the ViewPager
+ if (mPageChangeListener == null) {
+ mPageChangeListener = new TabLayoutOnPageChangeListener(this);
+ }
+ mPageChangeListener.reset();
+ viewPager.addOnPageChangeListener(mPageChangeListener);
+
+ // Now we'll add a tab selected listener to set ViewPager's current item
+ setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
+
+ // Now we'll populate ourselves from the pager adapter
+ setPagerAdapter(adapter, true);
+ } else {
+ // We've been given a null ViewPager so we need to clear out the internal state,
+ // listeners and observers
+ mViewPager = null;
+ setOnTabSelectedListener(null);
+ setPagerAdapter(null, true);
}
}
/**
- * Populate our tab content from the given {@link PagerAdapter}.
- * <p>
- * Any existing tabs will be removed first. Each tab will have it's text set to the value
- * returned from {@link PagerAdapter#getPageTitle(int)}
- * </p>
- *
- * @param adapter the adapter to populate from
+ * @deprecated Use {@link #setupWithViewPager(ViewPager)} to link a TabLayout with a ViewPager
+ * together. When that method is used, the TabLayout will be automatically updated
+ * when the {@link PagerAdapter} is changed.
*/
- public void setTabsFromPagerAdapter(@NonNull PagerAdapter adapter) {
+ @Deprecated
+ public void setTabsFromPagerAdapter(@Nullable final PagerAdapter adapter) {
+ setPagerAdapter(adapter, false);
+ }
+
+ private 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);
+ }
+
+ mPagerAdapter = adapter;
+
+ if (addObserver && adapter != null) {
+ // Register our observer on the new adapter
+ if (mPagerAdapterObserver == null) {
+ mPagerAdapterObserver = new PagerAdapterObserver();
+ }
+ adapter.registerDataSetObserver(mPagerAdapterObserver);
+ }
+
+ // Finally make sure we reflect the new adapter
+ populateFromPagerAdapter();
+ }
+
+ private void populateFromPagerAdapter() {
removeAllTabs();
- for (int i = 0, count = adapter.getCount(); i < count; i++) {
- addTab(newTab().setText(adapter.getPageTitle(i)));
+
+ if (mPagerAdapter != null) {
+ final int adapterCount = mPagerAdapter.getCount();
+ for (int i = 0; i < adapterCount; i++) {
+ addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
+ }
+
+ // Make sure we reflect the currently set ViewPager item
+ if (mViewPager != null && adapterCount > 0) {
+ final int curItem = mViewPager.getCurrentItem();
+ if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
+ selectTab(getTabAt(curItem));
+ }
+ }
+ } else {
+ removeAllTabs();
}
}
@@ -631,9 +719,14 @@
}
}
- private TabView createTabView(Tab tab) {
- final TabView tabView = new TabView(getContext(), tab);
+ private TabView createTabView(@NonNull final Tab tab) {
+ TabView tabView = mTabViewPool != null ? mTabViewPool.acquire() : null;
+ if (tabView == null) {
+ tabView = new TabView(getContext());
+ }
+ tabView.setTab(tab);
tabView.setFocusable(true);
+ tabView.setMinimumWidth(getTabMinWidth());
if (mTabClickListener == null) {
mTabClickListener = new View.OnClickListener() {
@@ -659,12 +752,16 @@
}
private void updateTab(int position) {
- final TabView view = (TabView) mTabStrip.getChildAt(position);
+ final TabView view = getTabView(position);
if (view != null) {
view.update();
}
}
+ private TabView getTabView(int position) {
+ return (TabView) mTabStrip.getChildAt(position);
+ }
+
private void addTabView(Tab tab, boolean setSelected) {
final TabView tabView = createTabView(tab);
mTabStrip.addView(tabView, createLayoutParamsForTabs());
@@ -706,7 +803,7 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// If we have a MeasureSpec which allows us to decide our height, try and use the default
// height
- final int idealHeight = dpToPx(DEFAULT_HEIGHT) + getPaddingTop() + getPaddingBottom();
+ final int idealHeight = dpToPx(getDefaultHeight()) + getPaddingTop() + getPaddingBottom();
switch (MeasureSpec.getMode(heightMeasureSpec)) {
case MeasureSpec.AT_MOST:
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -718,43 +815,54 @@
break;
}
+ final int specWidth = MeasureSpec.getSize(widthMeasureSpec);
+ if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
+ // If we don't have an unspecified width spec, use the given size to calculate
+ // the max tab width
+ mTabMaxWidth = mRequestedTabMaxWidth > 0
+ ? mRequestedTabMaxWidth
+ : specWidth - dpToPx(TAB_MIN_WIDTH_MARGIN);
+ }
+
// Now super measure itself using the (possibly) modified height spec
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mMode == MODE_FIXED && getChildCount() == 1) {
+ if (getChildCount() == 1) {
// If we're in fixed mode then we need to make the tab strip is the same width as us
// so we don't scroll
final View child = getChildAt(0);
- final int width = getMeasuredWidth();
+ boolean remeasure = false;
- if (child.getMeasuredWidth() > width) {
- // If the child is wider than us, re-measure it with a widthSpec set to exact our
- // measure width
+ switch (mMode) {
+ case MODE_SCROLLABLE:
+ // We only need to resize the child if it's smaller than us. This is similar
+ // to fillViewport
+ remeasure = child.getMeasuredWidth() < getMeasuredWidth();
+ break;
+ case MODE_FIXED:
+ // Resize the child so that it doesn't scroll
+ remeasure = child.getMeasuredWidth() != getMeasuredWidth();
+ break;
+ }
+
+ if (remeasure) {
+ // Re-measure the child with a widthSpec set to be exactly our measure width
int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTop()
+ getPaddingBottom(), child.getLayoutParams().height);
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ getMeasuredWidth(), MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
-
- // Now update the tab max width. We do it here as the default tab min width is
- // layout width - 56dp
- int maxTabWidth = mRequestedTabMaxWidth;
- final int defaultTabMaxWidth = getMeasuredWidth() - dpToPx(TAB_MIN_WIDTH_MARGIN);
- if (maxTabWidth == 0 || maxTabWidth > defaultTabMaxWidth) {
- // If the request tab max width is 0, or larger than our default, use the default
- maxTabWidth = defaultTabMaxWidth;
- }
-
- if (mTabMaxWidth != maxTabWidth) {
- // If the tab max width has changed, re-measure
- mTabMaxWidth = maxTabWidth;
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
}
private void removeTabViewAt(int position) {
+ final TabView view = (TabView) mTabStrip.getChildAt(position);
mTabStrip.removeViewAt(position);
+ if (view != null) {
+ view.reset();
+ mTabViewPool.release(view);
+ }
requestLayout();
}
@@ -818,9 +926,11 @@
animateToTab(tab.getPosition());
}
} else {
- final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
- setSelectedTabView(newPosition);
if (updateIndicator) {
+ final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
+ if (newPosition != Tab.INVALID_POSITION) {
+ setSelectedTabView(newPosition);
+ }
if ((mSelectedTab == null || mSelectedTab.getPosition() == Tab.INVALID_POSITION)
&& newPosition != Tab.INVALID_POSITION) {
// If we don't currently have a tab, just draw the indicator
@@ -873,14 +983,17 @@
break;
}
- updateTabViewsLayoutParams();
+ updateTabViews(true);
}
- private void updateTabViewsLayoutParams() {
+ private void updateTabViews(final boolean requestLayout) {
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
View child = mTabStrip.getChildAt(i);
+ child.setMinimumWidth(getTabMinWidth());
updateTabViewLayoutParams((LinearLayout.LayoutParams) child.getLayoutParams());
- child.requestLayout();
+ if (requestLayout) {
+ child.requestLayout();
+ }
}
}
@@ -973,13 +1086,14 @@
* the value given to {@link #setIcon(Drawable)}.
* </p>
*
- * @param layoutResId A layout resource to inflate and use as a custom tab view
+ * @param resId A layout resource to inflate and use as a custom tab view
* @return The current instance for call chaining
*/
@NonNull
- public Tab setCustomView(@LayoutRes int layoutResId) {
- return setCustomView(
- LayoutInflater.from(mParent.getContext()).inflate(layoutResId, null));
+ public Tab setCustomView(@LayoutRes int resId) {
+ final TabView tabView = mParent.getTabView(mPosition);
+ final LayoutInflater inflater = LayoutInflater.from(tabView.getContext());
+ return setCustomView(inflater.inflate(resId, tabView, false));
}
/**
@@ -1039,7 +1153,7 @@
*/
@NonNull
public Tab setIcon(@DrawableRes int resId) {
- return setIcon(TintManager.getDrawable(mParent.getContext(), resId));
+ return setIcon(AppCompatDrawableManager.get().getDrawable(mParent.getContext(), resId));
}
/**
@@ -1127,10 +1241,19 @@
public CharSequence getContentDescription() {
return mContentDesc;
}
+
+ private void reset() {
+ mTag = null;
+ mIcon = null;
+ mText = null;
+ mContentDesc = null;
+ mPosition = INVALID_POSITION;
+ mCustomView = null;
+ }
}
class TabView extends LinearLayout implements OnLongClickListener {
- private final Tab mTab;
+ private Tab mTab;
private TextView mTextView;
private ImageView mIconView;
@@ -1138,16 +1261,18 @@
private TextView mCustomTextView;
private ImageView mCustomIconView;
- public TabView(Context context, Tab tab) {
+ private int mDefaultMaxLines = 2;
+
+ public TabView(Context context) {
super(context);
- mTab = tab;
if (mTabBackgroundResId != 0) {
- setBackgroundDrawable(TintManager.getDrawable(context, mTabBackgroundResId));
+ setBackgroundDrawable(
+ AppCompatDrawableManager.get().getDrawable(context, mTabBackgroundResId));
}
ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,
mTabPaddingEnd, mTabPaddingBottom);
setGravity(Gravity.CENTER);
- update();
+ setOrientation(VERTICAL);
}
@Override
@@ -1183,22 +1308,85 @@
}
@Override
- public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ public void onMeasure(final int origWidthMeasureSpec, final int origHeightMeasureSpec) {
+ final int specWidthSize = MeasureSpec.getSize(origWidthMeasureSpec);
+ final int specWidthMode = MeasureSpec.getMode(origWidthMeasureSpec);
+ final int maxWidth = getTabMaxWidth();
+
+ final int widthMeasureSpec;
+ final int heightMeasureSpec = origHeightMeasureSpec;
+
+ if (maxWidth > 0 && (specWidthMode == MeasureSpec.UNSPECIFIED
+ || specWidthSize > maxWidth)) {
+ // If we have a max width and a given spec which is either unspecified or
+ // larger than the max width, update the width spec using the same mode
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(mTabMaxWidth, specWidthMode);
+ } else {
+ // Else, use the original width spec
+ widthMeasureSpec = origWidthMeasureSpec;
+ }
+
+ // Now lets measure
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- final int measuredWidth = getMeasuredWidth();
- if (measuredWidth < mTabMinWidth || measuredWidth > mTabMaxWidth) {
- // Re-measure if we are outside our min or max width
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- MathUtils.constrain(measuredWidth, mTabMinWidth, mTabMaxWidth),
- MeasureSpec.EXACTLY);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ // We need to switch the text size based on whether the text is spanning 2 lines or not
+ if (mTextView != null) {
+ final Resources res = getResources();
+ float textSize = mTabTextSize;
+ int maxLines = mDefaultMaxLines;
+
+ if (mIconView != null && mIconView.getVisibility() == VISIBLE) {
+ // If the icon view is being displayed, we limit the text to 1 line
+ maxLines = 1;
+ } else if (mTextView != null && mTextView.getLineCount() > 1) {
+ // Otherwise when we have text which wraps we reduce the text size
+ textSize = mTabTextMultiLineSize;
+ }
+
+ final float curTextSize = mTextView.getTextSize();
+ final int curLineCount = mTextView.getLineCount();
+ final int curMaxLines = TextViewCompat.getMaxLines(mTextView);
+
+ if (textSize != curTextSize || (curMaxLines >= 0 && maxLines != curMaxLines)) {
+ // We've got a new text size and/or max lines...
+ boolean updateTextView = true;
+
+ if (mMode == MODE_FIXED && textSize > curTextSize && curLineCount == 1) {
+ // If we're in fixed mode, going up in text size and currently have 1 line
+ // then it's very easy to get into an infinite recursion.
+ // To combat that we check to see if the change in text size
+ // will cause a line count change. If so, abort the size change.
+ final Layout layout = mTextView.getLayout();
+ if (layout == null
+ || approximateLineWidth(layout, 0, textSize) > layout.getWidth()) {
+ updateTextView = false;
+ }
+ }
+
+ if (updateTextView) {
+ mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+ mTextView.setMaxLines(maxLines);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
}
}
+ private void setTab(@Nullable final Tab tab) {
+ if (tab != mTab) {
+ mTab = tab;
+ update();
+ }
+ }
+
+ private void reset() {
+ setTab(null);
+ setSelected(false);
+ }
+
final void update() {
final Tab tab = mTab;
- final View custom = tab.getCustomView();
+ final View custom = tab != null ? tab.getCustomView() : null;
if (custom != null) {
final ViewParent customParent = custom.getParent();
if (customParent != this) {
@@ -1217,6 +1405,9 @@
}
mCustomTextView = (TextView) custom.findViewById(android.R.id.text1);
+ if (mCustomTextView != null) {
+ mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView);
+ }
mCustomIconView = (ImageView) custom.findViewById(android.R.id.icon);
} else {
// We do not have a custom view. Remove one if it already exists
@@ -1241,23 +1432,26 @@
.inflate(R.layout.design_layout_tab_text, this, false);
addView(textView);
mTextView = textView;
+ mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
}
mTextView.setTextAppearance(getContext(), mTabTextAppearance);
if (mTabTextColors != null) {
mTextView.setTextColor(mTabTextColors);
}
- updateTextAndIcon(tab, mTextView, mIconView);
+ updateTextAndIcon(mTextView, mIconView);
} else {
// Else, we'll see if there is a TextView or ImageView present and update them
if (mCustomTextView != null || mCustomIconView != null) {
- updateTextAndIcon(tab, mCustomTextView, mCustomIconView);
+ updateTextAndIcon(mCustomTextView, mCustomIconView);
}
}
}
- private void updateTextAndIcon(Tab tab, TextView textView, ImageView iconView) {
- final Drawable icon = tab.getIcon();
- final CharSequence text = tab.getText();
+ private void updateTextAndIcon(@Nullable final TextView textView,
+ @Nullable final ImageView iconView) {
+ final Drawable icon = mTab != null ? mTab.getIcon() : null;
+ final CharSequence text = mTab != null ? mTab.getText() : null;
+ final CharSequence contentDesc = mTab != null ? mTab.getContentDescription() : null;
if (iconView != null) {
if (icon != null) {
@@ -1268,23 +1462,36 @@
iconView.setVisibility(GONE);
iconView.setImageDrawable(null);
}
- iconView.setContentDescription(tab.getContentDescription());
+ iconView.setContentDescription(contentDesc);
}
final boolean hasText = !TextUtils.isEmpty(text);
if (textView != null) {
if (hasText) {
textView.setText(text);
- textView.setContentDescription(tab.getContentDescription());
textView.setVisibility(VISIBLE);
setVisibility(VISIBLE);
} else {
textView.setVisibility(GONE);
textView.setText(null);
}
+ textView.setContentDescription(contentDesc);
}
- if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
+ if (iconView != null) {
+ MarginLayoutParams lp = ((MarginLayoutParams) iconView.getLayoutParams());
+ int bottomMargin = 0;
+ if (hasText && iconView.getVisibility() == VISIBLE) {
+ // If we're showing both text and icon, add some margin bottom to the icon
+ bottomMargin = dpToPx(DEFAULT_GAP_TEXT_ICON);
+ }
+ if (bottomMargin != lp.bottomMargin) {
+ lp.bottomMargin = bottomMargin;
+ iconView.requestLayout();
+ }
+ }
+
+ if (!hasText && !TextUtils.isEmpty(contentDesc)) {
setOnLongClickListener(this);
} else {
setOnLongClickListener(null);
@@ -1315,6 +1522,13 @@
public Tab getTab() {
return mTab;
}
+
+ /**
+ * Approximates a given lines width with the new provided text size.
+ */
+ private float approximateLineWidth(Layout layout, int line, float textSize) {
+ return layout.getLineWidth(line) * (textSize / layout.getPaint().getTextSize());
+ }
}
private class SlidingTabStrip extends LinearLayout {
@@ -1327,6 +1541,8 @@
private int mIndicatorLeft = -1;
private int mIndicatorRight = -1;
+ private ValueAnimatorCompat mIndicatorAnimator;
+
SlidingTabStrip(Context context) {
super(context);
setWillNotDraw(false);
@@ -1358,6 +1574,10 @@
}
void setIndicatorPositionFromTabPosition(int position, float positionOffset) {
+ if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
+ mIndicatorAnimator.cancel();
+ }
+
mSelectedPosition = position;
mSelectionOffset = positionOffset;
updateIndicatorPosition();
@@ -1380,14 +1600,13 @@
if (mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER) {
final int count = getChildCount();
- final int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-
- // First we'll find the largest tab
+ // First we'll find the widest tab
int largestTabWidth = 0;
for (int i = 0, z = count; i < z; i++) {
- final View child = getChildAt(i);
- child.measure(unspecifiedSpec, heightMeasureSpec);
- largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());
+ View child = getChildAt(i);
+ if (child.getVisibility() == VISIBLE) {
+ largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());
+ }
}
if (largestTabWidth <= 0) {
@@ -1396,32 +1615,50 @@
}
final int gutter = dpToPx(FIXED_WRAP_GUTTER_MIN);
+ boolean remeasure = false;
+
if (largestTabWidth * count <= getMeasuredWidth() - gutter * 2) {
// If the tabs fit within our width minus gutters, we will set all tabs to have
// the same width
for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- final LinearLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.width = largestTabWidth;
- lp.weight = 0;
+ final LinearLayout.LayoutParams lp =
+ (LayoutParams) getChildAt(i).getLayoutParams();
+ if (lp.width != largestTabWidth || lp.weight != 0) {
+ lp.width = largestTabWidth;
+ lp.weight = 0;
+ remeasure = true;
+ }
}
} else {
// If the tabs will wrap to be larger than the width minus gutters, we need
// to switch to GRAVITY_FILL
mTabGravity = GRAVITY_FILL;
- updateTabViewsLayoutParams();
+ updateTabViews(false);
+ remeasure = true;
}
- // Now re-measure after our changes
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (remeasure) {
+ // Now re-measure after our changes
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- // If we've been layed out, update the indicator position
- updateIndicatorPosition();
+
+ if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
+ // If we're currently running an animation, lets cancel it and start a
+ // new animation with the remaining duration
+ mIndicatorAnimator.cancel();
+ final long duration = mIndicatorAnimator.getDuration();
+ animateIndicatorToPosition(mSelectedPosition,
+ Math.round((1f - mIndicatorAnimator.getAnimatedFraction()) * duration));
+ } else {
+ // If we've been layed out, update the indicator position
+ updateIndicatorPosition();
+ }
}
private void updateIndicatorPosition() {
@@ -1457,6 +1694,10 @@
}
void animateIndicatorToPosition(final int position, int duration) {
+ if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
+ mIndicatorAnimator.cancel();
+ }
+
final boolean isRtl = ViewCompat.getLayoutDirection(this)
== ViewCompat.LAYOUT_DIRECTION_RTL;
@@ -1510,12 +1751,6 @@
mSelectedPosition = position;
mSelectionOffset = 0f;
}
-
- @Override
- public void onAnimationCancel(ValueAnimatorCompat animator) {
- mSelectedPosition = position;
- mSelectionOffset = 0f;
- }
});
animator.start();
}
@@ -1550,14 +1785,29 @@
return new ColorStateList(states, colors);
}
- private ColorStateList loadTextColorFromTextAppearance(int textAppearanceResId) {
- TypedArray a = getContext().obtainStyledAttributes(textAppearanceResId,
- R.styleable.TextAppearance);
- try {
- return a.getColorStateList(R.styleable.TextAppearance_android_textColor);
- } finally {
- a.recycle();
+ private int getDefaultHeight() {
+ boolean hasIconAndText = false;
+ for (int i = 0, count = mTabs.size(); i < count; i++) {
+ Tab tab = mTabs.get(i);
+ if (tab != null && tab.getIcon() != null && !TextUtils.isEmpty(tab.getText())) {
+ hasIconAndText = true;
+ break;
+ }
}
+ return hasIconAndText ? DEFAULT_HEIGHT_WITH_TEXT_ICON : DEFAULT_HEIGHT;
+ }
+
+ private int getTabMinWidth() {
+ if (mRequestedTabMinWidth != INVALID_WIDTH) {
+ // If we have been given a min width, use it
+ return mRequestedTabMinWidth;
+ }
+ // Else, we'll use the default value
+ return mMode == MODE_SCROLLABLE ? mScrollableTabMinWidth : 0;
+ }
+
+ private int getTabMaxWidth() {
+ return mTabMaxWidth;
}
/**
@@ -1590,25 +1840,35 @@
int positionOffsetPixels) {
final TabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout != null) {
- // Update the scroll position, only update the text selection if we're being
- // dragged (or we're settling after a drag)
- final boolean updateText = (mScrollState == ViewPager.SCROLL_STATE_DRAGGING)
- || (mScrollState == ViewPager.SCROLL_STATE_SETTLING
- && mPreviousScrollState == ViewPager.SCROLL_STATE_DRAGGING);
- tabLayout.setScrollPosition(position, positionOffset, updateText);
+ // Only update the text selection if we're not settling, or we are settling after
+ // being dragged
+ final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
+ mPreviousScrollState == SCROLL_STATE_DRAGGING;
+ // Update the indicator if we're not settling after being idle. This is caused
+ // from a setCurrentItem() call and will be handled by an animation from
+ // onPageSelected() instead.
+ final boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING
+ && mPreviousScrollState == SCROLL_STATE_IDLE);
+ tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
}
}
@Override
public void onPageSelected(int position) {
final TabLayout tabLayout = mTabLayoutRef.get();
- if (tabLayout != null) {
+ if (tabLayout != null && tabLayout.getSelectedTabPosition() != position) {
// Select the tab, only updating the indicator if we're not being dragged/settled
// (since onPageScrolled will handle that).
- tabLayout.selectTab(tabLayout.getTabAt(position),
- mScrollState == ViewPager.SCROLL_STATE_IDLE);
+ final boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE
+ || (mScrollState == SCROLL_STATE_SETTLING
+ && mPreviousScrollState == SCROLL_STATE_IDLE);
+ tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
}
}
+
+ private void reset() {
+ mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
+ }
}
/**
@@ -1638,4 +1898,16 @@
}
}
+ private class PagerAdapterObserver extends DataSetObserver {
+ @Override
+ public void onChanged() {
+ populateFromPagerAdapter();
+ }
+
+ @Override
+ public void onInvalidated() {
+ populateFromPagerAdapter();
+ }
+ }
+
}
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 16ebc30..32abe85 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -22,7 +22,11 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.design.R;
@@ -31,7 +35,8 @@
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v4.widget.Space;
+import android.support.v7.widget.AppCompatDrawableManager;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
@@ -56,15 +61,29 @@
public class TextInputLayout extends LinearLayout {
private static final int ANIMATION_DURATION = 200;
+ private static final int INVALID_MAX_LENGTH = -1;
private EditText mEditText;
+
+ private boolean mHintEnabled;
private CharSequence mHint;
private Paint mTmpPaint;
+ private LinearLayout mIndicatorArea;
+ private int mIndicatorsAdded;
+
private boolean mErrorEnabled;
private TextView mErrorView;
private int mErrorTextAppearance;
+ private boolean mErrorShown;
+
+ private boolean mCounterEnabled;
+ private TextView mCounterView;
+ private int mCounterMaxLength;
+ private int mCounterTextAppearance;
+ private int mCounterOverflowTextAppearance;
+ private boolean mCounterOverflowed;
private ColorStateList mDefaultTextColor;
private ColorStateList mFocusedTextColor;
@@ -74,6 +93,8 @@
private boolean mHintAnimationEnabled;
private ValueAnimatorCompat mAnimator;
+ private boolean mHasReconstructedEditTextBackground;
+
public TextInputLayout(Context context) {
this(context, null);
}
@@ -86,6 +107,8 @@
// Can't call through to super(Context, AttributeSet, int) since it doesn't exist on API 10
super(context, attrs);
+ ThemeUtils.checkAppCompatTheme(context);
+
setOrientation(VERTICAL);
setWillNotDraw(false);
setAddStatesFromChildren(true);
@@ -96,7 +119,8 @@
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.TextInputLayout, defStyleAttr, R.style.Widget_Design_TextInputLayout);
- mHint = a.getText(R.styleable.TextInputLayout_android_hint);
+ mHintEnabled = a.getBoolean(R.styleable.TextInputLayout_hintEnabled, true);
+ setHint(a.getText(R.styleable.TextInputLayout_android_hint));
mHintAnimationEnabled = a.getBoolean(
R.styleable.TextInputLayout_hintAnimationEnabled, true);
@@ -114,9 +138,19 @@
mErrorTextAppearance = a.getResourceId(R.styleable.TextInputLayout_errorTextAppearance, 0);
final boolean errorEnabled = a.getBoolean(R.styleable.TextInputLayout_errorEnabled, false);
+
+ final boolean counterEnabled = a.getBoolean(
+ R.styleable.TextInputLayout_counterEnabled, false);
+ setCounterMaxLength(
+ a.getInt(R.styleable.TextInputLayout_counterMaxLength, INVALID_MAX_LENGTH));
+ mCounterTextAppearance = a.getResourceId(
+ R.styleable.TextInputLayout_counterTextAppearance, 0);
+ mCounterOverflowTextAppearance = a.getResourceId(
+ R.styleable.TextInputLayout_counterOverflowTextAppearance, 0);
a.recycle();
setErrorEnabled(errorEnabled);
+ setCounterEnabled(counterEnabled);
if (ViewCompat.getImportantForAccessibility(this)
== ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
@@ -140,12 +174,21 @@
}
/**
- * Set the typeface to use for the both the expanded and floating hint.
+ * Set the typeface to use for both the expanded and floating hint.
*
* @param typeface typeface to use, or {@code null} to use the default.
*/
public void setTypeface(@Nullable Typeface typeface) {
- mCollapsingTextHelper.setTypeface(typeface);
+ mCollapsingTextHelper.setTypefaces(typeface);
+ }
+
+ /**
+ * Returns the typeface used for both the expanded and floating hint.
+ */
+ @NonNull
+ public Typeface getTypeface() {
+ // This could be either the collapsed or expanded
+ return mCollapsingTextHelper.getCollapsedTypeface();
}
private void setEditText(EditText editText) {
@@ -156,7 +199,7 @@
mEditText = editText;
// Use the EditText's typeface, and it's text size for our expanded text
- mCollapsingTextHelper.setTypeface(mEditText.getTypeface());
+ mCollapsingTextHelper.setTypefaces(mEditText.getTypeface());
mCollapsingTextHelper.setExpandedTextSize(mEditText.getTextSize());
mCollapsingTextHelper.setExpandedTextGravity(mEditText.getGravity());
@@ -164,7 +207,10 @@
mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
- updateLabelVisibility(true);
+ updateLabelState(true);
+ if (mCounterEnabled) {
+ updateCounter(s.length());
+ }
}
@Override
@@ -179,21 +225,23 @@
mDefaultTextColor = mEditText.getHintTextColors();
}
- // If we do not have a valid hint, try and retrieve it from the EditText
- if (TextUtils.isEmpty(mHint)) {
+ // If we do not have a valid hint, try and retrieve it from the EditText, if enabled
+ if (mHintEnabled && TextUtils.isEmpty(mHint)) {
setHint(mEditText.getHint());
// Clear the EditText's hint as we will display it ourselves
mEditText.setHint(null);
}
- if (mErrorView != null) {
- // Add some start/end padding to the error so that it matches the EditText
- ViewCompat.setPaddingRelative(mErrorView, ViewCompat.getPaddingStart(mEditText),
- 0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
+ if (mCounterView != null) {
+ updateCounter(mEditText.getText().length());
+ }
+
+ if (mIndicatorArea != null) {
+ adjustIndicatorPadding();
}
// Update the label visibility with no animation
- updateLabelVisibility(false);
+ updateLabelState(false);
}
private LayoutParams updateEditTextMargin(ViewGroup.LayoutParams lp) {
@@ -201,28 +249,40 @@
// to the EditText so make room for the label
LayoutParams llp = lp instanceof LayoutParams ? (LayoutParams) lp : new LayoutParams(lp);
- if (mTmpPaint == null) {
- mTmpPaint = new Paint();
+ if (mHintEnabled) {
+ if (mTmpPaint == null) {
+ mTmpPaint = new Paint();
+ }
+ mTmpPaint.setTypeface(mCollapsingTextHelper.getCollapsedTypeface());
+ mTmpPaint.setTextSize(mCollapsingTextHelper.getCollapsedTextSize());
+ llp.topMargin = (int) -mTmpPaint.ascent();
+ } else {
+ llp.topMargin = 0;
}
- mTmpPaint.setTypeface(mCollapsingTextHelper.getTypeface());
- mTmpPaint.setTextSize(mCollapsingTextHelper.getCollapsedTextSize());
- llp.topMargin = (int) -mTmpPaint.ascent();
return llp;
}
- private void updateLabelVisibility(boolean animate) {
- boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
- boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
+ private void updateLabelState(boolean animate) {
+ final boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
+ final boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
+ final boolean isErrorShowing = !TextUtils.isEmpty(getError());
- if (mDefaultTextColor != null && mFocusedTextColor != null) {
+ if (mDefaultTextColor != null) {
mCollapsingTextHelper.setExpandedTextColor(mDefaultTextColor.getDefaultColor());
- mCollapsingTextHelper.setCollapsedTextColor(isFocused
- ? mFocusedTextColor.getDefaultColor()
- : mDefaultTextColor.getDefaultColor());
}
- if (hasText || isFocused) {
+ if (mCounterOverflowed && mCounterView != null) {
+ mCollapsingTextHelper.setCollapsedTextColor(mCounterView.getCurrentTextColor());
+ } else if (isErrorShowing && mErrorView != null) {
+ mCollapsingTextHelper.setCollapsedTextColor(mErrorView.getCurrentTextColor());
+ } else if (isFocused && mFocusedTextColor != null) {
+ mCollapsingTextHelper.setCollapsedTextColor(mFocusedTextColor.getDefaultColor());
+ } else if (mDefaultTextColor != null) {
+ mCollapsingTextHelper.setCollapsedTextColor(mDefaultTextColor.getDefaultColor());
+ }
+
+ if (hasText || isFocused || isErrorShowing) {
// We should be showing the label so do so if it isn't already
collapseHint(animate);
} else {
@@ -240,25 +300,89 @@
}
/**
- * Set the hint to be displayed in the floating label
+ * Set the hint to be displayed in the floating label, if enabled.
+ *
+ * @see #setHintEnabled(boolean)
*
* @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
*/
public void setHint(@Nullable CharSequence hint) {
+ if (mHintEnabled) {
+ setHintInternal(hint);
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ }
+ }
+
+ private void setHintInternal(CharSequence hint) {
mHint = hint;
mCollapsingTextHelper.setText(hint);
-
- sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
}
/**
- * Returns the hint which is displayed in the floating label.
+ * Returns the hint which is displayed in the floating label, if enabled.
+ *
+ * @return the hint, or null if there isn't one set, or the hint is not enabled.
*
* @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
*/
@Nullable
public CharSequence getHint() {
- return mHint;
+ return mHintEnabled ? mHint : null;
+ }
+
+ /**
+ * Sets whether the floating label functionality is enabled or not in this layout.
+ *
+ * <p>If enabled, any non-empty hint in the child EditText will be moved into the floating
+ * hint, and its existing hint will be cleared. If disabled, then any non-empty floating hint
+ * in this layout will be moved into the EditText, and this layout's hint will be cleared.</p>
+ *
+ * @see #setHint(CharSequence)
+ * @see #isHintEnabled()
+ *
+ * @attr ref android.support.design.R.styleable#TextInputLayout_hintEnabled
+ */
+ public void setHintEnabled(boolean enabled) {
+ if (enabled != mHintEnabled) {
+ mHintEnabled = enabled;
+
+ final CharSequence editTextHint = mEditText.getHint();
+ if (!mHintEnabled) {
+ if (!TextUtils.isEmpty(mHint) && TextUtils.isEmpty(editTextHint)) {
+ // If the hint is disabled, but we have a hint set, and the EditText doesn't,
+ // pass it through...
+ mEditText.setHint(mHint);
+ }
+ // Now clear out any set hint
+ setHintInternal(null);
+ } else {
+ if (!TextUtils.isEmpty(editTextHint)) {
+ // If the hint is now enabled and the EditText has one set, we'll use it if
+ // we don't already have one, and clear the EditText's
+ if (TextUtils.isEmpty(mHint)) {
+ setHint(editTextHint);
+ }
+ mEditText.setHint(null);
+ }
+ }
+
+ // Now update the EditText top margin
+ if (mEditText != null) {
+ final LayoutParams lp = updateEditTextMargin(mEditText.getLayoutParams());
+ mEditText.setLayoutParams(lp);
+ }
+ }
+ }
+
+ /**
+ * Returns whether the floating label functionality is enabled or not in this layout.
+ *
+ * @see #setHintEnabled(boolean)
+ *
+ * @attr ref android.support.design.R.styleable#TextInputLayout_hintEnabled
+ */
+ public boolean isHintEnabled() {
+ return mHintEnabled;
}
/**
@@ -271,7 +395,7 @@
mFocusedTextColor = ColorStateList.valueOf(mCollapsingTextHelper.getCollapsedTextColor());
if (mEditText != null) {
- updateLabelVisibility(false);
+ updateLabelState(false);
// Text size might have changed so update the top margin
LayoutParams lp = updateEditTextMargin(mEditText.getLayoutParams());
@@ -280,6 +404,42 @@
}
}
+ private void addIndicator(TextView indicator, int index) {
+ if (mIndicatorArea == null) {
+ mIndicatorArea = new LinearLayout(getContext());
+ mIndicatorArea.setOrientation(LinearLayout.HORIZONTAL);
+ addView(mIndicatorArea, LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+
+ // Add a flexible spacer in the middle so that the left/right views stay pinned
+ final Space spacer = new Space(getContext());
+ final LinearLayout.LayoutParams spacerLp = new LinearLayout.LayoutParams(0, 0, 1f);
+ mIndicatorArea.addView(spacer, spacerLp);
+
+ if (mEditText != null) {
+ adjustIndicatorPadding();
+ }
+ }
+ mIndicatorArea.setVisibility(View.VISIBLE);
+ mIndicatorArea.addView(indicator, index);
+ mIndicatorsAdded++;
+ }
+
+ private void adjustIndicatorPadding() {
+ // Add padding to the error and character counter so that they match the EditText
+ ViewCompat.setPaddingRelative(mIndicatorArea, ViewCompat.getPaddingStart(mEditText),
+ 0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
+ }
+
+ private void removeIndicator(TextView indicator) {
+ if (mIndicatorArea != null) {
+ mIndicatorArea.removeView(indicator);
+ if (--mIndicatorsAdded == 0) {
+ mIndicatorArea.setVisibility(View.GONE);
+ }
+ }
+ }
+
/**
* Whether the error functionality is enabled or not in this layout. Enabling this
* functionality before setting an error message via {@link #setError(CharSequence)}, will mean
@@ -297,15 +457,13 @@
mErrorView = new TextView(getContext());
mErrorView.setTextAppearance(getContext(), mErrorTextAppearance);
mErrorView.setVisibility(INVISIBLE);
- addView(mErrorView);
-
- if (mEditText != null) {
- // Add some start/end padding to the error so that it matches the EditText
- ViewCompat.setPaddingRelative(mErrorView, ViewCompat.getPaddingStart(mEditText),
- 0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
- }
+ ViewCompat.setAccessibilityLiveRegion(mErrorView,
+ ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
+ addIndicator(mErrorView, 0);
} else {
- removeView(mErrorView);
+ mErrorShown = false;
+ updateEditTextBackground();
+ removeIndicator(mErrorView);
mErrorView = null;
}
mErrorEnabled = enabled;
@@ -345,44 +503,202 @@
}
if (!TextUtils.isEmpty(error)) {
- ViewCompat.setAlpha(mErrorView, 0f);
- mErrorView.setText(error);
- ViewCompat.animate(mErrorView)
- .alpha(1f)
- .setDuration(ANIMATION_DURATION)
- .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
- .setListener(new ViewPropertyAnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(View view) {
- view.setVisibility(VISIBLE);
- }
- })
- .start();
+ boolean animate;
+ if (TextUtils.equals(error, mErrorView.getText())) {
+ // We've been given the same error message, so only animate if needed
+ animate = !mErrorView.isShown() || ViewCompat.getAlpha(mErrorView) < 1f;
+ } else {
+ animate = true;
+ mErrorView.setText(error);
+ }
+
+ if (animate) {
+ if (ViewCompat.getAlpha(mErrorView) == 1f) {
+ // If it's currently 100% show, we'll animate it from 0
+ ViewCompat.setAlpha(mErrorView, 0f);
+ }
+ ViewCompat.animate(mErrorView)
+ .alpha(1f)
+ .setDuration(ANIMATION_DURATION)
+ .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
+ .setListener(new ViewPropertyAnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(View view) {
+ view.setVisibility(VISIBLE);
+ }
+ })
+ .start();
+ }
// Set the EditText's background tint to the error color
- ViewCompat.setBackgroundTintList(mEditText,
- ColorStateList.valueOf(mErrorView.getCurrentTextColor()));
+ mErrorShown = true;
+ updateEditTextBackground();
+ updateLabelState(true);
} else {
if (mErrorView.getVisibility() == VISIBLE) {
ViewCompat.animate(mErrorView)
.alpha(0f)
.setDuration(ANIMATION_DURATION)
- .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
+ .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
.setListener(new ViewPropertyAnimatorListenerAdapter() {
@Override
public void onAnimationEnd(View view) {
view.setVisibility(INVISIBLE);
+
+ updateLabelState(true);
}
}).start();
// Restore the 'original' tint, using colorControlNormal and colorControlActivated
- final TintManager tintManager = TintManager.get(getContext());
- ViewCompat.setBackgroundTintList(mEditText,
- tintManager.getTintList(R.drawable.abc_edit_text_material));
+ mErrorShown = false;
+ updateEditTextBackground();
}
}
+ }
- sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ /**
+ * Whether the character counter functionality is enabled or not in this layout.
+ *
+ * @attr ref android.support.design.R.styleable#TextInputLayout_counterEnabled
+ */
+ public void setCounterEnabled(boolean enabled) {
+ if (mCounterEnabled != enabled) {
+ if (enabled) {
+ mCounterView = new TextView(getContext());
+ mCounterView.setMaxLines(1);
+ mCounterView.setTextAppearance(getContext(), mCounterTextAppearance);
+ ViewCompat.setAccessibilityLiveRegion(mCounterView,
+ ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
+ addIndicator(mCounterView, -1);
+ if (mEditText == null) {
+ updateCounter(0);
+ } else {
+ updateCounter(mEditText.getText().length());
+ }
+ } else {
+ removeIndicator(mCounterView);
+ mCounterView = null;
+ }
+ mCounterEnabled = enabled;
+ }
+ }
+
+ /**
+ * Returns whether the character counter functionality is enabled or not in this layout.
+ *
+ * @attr ref android.support.design.R.styleable#TextInputLayout_counterEnabled
+ *
+ * @see #setCounterEnabled(boolean)
+ */
+ public boolean isCounterEnabled() {
+ return mCounterEnabled;
+ }
+
+ /**
+ * Sets the max length to display at the character counter.
+ *
+ * @param maxLength maxLength to display. Any value less than or equal to 0 will not be shown.
+ *
+ * @attr ref android.support.design.R.styleable#TextInputLayout_counterMaxLength
+ */
+ public void setCounterMaxLength(int maxLength) {
+ if (mCounterMaxLength != maxLength) {
+ if (maxLength > 0) {
+ mCounterMaxLength = maxLength;
+ } else {
+ mCounterMaxLength = INVALID_MAX_LENGTH;
+ }
+ if (mCounterEnabled) {
+ updateCounter(mEditText == null ? 0 : mEditText.getText().length());
+ }
+ }
+ }
+
+ /**
+ * Returns the max length shown at the character counter.
+ *
+ * @attr ref android.support.design.R.styleable#TextInputLayout_counterMaxLength
+ */
+ public int getCounterMaxLength() {
+ return mCounterMaxLength;
+ }
+
+ private void updateCounter(int length) {
+ boolean wasCounterOverflowed = mCounterOverflowed;
+ if (mCounterMaxLength == INVALID_MAX_LENGTH) {
+ mCounterView.setText(String.valueOf(length));
+ mCounterOverflowed = false;
+ } else {
+ mCounterOverflowed = length > mCounterMaxLength;
+ if (wasCounterOverflowed != mCounterOverflowed) {
+ mCounterView.setTextAppearance(getContext(), mCounterOverflowed ?
+ mCounterOverflowTextAppearance : mCounterTextAppearance);
+ }
+ mCounterView.setText(getContext().getString(R.string.character_counter_pattern,
+ length, mCounterMaxLength));
+ }
+ if (mEditText != null && wasCounterOverflowed != mCounterOverflowed) {
+ updateLabelState(false);
+ updateEditTextBackground();
+ }
+ }
+
+ private void updateEditTextBackground() {
+ ensureBackgroundDrawableStateWorkaround();
+
+ final Drawable editTextBackground = mEditText.getBackground();
+ if (editTextBackground == null) {
+ return;
+ }
+
+ if (mErrorShown && mErrorView != null) {
+ // Set a color filter of the error color
+ editTextBackground.setColorFilter(
+ AppCompatDrawableManager.getPorterDuffColorFilter(
+ mErrorView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
+ } else if (mCounterOverflowed && mCounterView != null) {
+ // Set a color filter of the counter color
+ editTextBackground.setColorFilter(
+ AppCompatDrawableManager.getPorterDuffColorFilter(
+ mCounterView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
+ } else {
+ // Else reset the color filter and refresh the drawable state so that the
+ // normal tint is used
+ editTextBackground.clearColorFilter();
+ mEditText.refreshDrawableState();
+ }
+ }
+
+ private void ensureBackgroundDrawableStateWorkaround() {
+ final Drawable bg = mEditText.getBackground();
+ if (bg == null) {
+ return;
+ }
+
+ if (!mHasReconstructedEditTextBackground) {
+ // This is gross. There is an issue in the platform which affects container Drawables
+ // where the first drawable retrieved from resources will propogate any changes
+ // (like color filter) to all instances from the cache. We'll try to workaround it...
+
+ final Drawable newBg = bg.getConstantState().newDrawable();
+
+ if (bg instanceof DrawableContainer) {
+ // If we have a Drawable container, we can try and set it's constant state via
+ // reflection from the new Drawable
+ mHasReconstructedEditTextBackground =
+ DrawableUtils.setContainerConstantState(
+ (DrawableContainer) bg, newBg.getConstantState());
+ }
+
+ if (!mHasReconstructedEditTextBackground) {
+ // If we reach here then we just need to set a brand new instance of the Drawable
+ // 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);
+ mHasReconstructedEditTextBackground = true;
+ }
+ }
}
/**
@@ -427,14 +743,17 @@
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
- mCollapsingTextHelper.draw(canvas);
+
+ if (mHintEnabled) {
+ mCollapsingTextHelper.draw(canvas);
+ }
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (mEditText != null) {
+ if (mHintEnabled && mEditText != null) {
final int l = mEditText.getLeft() + mEditText.getCompoundPaddingLeft();
final int r = mEditText.getRight() - mEditText.getCompoundPaddingRight();
@@ -455,7 +774,7 @@
public void refreshDrawableState() {
super.refreshDrawableState();
// Drawable state has changed so see if we need to update the label
- updateLabelVisibility(ViewCompat.isLaidOut(this));
+ updateLabelState(ViewCompat.isLaidOut(this));
}
private void collapseHint(boolean animate) {
diff --git a/design/src/android/support/design/widget/ThemeUtils.java b/design/src/android/support/design/widget/ThemeUtils.java
new file mode 100644
index 0000000..327a44d
--- /dev/null
+++ b/design/src/android/support/design/widget/ThemeUtils.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package android.support.design.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.design.R;
+
+class ThemeUtils {
+
+ private static final int[] APPCOMPAT_CHECK_ATTRS = { R.attr.colorPrimary };
+
+ static void checkAppCompatTheme(Context context) {
+ TypedArray a = context.obtainStyledAttributes(APPCOMPAT_CHECK_ATTRS);
+ final boolean failed = !a.hasValue(0);
+ if (a != null) {
+ a.recycle();
+ }
+ if (failed) {
+ throw new IllegalArgumentException("You need to use a Theme.AppCompat theme "
+ + "(or descendant) with the design library.");
+ }
+ }
+}
diff --git a/design/src/android/support/design/widget/ViewOffsetHelper.java b/design/src/android/support/design/widget/ViewOffsetHelper.java
index 6bde40b..1254f17 100644
--- a/design/src/android/support/design/widget/ViewOffsetHelper.java
+++ b/design/src/android/support/design/widget/ViewOffsetHelper.java
@@ -66,9 +66,9 @@
}
private static void tickleInvalidationFlag(View view) {
- final float x = ViewCompat.getTranslationX(view);
- ViewCompat.setTranslationX(view, x + 1);
- ViewCompat.setTranslationX(view, x);
+ final float y = ViewCompat.getTranslationY(view);
+ ViewCompat.setTranslationY(view, y + 1);
+ ViewCompat.setTranslationY(view, y);
}
/**
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
index 63e93b7..06d8d6f 100644
--- a/graphics/drawable/Android.mk
+++ b/graphics/drawable/Android.mk
@@ -17,8 +17,8 @@
#static vector drawable library
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-vectordrawable
-LOCAL_SDK_VERSION := 7
-LOCAL_SRC_FILES := $(call all-java-files-under, static)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, static util)
LOCAL_JAVA_LIBRARIES := android-support-v4
@@ -29,8 +29,8 @@
#Animated vector drawable library
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v11-animatedvectordrawable
-LOCAL_SDK_VERSION := 11
-LOCAL_SRC_FILES := $(call all-java-files-under, animated)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, animated util)
LOCAL_JAVA_LIBRARIES := android-support-v4
@@ -38,4 +38,5 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-vectordrawable
+LOCAL_AAPT_FLAGS := --no-version-vectors
include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
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 78ef62d..eff9670 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -16,7 +16,6 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -45,12 +44,12 @@
/**
* This class uses {@link android.animation.ObjectAnimator} and
* {@link android.animation.AnimatorSet} to animate the properties of a
- * {@link android.graphics.drawable.VectorDrawableCompat} to create an animated drawable.
+ * {@link android.support.graphics.drawable.VectorDrawableCompat} to create an animated drawable.
* <p>
* AnimatedVectorDrawableCompat are normally defined as 3 separate XML files.
* </p>
* <p>
- * First is the XML file for {@link android.graphics.drawable.VectorDrawableCompat}. Note that we
+ * First is the XML file for {@link android.support.graphics.drawable.VectorDrawableCompat}. Note that we
* allow the animation to happen on the group's attributes and path's attributes, which requires they
* are uniquely named in this XML file. Groups and paths without animations do not need names.
* </p>
@@ -306,9 +305,9 @@
}
if (ANIMATED_VECTOR.equals(tagName)) {
final TypedArray a =
- obtainAttributes(res, theme, attrs, R.styleable.AnimatedVectorDrawable);
+ obtainAttributes(res, theme, attrs, AndroidResources.styleable_AnimatedVectorDrawable);
- int drawableRes = a.getResourceId(R.styleable.AnimatedVectorDrawable_drawable,
+ int drawableRes = a.getResourceId(AndroidResources.styleable_AnimatedVectorDrawable_drawable,
0);
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
Log.v(LOGTAG, "drawableRes is " + drawableRes);
@@ -327,11 +326,11 @@
a.recycle();
} else if (TARGET.equals(tagName)) {
final TypedArray a =
- res.obtainAttributes(attrs, R.styleable.AnimatedVectorDrawableTarget);
+ res.obtainAttributes(attrs, AndroidResources.styleable_AnimatedVectorDrawableTarget);
final String target = a.getString(
- R.styleable.AnimatedVectorDrawableTarget_name);
+ AndroidResources.styleable_AnimatedVectorDrawableTarget_name);
- int id = a.getResourceId(R.styleable.AnimatedVectorDrawableTarget_animation, 0);
+ int id = a.getResourceId(AndroidResources.styleable_AnimatedVectorDrawableTarget_animation, 0);
if (id != 0) {
Animator objectAnimator = AnimatorInflater.loadAnimator(mContext, id);
setupAnimatorsForTarget(target, objectAnimator);
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
index a92c3e5..8503fae 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
@@ -131,8 +131,8 @@
}
for (int i = 0; i < nodesFrom.length; i ++) {
- if (nodesFrom[i].mType != nodesTo[i].mType
- || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+ if (nodesFrom[i].type != nodesTo[i].type
+ || nodesFrom[i].params.length != nodesTo[i].params.length) {
return false;
}
}
@@ -148,9 +148,9 @@
*/
public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
for (int i = 0; i < source.length; i ++) {
- target[i].mType = source[i].mType;
- for (int j = 0; j < source[i].mParams.length; j ++) {
- target[i].mParams[j] = source[i].mParams[j];
+ target[i].type = source[i].type;
+ for (int j = 0; j < source[i].params.length; j ++) {
+ target[i].params[j] = source[i].params[j];
}
}
}
@@ -288,17 +288,18 @@
* An array of PathDataNode can represent the whole "d" attribute.
*/
public static class PathDataNode {
- private char mType;
- private float[] mParams;
+ /*package*/
+ char type;
+ float[] params;
private PathDataNode(char type, float[] params) {
- mType = type;
- mParams = params;
+ this.type = type;
+ this.params = params;
}
private PathDataNode(PathDataNode n) {
- mType = n.mType;
- mParams = copyOfRange(n.mParams, 0, n.mParams.length);
+ type = n.type;
+ params = copyOfRange(n.params, 0, n.params.length);
}
/**
@@ -311,8 +312,8 @@
float[] current = new float[6];
char previousCommand = 'm';
for (int i = 0; i < node.length; i++) {
- addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
- previousCommand = node[i].mType;
+ addCommand(path, current, previousCommand, node[i].type, node[i].params);
+ previousCommand = node[i].type;
}
}
@@ -327,9 +328,9 @@
*/
public void interpolatePathDataNode(PathDataNode nodeFrom,
PathDataNode nodeTo, float fraction) {
- for (int i = 0; i < nodeFrom.mParams.length; i++) {
- mParams[i] = nodeFrom.mParams[i] * (1 - fraction)
- + nodeTo.mParams[i] * fraction;
+ for (int i = 0; i < nodeFrom.params.length; i++) {
+ params[i] = nodeFrom.params[i] * (1 - fraction)
+ + nodeTo.params[i] * fraction;
}
}
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 d33c204..c0e5b40 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -196,7 +196,7 @@
private static final int LINEJOIN_ROUND = 1;
private static final int LINEJOIN_BEVEL = 2;
- private static final boolean DBG_VECTOR_DRAWABLE = true;
+ private static final boolean DBG_VECTOR_DRAWABLE = false;
private VectorDrawableState mVectorState;
@@ -420,7 +420,6 @@
final VectorDrawableCompat drawable = new VectorDrawableCompat();
drawable.inflate(res, parser, attrs, theme);
-
return drawable;
} catch (XmlPullParserException e) {
Log.e(LOGTAG, "parser error", e);
@@ -462,8 +461,9 @@
final VPathRenderer pathRenderer = new VPathRenderer();
state.mVPathRenderer = pathRenderer;
- final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable);
- updateStateFromTypedArray(a);
+ final TypedArray a = obtainAttributes(res, theme, attrs, AndroidResources.styleable_VectorDrawableTypeArray);
+
+ updateStateFromTypedArray(a, parser);
a.recycle();
state.mChangingConfigurations = getChangingConfigurations();
state.mCacheDirty = true;
@@ -472,30 +472,47 @@
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
- private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+
+ /**
+ * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
+ * attribute's enum value.
+ */
+ private static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+ switch (value) {
+ case 3: return Mode.SRC_OVER;
+ case 5: return Mode.SRC_IN;
+ case 9: return Mode.SRC_ATOP;
+ case 14: return Mode.MULTIPLY;
+ case 15: return Mode.SCREEN;
+ case 16: return Mode.ADD;
+ default: return defaultMode;
+ }
+ }
+
+ private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) throws XmlPullParserException {
final VectorDrawableState state = mVectorState;
final VPathRenderer pathRenderer = state.mVPathRenderer;
// Account for any configuration changes.
// state.mChangingConfigurations |= Utils.getChangingConfigurations(a);
- final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
- // if (tintMode != -1) {
- // state.mTintMode = Utils.parseTintMode(tintMode, DEFAULT_TINT_MODE);
- // }
+ final int mode = TypedArrayUtils.getNamedInt(a, parser, "tintMode",
+ AndroidResources.styleable_VectorDrawable_Mode, -1);
+ state.mTintMode = parseTintMode(mode, Mode.SRC_IN);
- final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
+ final ColorStateList tint = a.getColorStateList(AndroidResources.styleable_VectorDrawable_tint);
if (tint != null) {
state.mTint = tint;
}
- state.mAutoMirrored = a.getBoolean(
- R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
+ state.mAutoMirrored = TypedArrayUtils.getNamedBoolean(a, parser, "autoMirrored",
+ AndroidResources.styleable_VectorDrawable_autoMirrored, state.mAutoMirrored);
- pathRenderer.mViewportWidth = a.getFloat(
- R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
- pathRenderer.mViewportHeight = a.getFloat(
- R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
+ pathRenderer.mViewportWidth = TypedArrayUtils.getNamedFloat(a, parser, "viewportWidth",
+ AndroidResources.styleable_VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
+
+ pathRenderer.mViewportHeight = TypedArrayUtils.getNamedFloat(a, parser, "viewportHeight",
+ AndroidResources.styleable_VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
if (pathRenderer.mViewportWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
@@ -506,10 +523,9 @@
}
pathRenderer.mBaseWidth = a.getDimension(
- R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
+ AndroidResources.styleable_VectorDrawable_width, pathRenderer.mBaseWidth);
pathRenderer.mBaseHeight = a.getDimension(
- R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
-
+ AndroidResources.styleable_VectorDrawable_height, pathRenderer.mBaseHeight);
if (pathRenderer.mBaseWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires width > 0");
@@ -518,11 +534,12 @@
"<vector> tag requires height > 0");
}
- final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
- pathRenderer.getAlpha());
+ // shown up from API 11.
+ final float alphaInFloat = TypedArrayUtils.getNamedFloat(a, parser, "alpha",
+ AndroidResources.styleable_VectorDrawable_alpha, pathRenderer.getAlpha());
pathRenderer.setAlpha(alphaInFloat);
- final String name = a.getString(R.styleable.VectorDrawable_name);
+ final String name = a.getString(AndroidResources.styleable_VectorDrawable_name);
if (name != null) {
pathRenderer.mRootName = name;
pathRenderer.mVGTargetsMap.put(name, pathRenderer);
@@ -545,10 +562,9 @@
if (eventType == XmlPullParser.START_TAG) {
final String tagName = parser.getName();
final VGroup currentGroup = groupStack.peek();
- Log.v(LOGTAG, tagName);
if (SHAPE_PATH.equals(tagName)) {
final VFullPath path = new VFullPath();
- path.inflate(res, attrs, theme);
+ path.inflate(res, attrs, theme, parser);
currentGroup.mChildren.add(path);
if (path.getPathName() != null) {
pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
@@ -557,7 +573,7 @@
state.mChangingConfigurations |= path.mChangingConfigurations;
} else if (SHAPE_CLIP_PATH.equals(tagName)) {
final VClipPath path = new VClipPath();
- path.inflate(res, attrs, theme);
+ path.inflate(res, attrs, theme, parser);
currentGroup.mChildren.add(path);
if (path.getPathName() != null) {
pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
@@ -565,7 +581,7 @@
state.mChangingConfigurations |= path.mChangingConfigurations;
} else if (SHAPE_GROUP.equals(tagName)) {
VGroup newChildGroup = new VGroup();
- newChildGroup.inflate(res, attrs, theme);
+ newChildGroup.inflate(res, attrs, theme, parser);
currentGroup.mChildren.add(newChildGroup);
groupStack.push(newChildGroup);
if (newChildGroup.getGroupName() != null) {
@@ -614,6 +630,8 @@
Object child = currentGroup.mChildren.get(i);
if (child instanceof VGroup) {
printGroupTree((VGroup) child, level + 1);
+ } else {
+ ((VPath) child).printVPath(level + 1);
}
}
}
@@ -1017,29 +1035,41 @@
return mLocalMatrix;
}
- public void inflate(Resources res, AttributeSet attrs, Theme theme) {
+ public void inflate(Resources res, AttributeSet attrs, Theme theme, XmlPullParser parser) {
final TypedArray a = obtainAttributes(res, theme, attrs,
- R.styleable.VectorDrawableGroup);
- updateStateFromTypedArray(a);
+ AndroidResources.styleable_VectorDrawableGroup);
+ updateStateFromTypedArray(a, parser);
a.recycle();
}
- private void updateStateFromTypedArray(TypedArray a) {
+ private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) {
// Account for any configuration changes.
// mChangingConfigurations |= Utils.getChangingConfigurations(a);
// Extract the theme attributes, if any.
mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs();
- mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
- mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
- mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
- mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
- mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
- mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
- mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+ // This is added in API 11
+ mRotate = TypedArrayUtils.getNamedFloat(a, parser, "rotation",
+ AndroidResources.styleable_VectorDrawableGroup_rotation, mRotate);
- final String groupName = a.getString(R.styleable.VectorDrawableGroup_name);
+ mPivotX = a.getFloat(AndroidResources.styleable_VectorDrawableGroup_pivotX, mPivotX);
+ mPivotY = a.getFloat(AndroidResources.styleable_VectorDrawableGroup_pivotY, mPivotY);
+
+ // This is added in API 11
+ mScaleX = TypedArrayUtils.getNamedFloat(a, parser, "scaleX",
+ AndroidResources.styleable_VectorDrawableGroup_scaleX, mScaleX);
+
+ // This is added in API 11
+ mScaleY = TypedArrayUtils.getNamedFloat(a, parser, "scaleY",
+ AndroidResources.styleable_VectorDrawableGroup_scaleY, mScaleY);
+
+ mTranslateX = TypedArrayUtils.getNamedFloat(a, parser, "translateX",
+ AndroidResources.styleable_VectorDrawableGroup_translateX, mTranslateX);
+ mTranslateY = TypedArrayUtils.getNamedFloat(a, parser, "translateY",
+ AndroidResources.styleable_VectorDrawableGroup_translateY, mTranslateY);
+
+ final String groupName = a.getString(AndroidResources.styleable_VectorDrawableGroup_name);
if (groupName != null) {
mGroupName = groupName;
}
@@ -1162,6 +1192,28 @@
// Empty constructor.
}
+ public void printVPath(int level) {
+ String indent = "";
+ for (int i = 0; i < level; i++) {
+ indent += " ";
+ }
+ Log.v(LOGTAG, indent + "current path is :" + mPathName +
+ " pathData is " + NodesToString(mNodes));
+
+ }
+
+ public String NodesToString(PathParser.PathDataNode[] nodes) {
+ String result = " ";
+ for (int i = 0; i < nodes.length; i++) {
+ result += nodes[i].type + ":";
+ float[] params = nodes[i].params;
+ for (int j = 0; j < params.length; j++) {
+ result += params[j] + ",";
+ }
+ }
+ return result;
+ }
+
public VPath(VPath copy) {
mPathName = copy.mPathName;
mChangingConfigurations = copy.mChangingConfigurations;
@@ -1219,10 +1271,14 @@
super(copy);
}
- public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+ public void inflate(Resources r, AttributeSet attrs, Theme theme, XmlPullParser parser) {
// TODO TINT THEME Not supported yet
+ final boolean hasPathData = TypedArrayUtils.hasAttribute(parser, "pathData");
+ if (!hasPathData) {
+ return;
+ }
final TypedArray a = obtainAttributes(r, theme, attrs,
- R.styleable.VectorDrawableClipPath);
+ AndroidResources.styleable_VectorDrawableClipPath);
updateStateFromTypedArray(a);
a.recycle();
}
@@ -1231,12 +1287,12 @@
// Account for any configuration changes.
// mChangingConfigurations |= Utils.getChangingConfigurations(a);;
- final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
+ final String pathName = a.getString(AndroidResources.styleable_VectorDrawableClipPath_name);
if (pathName != null) {
mPathName = pathName;
}
- final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
+ final String pathData = a.getString(AndroidResources.styleable_VectorDrawableClipPath_pathData);
if (pathData != null) {
mNodes = PathParser.createNodesFromPathData(pathData);
}
@@ -1325,52 +1381,64 @@
return mThemeAttrs != null;
}
- public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+ public void inflate(Resources r, AttributeSet attrs, Theme theme, XmlPullParser parser) {
final TypedArray a = obtainAttributes(r, theme, attrs,
- R.styleable.VectorDrawablePath);
- updateStateFromTypedArray(a);
+ AndroidResources.styleable_VectorDrawablePath);
+ updateStateFromTypedArray(a, parser);
a.recycle();
}
- private void updateStateFromTypedArray(TypedArray a) {
+ private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) {
// Account for any configuration changes.
// mChangingConfigurations |= Utils.getChangingConfigurations(a);
// Extract the theme attributes, if any.
mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs();
- final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
+ // In order to work around the conflicting id issue, we need to double check the existence
+ // of the attribute.
+ // B/c if the attribute existed in the compiled XML, then calling TypedArray will be safe
+ // since the framework will look up in the XML first.
+ // Note that each getAttributeValue take roughly 0.03ms, it is a price we have to pay here.
+ final boolean hasPathData = TypedArrayUtils.hasAttribute(parser, "pathData");
+ if (!hasPathData) {
+ //If there is no pathData in the <path> tag, then this is an empty path, nothing need to be drawn.
+ return;
+ }
+
+ final String pathName = a.getString(AndroidResources.styleable_VectorDrawablePath_name);
if (pathName != null) {
mPathName = pathName;
}
-
- final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
+ final String pathData = a.getString(AndroidResources.styleable_VectorDrawablePath_pathData);
if (pathData != null) {
mNodes = PathParser.createNodesFromPathData(pathData);
}
- mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
- mFillColor);
- mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha,
- mFillAlpha);
- mStrokeLineCap = getStrokeLineCap(a.getInt(
- R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
- mStrokeLineJoin = getStrokeLineJoin(a.getInt(
- R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
- mStrokeMiterlimit = a.getFloat(
- R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
- mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor,
- mStrokeColor);
- mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
- mStrokeAlpha);
- mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
- mStrokeWidth);
- mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
- mTrimPathEnd);
- mTrimPathOffset = a.getFloat(
- R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
- mTrimPathStart = a.getFloat(
- R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
+ mFillColor = TypedArrayUtils.getNamedColor(a, parser, "fillColor",
+ AndroidResources.styleable_VectorDrawablePath_fillColor, mFillColor);
+ mFillAlpha = TypedArrayUtils.getNamedFloat(a, parser, "alpha",
+ AndroidResources.styleable_VectorDrawablePath_fillAlpha, mFillAlpha);
+ final int lineCap = TypedArrayUtils.getNamedInt(a, parser, "strokeLineCap",
+ AndroidResources.styleable_VectorDrawablePath_strokeLineCap, -1);
+ mStrokeLineCap = getStrokeLineCap(lineCap, mStrokeLineCap);
+ final int lineJoin = TypedArrayUtils.getNamedInt(a, parser, "strokeLineJoin",
+ AndroidResources.styleable_VectorDrawablePath_strokeLineJoin, -1);
+ mStrokeLineJoin = getStrokeLineJoin(lineJoin, mStrokeLineJoin);
+ mStrokeMiterlimit = TypedArrayUtils.getNamedFloat(a, parser, "strokeMiterLimit",
+ AndroidResources.styleable_VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
+ mStrokeColor = TypedArrayUtils.getNamedColor(a, parser, "strokeColor",
+ AndroidResources.styleable_VectorDrawablePath_strokeColor, mStrokeColor);
+ mStrokeAlpha = TypedArrayUtils.getNamedFloat(a, parser, "strokeAlpha",
+ AndroidResources.styleable_VectorDrawablePath_strokeAlpha, mStrokeAlpha);
+ mStrokeWidth = TypedArrayUtils.getNamedFloat(a, parser, "strokeWidth",
+ AndroidResources.styleable_VectorDrawablePath_strokeWidth, mStrokeWidth);
+ mTrimPathEnd = TypedArrayUtils.getNamedFloat(a, parser, "trimPathEnd",
+ AndroidResources.styleable_VectorDrawablePath_trimPathEnd, mTrimPathEnd);
+ mTrimPathOffset = TypedArrayUtils.getNamedFloat(a, parser, "trimPathOffset",
+ AndroidResources.styleable_VectorDrawablePath_trimPathOffset, mTrimPathOffset);
+ mTrimPathStart = TypedArrayUtils.getNamedFloat(a, parser, "trimPathStart",
+ AndroidResources.styleable_VectorDrawablePath_trimPathStart, mTrimPathStart);
}
@Override
@@ -1381,7 +1449,7 @@
/*
* TODO TINT THEME Not supported yet final TypedArray a =
- * t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+ * t.resolveAttributes(mThemeAttrs, styleable_VectorDrawablePath);
* updateStateFromTypedArray(a); a.recycle();
*/
}
diff --git a/graphics/drawable/testanimated/Android.mk b/graphics/drawable/testanimated/Android.mk
index c888d9e..004cddb 100644
--- a/graphics/drawable/testanimated/Android.mk
+++ b/graphics/drawable/testanimated/Android.mk
@@ -18,7 +18,7 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := 11
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -30,6 +30,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v11-animatedvectordrawable android-support-v4
-LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages android.support.graphics.drawable
+LOCAL_AAPT_FLAGS += --auto-add-overlay \
+ --extra-packages android.support.graphics.drawable \
+ --no-version-vectors
include $(BUILD_PACKAGE)
diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
index 7c3b1de..dac981b 100644
--- a/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
+++ b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
@@ -14,14 +14,13 @@
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:drawable="@drawable/vector_drawable_grouping_1" >
+ android:drawable="@drawable/vector_drawable_grouping_1" >
<target
- auto:name="sun"
- auto:animation="@anim/animation_grouping_1_01" />
+ android:name="sun"
+ android:animation="@anim/animation_grouping_1_01" />
<target
- auto:name="earth"
- auto:animation="@anim/animation_grouping_1_01" />
+ android:name="earth"
+ android:animation="@anim/animation_grouping_1_01" />
</animated-vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
index e37d2a1..2944dc2 100644
--- a/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
+++ b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
@@ -14,13 +14,12 @@
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:drawable="@drawable/vector_drawable_progress_bar" >
+ android:drawable="@drawable/vector_drawable_progress_bar" >
<target
- auto:name="pie1"
- auto:animation="@anim/trim_path_animation_progress_bar" />
+ android:name="pie1"
+ android:animation="@anim/trim_path_animation_progress_bar" />
<target
- auto:name="root_bar"
- auto:animation="@anim/alpha_animation_progress_bar" />
+ android:name="root_bar"
+ android:animation="@anim/alpha_animation_progress_bar" />
</animated-vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
index eceda71..06f098e 100644
--- a/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
+++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
@@ -14,37 +14,36 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="256"
- auto:viewportWidth="256" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="256"
+ android:viewportWidth="256" >
<group
- auto:name="shape_layer_1"
- auto:translateX="128"
- auto:translateY="128" >
- <group auto:name="sun" >
+ android:name="shape_layer_1"
+ android:translateX="128"
+ android:translateY="128" >
+ <group android:name="sun" >
<path
- auto:name="ellipse_path_1"
- auto:fillColor="#ffff8000"
- auto:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" />
+ android:name="ellipse_path_1"
+ android:fillColor="#ffff8000"
+ android:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" />
<group
- auto:name="earth"
- auto:translateX="75" >
+ android:name="earth"
+ android:translateX="75" >
<path
- auto:name="ellipse_path_1_1"
- auto:fillColor="#ff5656ea"
- auto:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" />
+ android:name="ellipse_path_1_1"
+ android:fillColor="#ff5656ea"
+ android:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" />
<group
- auto:name="moon"
- auto:translateX="25" >
+ android:name="moon"
+ android:translateX="25" >
<path
- auto:name="ellipse_path_1_2"
- auto:fillColor="#ffadadad"
- auto:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" />
+ android:name="ellipse_path_1_2"
+ android:fillColor="#ffadadad"
+ android:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" />
</group>
</group>
</group>
diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
index 0b8884b..535265e 100644
--- a/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
+++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
@@ -14,36 +14,35 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="64"
- auto:viewportWidth="64"
- auto:name="root_bar" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="64"
+ android:viewportWidth="64"
+ android:name="root_bar" >
<group
- auto:name="root"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="0"
- auto:translateX="32.0"
- auto:translateY="32.0" >
+ android:name="root"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="0"
+ android:translateX="32.0"
+ android:translateY="32.0" >
<group
- auto:name="rotationGroup"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="0" >
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="0" >
<path
- auto:name="pie1"
- auto:fillColor="#00000000"
- auto:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19"
- auto:strokeColor="#FF00FFFF"
- auto:strokeLineCap="round"
- auto:strokeLineJoin="miter"
- auto:strokeWidth="2"
- auto:trimPathEnd="0.1"
- auto:trimPathOffset="0"
- auto:trimPathStart="0" />
+ android:name="pie1"
+ android:fillColor="#00000000"
+ android:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19"
+ android:strokeColor="#FF00FFFF"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="miter"
+ android:strokeWidth="2"
+ android:trimPathEnd="0.1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
</group>
</group>
diff --git a/graphics/drawable/teststatic/Android.mk b/graphics/drawable/teststatic/Android.mk
index d8a0fd7..4c4a7ba 100644
--- a/graphics/drawable/teststatic/Android.mk
+++ b/graphics/drawable/teststatic/Android.mk
@@ -18,7 +18,7 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := 7
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -32,7 +32,8 @@
LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
- --extra-packages android.support.graphics.drawable
+ --extra-packages android.support.graphics.drawable \
+ --no-version-vectors
include $(BUILD_PACKAGE)
diff --git a/graphics/drawable/teststatic/AndroidManifest.xml b/graphics/drawable/teststatic/AndroidManifest.xml
index 19586fb..39ac8ba 100644
--- a/graphics/drawable/teststatic/AndroidManifest.xml
+++ b/graphics/drawable/teststatic/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.support.test.vectordrawable" >
- <uses-sdk android:minSdkVersion="7" />
+ <uses-sdk android:minSdkVersion="7"/>
<application android:icon="@drawable/app_sample_code" android:label="VectorDrawableCompatTest" >
<activity android:name="android.support.test.vectordrawable.TestActivity" />
@@ -29,4 +29,4 @@
</intent-filter>
</application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
index 12357ef..286b487 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
@@ -15,20 +14,16 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="48dp"
- auto:viewportHeight="480"
- auto:viewportWidth="480"
- auto:width="48dp" >
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="480"
+ android:viewportWidth="480" >
<group>
<path
- auto:name="box1"
- auto:fillColor="?android:attr/textColorPrimary"
- auto:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
- auto:strokeColor="?android:attr/colorBackground"
- auto:strokeLineCap="round"
- auto:strokeLineJoin="round" />
+ android:name="box1"
+ android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round" />
</group>
-
-</vector>
\ No newline at end of file
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
index cb6b9df..7567887 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
@@ -1,5 +1,4 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,24 +13,20 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="320"
- auto:viewportWidth="320"
- auto:width="64dp" >
-
+ android:width="64dp"
+ android:height="64dp" android:viewportWidth="320"
+ android:viewportHeight="320">
<group
- auto:pivotX="70"
- auto:pivotY="120"
- auto:rotation="180" >
+ android:rotation="180"
+ android:pivotX="70"
+ android:pivotY="120">
<path
- auto:name="house"
- auto:fillColor="#ff440000"
- auto:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="10"
- auto:trimPathEnd=".9"
- auto:trimPathStart=".1" />
+ android:name="house"
+ android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
+ android:fillColor="#ff440000"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10"
+ android:trimPathStart=".1"
+ android:trimPathEnd=".9"/>
</group>
-
-</vector>
\ No newline at end of file
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
index 37d0086..454468a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
@@ -14,51 +14,57 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="12.25"
- auto:viewportWidth="7.30625"
- auto:width="64dp" >
+ android:height="64dp"
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625"
+ android:width="64dp" >
<group
- auto:pivotX="3.65"
- auto:pivotY="6.125"
- auto:rotation="-30" >
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="-30" >
<clip-path
- auto:name="clip1"
- auto:pathData="
+ android:name="clip1"
+ android:pathData="
M 0, 6.125
l 7.3, 0
l 0, 12.25
l-7.3, 0
z" />
- </group>
- <group>
- <path
- auto:name="one"
- auto:fillColor="#ff88ff"
- auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+
+ <group
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="30" >
+ <path
+ android:name="one"
+ android:fillColor="#ff88ff"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
l-5.046875,0.0 0.0-1.0Z" />
+ </group>
</group>
<group
- auto:pivotX="3.65"
- auto:pivotY="6.125"
- auto:rotation="-30" >
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="-30" >
<clip-path
- auto:name="clip2"
- auto:pathData="
+ android:name="clip2"
+ android:pathData="
M 0, 0
l 7.3, 0
l 0, 6.125
l-7.3, 0
z" />
- </group>
- <group>
- <path
- auto:name="two"
- auto:fillColor="#ff88ff"
- auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+
+ <group
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="30" >
+ <path
+ android:name="two"
+ android:fillColor="#ff88ff"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
@@ -67,6 +73,7 @@
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
q-0.78125024,0.8125-2.2187502,2.265625Z" />
+ </group>
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
index 4e2086f..e6658a6 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
@@ -13,38 +13,41 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp"
- auto:viewportWidth="7.30625"
- auto:viewportHeight="12.25"
- auto:autoMirrored="true">
+ android:autoMirrored="true"
+ android:height="64dp"
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625"
+ android:width="64dp" >
<group>
<clip-path
- auto:name="clip1"
- auto:pathData="
+ android:name="clip1"
+ android:pathData="
M 3.65, 6.125
m-.001, 0
a .001,.001 0 1,0 .002,0
- a .001,.001 0 1,0-.002,0z"/>
- <path
- auto:name="one"
- auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
- l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
- l-5.046875,0.0 0.0-1.0Z"
- auto:fillColor="#ff88ff"/>
+ a .001,.001 0 1,0-.002,0z" />
+ <path
+ android:name="one"
+ android:fillColor="#ff88ff"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+ l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+ l-5.046875,0.0 0.0-1.0Z" />
+ </group>
+ <group>
<clip-path
- auto:name="clip2"
- auto:pathData="
+ android:name="clip2"
+ android:pathData="
M 3.65, 6.125
m-6, 0
a 6,6 0 1,0 12,0
- a 6,6 0 1,0-12,0z"/>
+ a 6,6 0 1,0-12,0z" />
+
<path
- auto:name="two"
- auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+ android:name="two"
+ android:fillColor="#ff88ff"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
@@ -52,7 +55,7 @@
q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
- q-0.78125024,0.8125-2.2187502,2.265625Z"
- auto:fillColor="#ff88ff"/>
+ q-0.78125024,0.8125-2.2187502,2.265625Z" />
</group>
-</vector>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
index 48801e3..d1723dc 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
@@ -14,24 +14,23 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="12.25"
- auto:viewportWidth="7.30625" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625" >
<group>
<path
- auto:name="one"
- auto:fillColor="#ffff00"
- auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+ android:name="one"
+ android:fillColor="#ffff00"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
l-5.046875,0.0 0.0-1.0Z" />
<path
- auto:name="two"
- auto:fillColor="#ffff00"
- auto:fillAlpha="0"
- auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+ android:name="two"
+ android:fillColor="#ffff00"
+ android:fillAlpha="0"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
index 24173e2..4b530fd 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
@@ -13,37 +13,36 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp"
- auto:viewportWidth="700"
- auto:viewportHeight="700">
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="700"
+ android:viewportHeight="700">
<group>
- <path auto:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
- auto:name="path2451"
- auto:fillColor="#00000000"
- auto:strokeColor="#FF000000"
- auto:strokeWidth="30.65500000000000"/>
- <path auto:pathData="M 365.015 311.066"
- auto:name="path2453"
- auto:fillColor="#00000000"
- auto:strokeColor="#FF000000"
- auto:strokeWidth="30.655000000000001"/>
- <path auto:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
- auto:name="path2455"
- auto:strokeColor="#FF000000"
- auto:fillColor="#FFFFFFFF"
- auto:strokeWidth="30.655000000000001"/>
- <path auto:pathData="M 170.515 451.566L 305.61 313.46"
- auto:name="path2457"
- auto:fillColor="#00000000"
- auto:strokeColor="#000000"
- auto:strokeWidth="30.655000000000001"/>
- <path auto:pathData="M 557.968 449.974L 426.515 315.375"
- auto:name="path2459"
- auto:fillColor="#00000000"
- auto:strokeColor="#000000"
- auto:strokeWidth="30.655000000000001"/>
+ <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
+ android:name="path2451"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF000000"
+ android:strokeWidth="30.65500000000000"/>
+ <path android:pathData="M 365.015 311.066"
+ android:name="path2453"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF000000"
+ android:strokeWidth="30.655000000000001"/>
+ <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
+ android:name="path2455"
+ android:strokeColor="#FF000000"
+ android:fillColor="#FFFFFFFF"
+ android:strokeWidth="30.655000000000001"/>
+ <path android:pathData="M 170.515 451.566L 305.61 313.46"
+ android:name="path2457"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeWidth="30.655000000000001"/>
+ <path android:pathData="M 557.968 449.974L 426.515 315.375"
+ android:name="path2459"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeWidth="30.655000000000001"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
index 90435d3..bbf2451 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
@@ -13,18 +13,17 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp" auto:viewportWidth="140"
- auto:viewportHeight="110">
+ android:width="64dp"
+ android:height="64dp" android:viewportWidth="140"
+ android:viewportHeight="110">
<group>
<path
- auto:name="back"
- auto:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z
+ android:name="back"
+ android:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z
M 27,50 l 97,0 0,10-97,0 z
M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z"
- auto:fillColor="#ffffffff"
+ android:fillColor="#ffffffff"
/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
index 251d694..e5b59df 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
@@ -13,18 +13,17 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp" auto:viewportWidth="600"
- auto:viewportHeight="600">
+ android:width="64dp"
+ android:height="64dp" android:viewportWidth="600"
+ android:viewportHeight="600">
<group>
<path
- auto:name="pie1"
- auto:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
- auto:fillColor="#ffffcc00"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="1"/>
+ android:name="pie1"
+ android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
+ android:fillColor="#ffffcc00"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="1"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
index eccb0d0..ce2441d 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
@@ -14,20 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200" >
<group
- auto:pivotX="100"
- auto:pivotY="100"
- auto:rotation="90">
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="90">
<path
- auto:name="house"
- auto:fillColor="#ffffffff"
- auto:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/>
+ android:name="house"
+ android:fillColor="#ffffffff"
+ android:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/>
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
index b26d30d..935d4a5 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
@@ -15,29 +15,28 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportWidth="200"
- auto:viewportHeight="200">
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportWidth="200"
+ android:viewportHeight="200">
<group>
<path
- auto:name="bar3"
- auto:fillColor="#FFFFFFFF"
- auto:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" />
+ android:name="bar3"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" />
<path
- auto:name="bar2"
- auto:fillColor="#FFFFFFFF"
- auto:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
+ android:name="bar2"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
<path
- auto:name="bar1"
- auto:fillColor="#FF555555"
- auto:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
+ android:name="bar1"
+ android:fillColor="#FF555555"
+ android:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
<path
- auto:name="bar0"
- auto:fillColor="#FF555555"
- auto:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" />
+ android:name="bar0"
+ android:fillColor="#FF555555"
+ android:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
index eb440f5..05f481b 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
@@ -14,23 +14,22 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="80"
- auto:viewportWidth="40" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="80"
+ android:viewportWidth="40" >
<group>
<path
- auto:name="battery"
- auto:fillColor="#3388ff"
- auto:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
- auto:strokeColor="#ff8833"
- auto:strokeWidth="1" />
+ android:name="battery"
+ android:fillColor="#3388ff"
+ android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
+ android:strokeColor="#ff8833"
+ android:strokeWidth="1" />
<path
- auto:name="spark"
- auto:fillColor="#FFFF0000"
- auto:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
+ android:name="spark"
+ android:fillColor="#FFFF0000"
+ android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
index 94a23e8..94338a7 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
@@ -14,79 +14,78 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:name="rootGroup"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="600"
- auto:viewportWidth="600"
- auto:alpha="0.5" >
+ android:name="rootGroup"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="600"
+ android:viewportWidth="600"
+ android:alpha="0.5" >
<group
- auto:name="rotationGroup"
- auto:pivotX="300.0"
- auto:pivotY="300.0"
- auto:rotation="45.0" >
+ android:name="rotationGroup"
+ android:pivotX="300.0"
+ android:pivotY="300.0"
+ android:rotation="45.0" >
<path
- auto:name="pie1"
- auto:fillColor="#00000000"
- auto:pathData="M300,70 a230,230 0 1,0 1,0 z"
- auto:strokeColor="#FF777777"
- auto:strokeWidth="70"
- auto:trimPathEnd=".75"
- auto:trimPathOffset="0"
- auto:trimPathStart="0" />
+ android:name="pie1"
+ android:fillColor="#00000000"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+ android:strokeColor="#FF777777"
+ android:strokeWidth="70"
+ android:trimPathEnd=".75"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
<path
- auto:name="v"
- auto:fillColor="#000000"
- auto:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
+ android:name="v"
+ android:fillColor="#000000"
+ android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
<group
- auto:name="translateToCenterGroup"
- auto:rotation="0.0"
- auto:translateX="200.0"
- auto:translateY="200.0" >
+ android:name="translateToCenterGroup"
+ android:rotation="0.0"
+ android:translateX="200.0"
+ android:translateY="200.0" >
<group
- auto:name="rotationGroup2"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroup2"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines1"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="20" />
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroupHalf"
- auto:translateX="65.0"
- auto:translateY="80.0" >
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0" >
<group
- auto:name="rotationGroup3"
- auto:pivotX="-65.0"
- auto:pivotY="-80.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroup3"
+ android:pivotX="-65.0"
+ android:pivotY="-80.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines2"
- auto:fillColor="#FF00FF00"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="20" />
+ android:name="twoLines2"
+ android:fillColor="#FF00FF00"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroup"
- auto:translateX="65.0"
- auto:translateY="80.0" >
+ android:name="translateGroup"
+ android:translateX="65.0"
+ android:translateY="80.0" >
<group
- auto:name="rotationGroupBlue"
- auto:pivotX="-65.0"
- auto:pivotY="-80.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroupBlue"
+ android:pivotX="-65.0"
+ android:pivotY="-80.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines3"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="20" />
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="20" />
</group>
</group>
</group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
index 43fc7ea..097e028 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
@@ -14,25 +14,24 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="600" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="600" >
<group>
<path
- auto:name="pie1"
- auto:fillColor="#ffffffff"
- auto:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="1" />
+ android:name="pie1"
+ android:fillColor="#ffffffff"
+ android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="1" />
<path
- auto:name="half"
- auto:fillColor="#FFFF0000"
- auto:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="5" />
+ android:name="half"
+ android:fillColor="#FFFF0000"
+ android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="5" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
index 5b4fdd1..102ae7a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
@@ -14,26 +14,25 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="500"
- auto:viewportWidth="800" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="500"
+ android:viewportWidth="800" >
<group
- auto:pivotX="90"
- auto:pivotY="100"
- auto:rotation="20">
+ android:pivotX="90"
+ android:pivotY="100"
+ android:rotation="20">
<path
- auto:name="pie2"
- auto:pathData="M200,350 l 50,-25
+ android:name="pie2"
+ android:pathData="M200,350 l 50,-25
a25,12 -30 0,1 100,-50 l 50,-25
a25,25 -30 0,1 100,-50 l 50,-25
a25,37 -30 0,1 100,-50 l 50,-25
a25,50 -30 0,1 100,-50 l 50,-25"
- auto:fillColor="#00000000"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="10" />
+ android:fillColor="#00000000"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
index f4ef87f..bdfcf81 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
@@ -14,22 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="500" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="500" >
<group
- auto:pivotX="250"
- auto:pivotY="200"
- auto:rotation="180">
+ android:pivotX="250"
+ android:pivotY="200"
+ android:rotation="180">
<path
- auto:name="house"
- auto:fillColor="#ff440000"
- auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="10" />
+ android:name="house"
+ android:fillColor="#ff440000"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
index 0c64bca..ed1efa0 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
@@ -14,35 +14,34 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200" >
<group>
<path
- auto:name="background1"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
- auto:fillColor="#FF000000"/>
+ android:name="background1"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
+ android:fillColor="#FF000000"/>
<path
- auto:name="background2"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
- auto:fillColor="#FF000000"/>
+ android:name="background2"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
+ android:fillColor="#FF000000"/>
</group>
<group
- auto:pivotX="100"
- auto:pivotY="100"
- auto:rotation="90"
- auto:scaleX="0.75"
- auto:scaleY="0.5"
- auto:translateX="0.0"
- auto:translateY="100.0">
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="90"
+ android:scaleX="0.75"
+ android:scaleY="0.5"
+ android:translateX="0.0"
+ android:translateY="100.0">
<path
- auto:name="twoLines"
- auto:pathData="M 100,10 v 90 M 10,100 h 90"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="10" />
+ android:name="twoLines"
+ android:pathData="M 100,10 v 90 M 10,100 h 90"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
index 28cf09a..ba15f41 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
@@ -13,18 +13,17 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp" auto:viewportWidth="1200"
- auto:viewportHeight="600">
+ android:width="64dp"
+ android:height="64dp" android:viewportWidth="1200"
+ android:viewportHeight="600">
<group>
<path
- auto:name="house"
- auto:pathData="M200,300 Q400,50 600,300 T1000,300"
- auto:fillColor="#00000000"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="10"/>
+ android:name="house"
+ android:pathData="M200,300 Q400,50 600,300 T1000,300"
+ android:fillColor="#00000000"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="10"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
index d66d4ff..ee2122a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
@@ -14,19 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="500" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="500" >
<group>
<path
- auto:name="house"
- auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- auto:fillColor="#00000000"
- auto:strokeColor="#FFFFFF00"
- auto:strokeWidth="10" />
+ android:name="house"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:fillColor="#00000000"
+ android:strokeColor="#FFFFFF00"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
index 3a6559d..b98e1de 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
@@ -14,21 +14,20 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="800"
- auto:viewportWidth="1000" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="800"
+ android:viewportWidth="1000" >
<group>
<path
- auto:name="house"
- auto:pathData="M10,300 Q400,550 600,300 T1000,300"
- auto:pivotX="90"
- auto:pivotY="100"
- auto:fillColor="#00000000"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="60" />
+ android:name="house"
+ android:pathData="M10,300 Q400,550 600,300 T1000,300"
+ android:pivotX="90"
+ android:pivotY="100"
+ android:fillColor="#00000000"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="60" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
index d6fd704..1c86818 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
@@ -14,22 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="480"
- auto:viewportWidth="480" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="480"
+ android:viewportWidth="480" >
<group>
<path
- auto:name="edit"
- auto:fillColor="#FF00FFFF"
- auto:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+ android:name="edit"
+ android:fillColor="#FF00FFFF"
+ android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40
c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522
c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z"
- auto:strokeColor="#FF000000"
- auto:strokeWidth="10" />
+ android:strokeColor="#FF000000"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
index 9136b73..247f6bc 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
@@ -14,35 +14,34 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200" >
<group>
<path
- auto:name="background1"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
- auto:fillColor="#FF000000"/>
+ android:name="background1"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
+ android:fillColor="#FF000000"/>
<path
- auto:name="background2"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
- auto:fillColor="#FF000000"/>
+ android:name="background2"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
+ android:fillColor="#FF000000"/>
</group>
<group
- auto:pivotX="0"
- auto:pivotY="0"
- auto:rotation="90"
- auto:scaleX="0.75"
- auto:scaleY="0.5"
- auto:translateX="100.0"
- auto:translateY="100.0">
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="90"
+ android:scaleX="0.75"
+ android:scaleY="0.5"
+ android:translateX="100.0"
+ android:translateY="100.0">
<path
- auto:name="twoLines"
- auto:pathData="M 100,10 v 90 M 10,100 h 90"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="10" />
+ android:name="twoLines"
+ android:pathData="M 100,10 v 90 M 10,100 h 90"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
index 2b33a89..39d891f 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
@@ -14,53 +14,52 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="400" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
- <group auto:name="backgroundGroup" >
+ <group android:name="backgroundGroup" >
<path
- auto:name="background1"
- auto:fillColor="#80000000"
- auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background1"
+ android:fillColor="#80000000"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#80000000"
- auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background2"
+ android:fillColor="#80000000"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
</group>
<group
- auto:name="translateToCenterGroup"
- auto:translateX="50.0"
- auto:translateY="90.0" >
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
<path
- auto:name="twoLines"
- auto:pathData="M 0,0 v 100 M 0,0 h 100"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="M 0,0 v 100 M 0,0 h 100"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="20" />
<group
- auto:name="rotationGroup"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines1"
- auto:pathData="M 0,0 v 100 M 0,0 h 100"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="20" />
+ android:name="twoLines1"
+ android:pathData="M 0,0 v 100 M 0,0 h 100"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroup"
- auto:translateX="130.0"
- auto:translateY="160.0" >
- <group auto:name="scaleGroup" >
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0" >
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines2"
- auto:pathData="M 0,0 v 100 M 0,0 h 100"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="20" />
+ android:name="twoLines2"
+ android:pathData="M 0,0 v 100 M 0,0 h 100"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="20" />
</group>
</group>
</group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
index d5759f9..4a1c062 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
@@ -14,67 +14,66 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="400" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
- <group auto:name="backgroundGroup" >
+ <group android:name="backgroundGroup" >
<path
- auto:name="background1"
- auto:fillColor="#80000000"
- auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background1"
+ android:fillColor="#80000000"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#80000000"
- auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background2"
+ android:fillColor="#80000000"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
</group>
<group
- auto:name="translateToCenterGroup"
- auto:translateX="50.0"
- auto:translateY="90.0" >
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
<path
- auto:name="twoLines"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="20" />
<group
- auto:name="rotationGroup"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines1"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="20" />
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroup"
- auto:translateX="130.0"
- auto:translateY="160.0" >
- <group auto:name="scaleGroup" >
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0" >
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines3"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="20" />
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="20" />
</group>
</group>
<group
- auto:name="translateGroupHalf"
- auto:translateX="65.0"
- auto:translateY="80.0" >
- <group auto:name="scaleGroup" >
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0" >
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines2"
- auto:pathData="@string/twoLinePathData"
- auto:fillColor="#FFFFFFFF"
- auto:strokeColor="#FFFFFFFF"
- auto:strokeWidth="20" />
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:fillColor="?android:attr/colorForeground"
+ android:strokeColor="?android:attr/colorForeground"
+ android:strokeWidth="20" />
</group>
</group>
</group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
index b054692..a7a8bd3 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
@@ -14,67 +14,66 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="400" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
- <group auto:name="backgroundGroup">
+ <group android:name="backgroundGroup">
<path
- auto:name="background1"
- auto:fillColor="#FF000000"
- auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#FF000000"
- auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
</group>
<group
- auto:name="translateToCenterGroup"
- auto:translateX="50.0"
- auto:translateY="90.0" >
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
<path
- auto:name="twoLines"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="20" />
<group
- auto:name="rotationGroup"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="-45.0">
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
<path
- auto:name="twoLines1"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="20" />
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroup"
- auto:translateX="130.0"
- auto:translateY="160.0">
- <group auto:name="scaleGroup" >
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines3"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="20" />
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="20" />
</group>
</group>
<group
- auto:name="translateGroupHalf"
- auto:translateX="65.0"
- auto:translateY="80.0">
- <group auto:name="scaleGroup" >
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines2"
- auto:pathData="@string/twoLinePathData"
- auto:fillColor="#FFFFFFFF"
- auto:strokeColor="#FFFFFFFF"
- auto:strokeWidth="20" />
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:fillColor="?android:attr/colorForeground"
+ android:strokeColor="?android:attr/colorForeground"
+ android:strokeWidth="20" />
</group>
</group>
</group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
index 7a94ed6..7c9e771 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
@@ -14,70 +14,69 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="400" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
<group
- auto:name="FirstLevelGroup"
- auto:translateX="100.0"
- auto:translateY="0.0" >
+ android:name="FirstLevelGroup"
+ android:translateX="100.0"
+ android:translateY="0.0" >
<group
- auto:name="SecondLevelGroup1"
- auto:translateX="-100.0"
- auto:translateY="50.0" >
+ android:name="SecondLevelGroup1"
+ android:translateX="-100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF00FF00"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF00FF00"
+ android:pathData="@string/rectangle200" />
<group
- auto:name="ThridLevelGroup1"
- auto:translateX="-100.0"
- auto:translateY="50.0" >
+ android:name="ThridLevelGroup1"
+ android:translateX="-100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF0000FF"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF0000FF"
+ android:pathData="@string/rectangle200" />
</group>
<group
- auto:name="ThridLevelGroup2"
- auto:translateX="100.0"
- auto:translateY="50.0" >
+ android:name="ThridLevelGroup2"
+ android:translateX="100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF000000"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF000000"
+ android:pathData="@string/rectangle200" />
</group>
</group>
<group
- auto:name="SecondLevelGroup2"
- auto:translateX="100.0"
- auto:translateY="50.0" >
+ android:name="SecondLevelGroup2"
+ android:translateX="100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF0000FF"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF0000FF"
+ android:pathData="@string/rectangle200" />
<group
- auto:name="ThridLevelGroup3"
- auto:translateX="-100.0"
- auto:translateY="50.0" >
+ android:name="ThridLevelGroup3"
+ android:translateX="-100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FFFF0000"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FFFF0000"
+ android:pathData="@string/rectangle200" />
</group>
<group
- auto:name="ThridLevelGroup4"
- auto:translateX="100.0"
- auto:translateY="50.0" >
+ android:name="ThridLevelGroup4"
+ android:translateX="100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF00FF00"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF00FF00"
+ android:pathData="@string/rectangle200" />
</group>
</group>
<path
- auto:fillColor="#FFFF0000"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FFFF0000"
+ android:pathData="@string/rectangle200" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
index b2dd4a3..eda06d8 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
@@ -14,33 +14,32 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200"
- auto:width="64dp" >
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
<group>
<path
- auto:name="background1"
- auto:fillColor="#FF000000"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#FF000000"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
</group>
<group
- auto:translateX="50"
- auto:translateY="50" >
+ android:translateX="50"
+ android:translateY="50" >
<path
- auto:name="twoLines"
- auto:pathData="M 100,20 l 0 80 l -30 -80"
- auto:strokeColor="#FF00FF00"
- auto:strokeLineCap="butt"
- auto:strokeLineJoin="miter"
- auto:strokeMiterLimit="5"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="M 100,20 l 0 80 l -30 -80"
+ android:strokeColor="#FF00FF00"
+ android:strokeLineCap="butt"
+ android:strokeLineJoin="miter"
+ android:strokeMiterLimit="5"
+ android:strokeWidth="20" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
index b8f88ce..cd46dd9 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
@@ -14,33 +14,32 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200"
- auto:width="64dp" >
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
<group>
<path
- auto:name="background1"
- auto:fillColor="#FF000000"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#FF000000"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
</group>
<group
- auto:translateX="50"
- auto:translateY="50" >
+ android:translateX="50"
+ android:translateY="50" >
<path
- auto:name="twoLines"
- auto:pathData="M 100,20 l 0 80 l -30 -80"
- auto:strokeColor="#FF00FF00"
- auto:strokeLineCap="round"
- auto:strokeLineJoin="round"
- auto:strokeMiterLimit="10"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="M 100,20 l 0 80 l -30 -80"
+ android:strokeColor="#FF00FF00"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeMiterLimit="10"
+ android:strokeWidth="20" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
index 30c7fce..812af6b 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
@@ -14,34 +14,33 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200"
- auto:width="64dp"
- auto:autoMirrored="true" >
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp"
+ android:autoMirrored="true" >
<group>
<path
- auto:name="background1"
- auto:fillColor="#FF000000"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#FF000000"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
</group>
<group
- auto:translateX="50"
- auto:translateY="50" >
+ android:translateX="50"
+ android:translateY="50" >
<path
- auto:name="twoLines"
- auto:pathData="M 100,20 l 0 80 l -30 -80"
- auto:strokeColor="#FF00FF00"
- auto:strokeLineCap="square"
- auto:strokeLineJoin="bevel"
- auto:strokeMiterLimit="10"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="M 100,20 l 0 80 l -30 -80"
+ android:strokeColor="#FF00FF00"
+ android:strokeLineCap="square"
+ android:strokeLineJoin="bevel"
+ android:strokeMiterLimit="10"
+ android:strokeWidth="20" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
index 2ac1d42..b24d31c 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
@@ -14,16 +14,15 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="48dp"
- auto:width="48dp"
- auto:viewportHeight="1"
- auto:viewportWidth="1" >
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="1"
+ android:viewportWidth="1" >
<group>
<path
- auto:name="box1"
- auto:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z"
- auto:fillColor="#ff00ff00"/>
+ android:name="box1"
+ android:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z"
+ android:fillColor="#ff00ff00"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
index 6abb455..24f7372 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
@@ -14,16 +14,15 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="48dp"
- auto:width="48dp"
- auto:viewportHeight="48"
- auto:viewportWidth="48" >
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48" >
<group>
<path
- auto:name="plus1"
- auto:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
- auto:fillColor="#ff00ff00"/>
+ android:name="plus1"
+ android:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
+ android:fillColor="#ff00ff00"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml
new file mode 100644
index 0000000..828f0d9
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml
@@ -0,0 +1,57 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
+
+ <group>
+ <path
+ android:name="background1"
+ android:fillColor="@color/color0"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/color2"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="90" >
+ <group
+ android:scaleX="1.5"
+ android:scaleY="1" >
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="-90" >
+ <group
+ android:scaleX="1.5"
+ android:scaleY="1" >
+ <path
+ android:name="twoLines"
+ android:fillColor="#FFFF0000"
+ android:pathData="@string/triangle100"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml
new file mode 100644
index 0000000..530c73b
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
+
+ <group>
+ <path
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ android:scaleX="-1"
+ android:scaleY="-1" >
+ <group
+ android:scaleX="-1"
+ android:scaleY="-1" >
+ <group
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="45" >
+ <path
+ android:name="twoLines"
+ android:fillColor="#FFFF0000"
+ android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml
new file mode 100644
index 0000000..200eb61
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml
@@ -0,0 +1,48 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
+
+ <group>
+ <path
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ android:scaleX="2"
+ android:scaleY="0.5" >
+ <group
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="45" >
+ <path
+ android:name="twoLines"
+ android:fillColor="#FFFF0000"
+ android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml
new file mode 100644
index 0000000..a40fc9c2
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml
@@ -0,0 +1,62 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
+
+ <group>
+ <path
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="45" >
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="90" >
+ <group
+ android:scaleX="1.5"
+ android:scaleY="1" >
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="-90" >
+ <group
+ android:scaleX="1.5"
+ android:scaleY="1" >
+ <path
+ android:name="twoLines"
+ android:fillColor="#FFFF0000"
+ android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_test01.xml b/graphics/drawable/teststatic/res/drawable/vector_test01.xml
new file mode 100644
index 0000000..8b891d6
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_test01.xml
@@ -0,0 +1,31 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="128dp"
+ android:width="128dp"
+ android:viewportHeight="512"
+ android:viewportWidth="512" >
+
+ <group>
+ <path
+ android:name="002b"
+ android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="4"
+ android:fillColor="#00000000" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_test02.xml b/graphics/drawable/teststatic/res/drawable/vector_test02.xml
new file mode 100644
index 0000000..e0af323
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_test02.xml
@@ -0,0 +1,31 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="128dp"
+ android:width="128dp"
+ android:viewportHeight="512"
+ android:viewportWidth="512" >
+
+ <group>
+ <path
+ android:name="002b"
+ android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="4"
+ android:fillColor="#00000000" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/graphics/drawable/teststatic/res/values/colors.xml
similarity index 69%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to graphics/drawable/teststatic/res/values/colors.xml
index a4614f6..6eb3036 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/graphics/drawable/teststatic/res/values/colors.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -13,7 +12,9 @@
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:drawable="@drawable/ic_setting_light" />
-</selector>
+<resources>
+ <color name="color0">#a6e4ea</color>
+ <color name="color1">#ff3838</color>
+ <color name="color2">#ffff51</color>
+ <color name="color3">#0ed300</color>
+</resources>
diff --git a/graphics/drawable/teststatic/res/values/strings.xml b/graphics/drawable/teststatic/res/values/strings.xml
index c5451c88..065e7d9 100644
--- a/graphics/drawable/teststatic/res/values/strings.xml
+++ b/graphics/drawable/teststatic/res/values/strings.xml
@@ -25,4 +25,5 @@
<string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string>
<string name="heart"> "m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string>
<string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
-</resources>
\ No newline at end of file
+ <string name="triangle100">"M 100, 0 l 0, 100, -100, 0 z"</string>
+</resources>
diff --git a/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
index 8bb766e5..c92ff47 100644
--- a/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
+++ b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
@@ -34,6 +34,10 @@
private static final String LOGCAT = "VectorDrawable1";
protected int[] icon = {
+ R.drawable.vector_drawable_scale0,
+ R.drawable.vector_drawable_scale1,
+ R.drawable.vector_drawable_scale2,
+ R.drawable.vector_drawable_scale3,
R.drawable.vector_drawable01,
R.drawable.vector_drawable02,
R.drawable.vector_drawable03,
@@ -64,6 +68,8 @@
R.drawable.vector_drawable28,
R.drawable.vector_drawable29,
R.drawable.vector_drawable30,
+ R.drawable.vector_test01,
+ R.drawable.vector_test02
};
private static final int EXTRA_TESTS = 2;
@@ -85,8 +91,10 @@
time = android.os.SystemClock.currentThreadTimeMillis()-time;
// Testing Tint on one particular case.
- d[3].setTint(0x8000FF00);
- d[3].setTintMode(Mode.MULTIPLY);
+ if (d.length > 3) {
+ d[3].setTint(0x8000FF00);
+ d[3].setTintMode(Mode.MULTIPLY);
+ }
// Testing Constant State like operation by creating the first 2 icons
// from the 3rd one's constant state.
diff --git a/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java b/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java
new file mode 100644
index 0000000..e6b2e14
--- /dev/null
+++ b/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package android.support.graphics.drawable;
+
+public class AndroidResources {
+
+ // Resources ID generated in the latest R.java for framework.
+ static final int[] styleable_VectorDrawableTypeArray = {
+ android.R.attr.name, android.R.attr.tint, android.R.attr.height,
+ android.R.attr.width, android.R.attr.alpha, android.R.attr.autoMirrored,
+ android.R.attr.mode, android.R.attr.viewportWidth, android.R.attr.viewportHeight
+ };
+ static final int styleable_VectorDrawable_alpha = 4;
+ static final int styleable_VectorDrawable_autoMirrored = 5;
+ static final int styleable_VectorDrawable_height = 2;
+ static final int styleable_VectorDrawable_name = 0;
+ static final int styleable_VectorDrawable_tint = 1;
+ static final int styleable_VectorDrawable_Mode = 6;
+ static final int styleable_VectorDrawable_viewportHeight = 8;
+ static final int styleable_VectorDrawable_viewportWidth = 7;
+ static final int styleable_VectorDrawable_width = 3;
+ static final int[] styleable_VectorDrawableGroup = {
+ android.R.attr.name, android.R.attr.pivotX, android.R.attr.pivotY,
+ android.R.attr.scaleX, android.R.attr.scaleY, android.R.attr.rotation,
+ android.R.attr.translateX, android.R.attr.translateY
+ };
+ static final int styleable_VectorDrawableGroup_name = 0;
+ static final int styleable_VectorDrawableGroup_pivotX = 1;
+ static final int styleable_VectorDrawableGroup_pivotY = 2;
+ static final int styleable_VectorDrawableGroup_rotation = 5;
+ static final int styleable_VectorDrawableGroup_scaleX = 3;
+ static final int styleable_VectorDrawableGroup_scaleY = 4;
+ static final int styleable_VectorDrawableGroup_translateX = 6;
+ static final int styleable_VectorDrawableGroup_translateY = 7;
+ static final int[] styleable_VectorDrawablePath = {
+ android.R.attr.name, android.R.attr.fillColor, android.R.attr.pathData,
+ android.R.attr.strokeColor, android.R.attr.strokeWidth, android.R.attr.trimPathStart,
+ android.R.attr.trimPathEnd, android.R.attr.trimPathOffset, android.R.attr.strokeLineCap,
+ android.R.attr.strokeLineJoin, android.R.attr.strokeMiterLimit,
+ android.R.attr.strokeAlpha, android.R.attr.fillAlpha
+ };
+ static final int styleable_VectorDrawablePath_fillAlpha = 12;
+ static final int styleable_VectorDrawablePath_fillColor = 1;
+ static final int styleable_VectorDrawablePath_name = 0;
+ static final int styleable_VectorDrawablePath_pathData = 2;
+ static final int styleable_VectorDrawablePath_strokeAlpha = 11;
+ static final int styleable_VectorDrawablePath_strokeColor = 3;
+ static final int styleable_VectorDrawablePath_strokeLineCap = 8;
+ static final int styleable_VectorDrawablePath_strokeLineJoin = 9;
+ static final int styleable_VectorDrawablePath_strokeMiterLimit = 10;
+ static final int styleable_VectorDrawablePath_strokeWidth = 4;
+ static final int styleable_VectorDrawablePath_trimPathEnd = 6;
+ static final int styleable_VectorDrawablePath_trimPathOffset = 7;
+ static final int styleable_VectorDrawablePath_trimPathStart = 5;
+ static final int[] styleable_VectorDrawableClipPath = {
+ android.R.attr.name, android.R.attr.pathData
+ };
+ static final int styleable_VectorDrawableClipPath_name = 0;
+ static final int styleable_VectorDrawableClipPath_pathData = 1;
+
+ static final int[] styleable_AnimatedVectorDrawable = {
+ android.R.attr.drawable
+ };
+ static final int styleable_AnimatedVectorDrawable_drawable = 0;
+ static final int[] styleable_AnimatedVectorDrawableTarget = {
+ android.R.attr.name, android.R.attr.animation
+ };
+ static final int styleable_AnimatedVectorDrawableTarget_animation = 1;
+ static final int styleable_AnimatedVectorDrawableTarget_name = 0;
+}
diff --git a/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java b/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java
new file mode 100644
index 0000000..161eae6
--- /dev/null
+++ b/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package android.support.graphics.drawable;
+
+import android.content.res.TypedArray;
+import org.xmlpull.v1.XmlPullParser;
+
+
+public class TypedArrayUtils {
+ private static final String NAMESPACE = "http://schemas.android.com/apk/res/android";
+
+ public static boolean hasAttribute(XmlPullParser parser, String attrName) {
+ return parser.getAttributeValue(NAMESPACE, attrName) != null;
+ }
+
+ public static float getNamedFloat(TypedArray a, XmlPullParser parser, String attrName,
+ int resId, float defaultValue) {
+ final boolean hasAttr = hasAttribute(parser, attrName);
+ if (!hasAttr) {
+ return defaultValue;
+ } else {
+ return a.getFloat(resId, defaultValue);
+ }
+ }
+
+ public static boolean getNamedBoolean(TypedArray a, XmlPullParser parser, String attrName,
+ int resId, boolean defaultValue) {
+ final boolean hasAttr = hasAttribute(parser, attrName);
+ if (!hasAttr) {
+ return defaultValue;
+ } else {
+ return a.getBoolean(resId, defaultValue);
+ }
+ }
+
+ public static int getNamedInt(TypedArray a, XmlPullParser parser, String attrName,
+ int resId, int defaultValue) {
+ final boolean hasAttr = hasAttribute(parser, attrName);
+ if (!hasAttr) {
+ return defaultValue;
+ } else {
+ return a.getInt(resId, defaultValue);
+ }
+ }
+
+ public static int getNamedColor(TypedArray a, XmlPullParser parser, String attrName,
+ int resId, int defaultValue) {
+ final boolean hasAttr = hasAttribute(parser, attrName);
+ if (!hasAttr) {
+ return defaultValue;
+ } else {
+ return a.getColor(resId, defaultValue);
+ }
+ }
+}
diff --git a/local.properties b/local.properties
index 5b31c8a..8aea008 100644
--- a/local.properties
+++ b/local.properties
@@ -1 +1,11 @@
-android.dir=../../
\ No newline at end of file
+## This file is automatically generated by Android Studio.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Fri Aug 21 16:47:26 KST 2015
+android.dir=../../
diff --git a/percent/api/23.txt b/percent/api/23.0.0.txt
similarity index 100%
rename from percent/api/23.txt
rename to percent/api/23.0.0.txt
diff --git a/percent/api/23.1.0.txt b/percent/api/23.1.0.txt
new file mode 100644
index 0000000..eb10df8
--- /dev/null
+++ b/percent/api/23.1.0.txt
@@ -0,0 +1,65 @@
+package android.support.percent {
+
+ public class PercentFrameLayout extends android.widget.FrameLayout {
+ ctor public PercentFrameLayout(android.content.Context);
+ ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet);
+ ctor public PercentFrameLayout(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public static class PercentFrameLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+ ctor public PercentFrameLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public PercentFrameLayout.LayoutParams(int, int);
+ ctor public PercentFrameLayout.LayoutParams(int, int, int);
+ ctor public PercentFrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public PercentFrameLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public PercentFrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+ ctor public PercentFrameLayout.LayoutParams(android.support.percent.PercentFrameLayout.LayoutParams);
+ method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+ }
+
+ public class PercentLayoutHelper {
+ ctor public PercentLayoutHelper(android.view.ViewGroup);
+ method public void adjustChildren(int, int);
+ method public static void fetchWidthAndHeight(android.view.ViewGroup.LayoutParams, android.content.res.TypedArray, int, int);
+ method public static android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo(android.content.Context, android.util.AttributeSet);
+ method public boolean handleMeasuredStateTooSmall();
+ method public void restoreOriginalParams();
+ }
+
+ public static class PercentLayoutHelper.PercentLayoutInfo {
+ ctor public PercentLayoutHelper.PercentLayoutInfo();
+ method public void fillLayoutParams(android.view.ViewGroup.LayoutParams, int, int);
+ method public void fillMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams, int, int);
+ method public void restoreLayoutParams(android.view.ViewGroup.LayoutParams);
+ method public void restoreMarginLayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ field public float aspectRatio;
+ field public float bottomMarginPercent;
+ field public float endMarginPercent;
+ field public float heightPercent;
+ field public float leftMarginPercent;
+ field public float rightMarginPercent;
+ field public float startMarginPercent;
+ field public float topMarginPercent;
+ field public float widthPercent;
+ }
+
+ public static abstract interface PercentLayoutHelper.PercentLayoutParams {
+ method public abstract android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+ }
+
+ public class PercentRelativeLayout extends android.widget.RelativeLayout {
+ ctor public PercentRelativeLayout(android.content.Context);
+ ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet);
+ ctor public PercentRelativeLayout(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public static class PercentRelativeLayout.LayoutParams extends android.widget.RelativeLayout.LayoutParams implements android.support.percent.PercentLayoutHelper.PercentLayoutParams {
+ ctor public PercentRelativeLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public PercentRelativeLayout.LayoutParams(int, int);
+ ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public PercentRelativeLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ method public android.support.percent.PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo();
+ }
+
+}
+
diff --git a/percent/build.gradle b/percent/build.gradle
index 28907b8..6fbc478 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -28,3 +28,70 @@
targetCompatibility JavaVersion.VERSION_1_7
}
}
+
+android.libraryVariants.all { variant ->
+ def name = variant.buildType.name
+
+ if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
+ return; // Skip debug builds.
+ }
+ def suffix = name.capitalize()
+
+ def jarTask = project.tasks.create(name: "jar${suffix}", type: Jar){
+ dependsOn variant.javaCompile
+ from variant.javaCompile.destinationDir
+ from 'LICENSE.txt'
+ }
+ def javadocTask = project.tasks.create(name: "javadoc${suffix}", type: Javadoc) {
+ source android.sourceSets.main.java
+ classpath = files(variant.javaCompile.classpath.files) + files(
+ "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar")
+ }
+
+ def javadocJarTask = project.tasks.create(name: "javadocJar${suffix}", type: Jar) {
+ classifier = 'javadoc'
+ from 'build/docs/javadoc'
+ }
+
+ def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
+ classifier = 'sources'
+ from android.sourceSets.main.java.srcDirs
+ }
+
+ artifacts.add('archives', javadocJarTask);
+ artifacts.add('archives', sourcesJarTask);
+}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: uri(rootProject.ext.supportRepoOut)) {
+ }
+
+ pom.project {
+ name 'Android Percent Support Library'
+ description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 7 or later."
+ url 'http://developer.android.com/tools/extras/support-library.html'
+ inceptionYear '2011'
+
+ licenses {
+ license {
+ name 'The Apache Software License, Version 2.0'
+ url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ distribution 'repo'
+ }
+ }
+
+ scm {
+ url "http://source.android.com"
+ connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+ }
+ developers {
+ developer {
+ name 'The Android Open Source Project'
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/recommendation/api/23.txt b/recommendation/api/23.0.0.txt
similarity index 100%
rename from recommendation/api/23.txt
rename to recommendation/api/23.0.0.txt
diff --git a/recommendation/api/23.txt b/recommendation/api/23.1.0.txt
similarity index 100%
copy from recommendation/api/23.txt
copy to recommendation/api/23.1.0.txt
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index 0a9ca47..a9db906 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -16,16 +16,19 @@
sourceSets {
main.manifest.srcFile 'AndroidManifest.xml'
main.java.srcDirs = ['src']
- main.res.srcDirs = ['res']
+ main.res.srcDir 'res'
+ main.assets.srcDir 'assets'
+ main.resources.srcDir 'src'
+
+ // this moves src/instrumentTest to tests so all folders follow:
+ // tests/java, tests/res, tests/assets, ...
+ // This is a *reset* so it replaces the default paths
+ androidTest.setRoot('tests')
+ androidTest.java.srcDir 'tests/src'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
-
- lintOptions {
- // TODO: fix errors and reenable.
- abortOnError false
- }
}
diff --git a/recommendation/src/android/support/app/recommendation/ContentRecommendation.java b/recommendation/src/android/support/app/recommendation/ContentRecommendation.java
index fdc0907..11af02d 100644
--- a/recommendation/src/android/support/app/recommendation/ContentRecommendation.java
+++ b/recommendation/src/android/support/app/recommendation/ContentRecommendation.java
@@ -22,6 +22,8 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.annotation.StringDef;
@@ -799,7 +801,7 @@
* @param iconResourceId An integer id for the badge icon resource.
* @return The Builder object, for chaining.
*/
- public Builder setBadgeIcon(int iconResourceId) {
+ public Builder setBadgeIcon(@DrawableRes int iconResourceId) {
mBuilderBadgeIconId = iconResourceId;
return this;
}
@@ -823,7 +825,7 @@
* @param color An integer value representing the accent color for this recommendation.
* @return The Builder object, for chaining.
*/
- public Builder setColor(int color) {
+ public Builder setColor(@ColorInt int color) {
mBuilderColor = color;
return this;
}
diff --git a/scripts/support-deps-license.sh b/scripts/support-deps-license.sh
new file mode 100755
index 0000000..55efac6
--- /dev/null
+++ b/scripts/support-deps-license.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+#
+# This needs to be ran from the root folder in the Android source tree
+#
+
+function parentdirname() {
+ FULL_PATH=`readlink -f $1`
+ echo `dirname $FULL_PATH`
+}
+
+function rundeps() {
+ LIB_PATH=$1
+ LIB_PARENT_PATH=`parentdirname $LIB_PATH`
+ OUTPUT_FILE=`basename $LIB_PARENT_PATH`-`basename $LIB_PATH`.log
+ make deps-license PROJ_PATH=$LIB_PATH DEP_PATH=frameworks/support > $OUTPUT_FILE
+}
+
+rundeps frameworks/support/customtabs
+rundeps frameworks/support/design
+rundeps frameworks/support/percent
+rundeps frameworks/support/recommendation
+rundeps frameworks/support/v4
+rundeps frameworks/support/v7/appcompat
+rundeps frameworks/support/v7/cardview
+rundeps frameworks/support/v7/mediarouter
+rundeps frameworks/support/v7/palette
+rundeps frameworks/support/v7/gridlayout
+rundeps frameworks/support/v7/preference
+rundeps frameworks/support/v7/recyclerview
+rundeps frameworks/support/v13
+rundeps frameworks/support/v14/preference
+rundeps frameworks/support/v17/leanback
+rundeps frameworks/support/v17/preference-leanback
diff --git a/settings.gradle b/settings.gradle
index 4c4ac52..d33c2ac 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -48,3 +48,6 @@
include ':support-customtabs'
project(':support-customtabs').projectDir = new File(rootDir, 'customtabs')
+
+include ':support-recommendation'
+project(':support-recommendation').projectDir = new File(rootDir, 'recommendation')
diff --git a/v13/api/23.txt b/v13/api/23.0.0.txt
similarity index 100%
rename from v13/api/23.txt
rename to v13/api/23.0.0.txt
diff --git a/v13/api/23.txt b/v13/api/23.1.0.txt
similarity index 100%
copy from v13/api/23.txt
copy to v13/api/23.1.0.txt
diff --git a/v14/preference/NOTICES.md b/v14/preference/NOTICES.md
new file mode 100644
index 0000000..a390782
--- /dev/null
+++ b/v14/preference/NOTICES.md
@@ -0,0 +1,11 @@
+# Change Log
+
+## [23.1.0](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/v14/preference) (2015-09-28)
+
+**Breakage and deprecation notices:**
+
+- EditTextPreferenceDialogFragment
+ - onAddEditTextToDialogView has been removed. Any code depending on overriding this method should
+ be moved to onBindDialogView.
+ - The EditText view is now expected to be present in the dialog layout file with the id
+ @android:id/edit, and is no longer created in code.
diff --git a/v14/preference/api/23.txt b/v14/preference/api/23.0.0.txt
similarity index 100%
rename from v14/preference/api/23.txt
rename to v14/preference/api/23.0.0.txt
diff --git a/v14/preference/api/23.1.0.txt b/v14/preference/api/23.1.0.txt
new file mode 100644
index 0000000..fed4623
--- /dev/null
+++ b/v14/preference/api/23.1.0.txt
@@ -0,0 +1,94 @@
+package android.support.v14.preference {
+
+ public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+ ctor public EditTextPreferenceDialogFragment();
+ method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
+ method public void onDialogClosed(boolean);
+ }
+
+ public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+ ctor public ListPreferenceDialogFragment();
+ method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
+ method public void onDialogClosed(boolean);
+ }
+
+ public class MultiSelectListPreference extends android.support.v7.preference.DialogPreference {
+ ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
+ ctor public MultiSelectListPreference(android.content.Context);
+ method public int findIndexOfValue(java.lang.String);
+ method public java.lang.CharSequence[] getEntries();
+ method public java.lang.CharSequence[] getEntryValues();
+ method protected boolean[] getSelectedItems();
+ method public java.util.Set<java.lang.String> getValues();
+ method public void setEntries(java.lang.CharSequence[]);
+ method public void setEntries(int);
+ method public void setEntryValues(java.lang.CharSequence[]);
+ method public void setEntryValues(int);
+ method public void setValues(java.util.Set<java.lang.String>);
+ }
+
+ public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+ ctor public MultiSelectListPreferenceDialogFragment();
+ method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
+ method public void onDialogClosed(boolean);
+ }
+
+ public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+ ctor public PreferenceDialogFragment();
+ method public android.support.v7.preference.DialogPreference getPreference();
+ method protected void onBindDialogView(android.view.View);
+ method public void onClick(android.content.DialogInterface, int);
+ method protected android.view.View onCreateDialogView(android.content.Context);
+ method public abstract void onDialogClosed(boolean);
+ method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
+ field protected static final java.lang.String ARG_KEY = "key";
+ }
+
+ public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+ ctor public PreferenceFragment();
+ method public void addPreferencesFromResource(int);
+ method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ method public final android.support.v7.widget.RecyclerView getListView();
+ method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+ method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+ method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+ method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+ method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+ method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+ method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+ method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+ method public void setPreferencesFromResource(int, java.lang.String);
+ field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+ }
+
+ public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
+ method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+ method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
+ method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
+ }
+
+ public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
+ ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
+ ctor public SwitchPreference(android.content.Context);
+ method public java.lang.CharSequence getSwitchTextOff();
+ method public java.lang.CharSequence getSwitchTextOn();
+ method public void setSwitchTextOff(java.lang.CharSequence);
+ method public void setSwitchTextOff(int);
+ method public void setSwitchTextOn(java.lang.CharSequence);
+ method public void setSwitchTextOn(int);
+ }
+
+}
+
diff --git a/v14/preference/api/current.txt b/v14/preference/api/current.txt
index cbf8fe5..5ebd7cf 100644
--- a/v14/preference/api/current.txt
+++ b/v14/preference/api/current.txt
@@ -3,7 +3,6 @@
public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
ctor public EditTextPreferenceDialogFragment();
method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
- method protected void onAddEditTextToDialogView(android.view.View, android.widget.EditText);
method public void onDialogClosed(boolean);
}
@@ -61,6 +60,8 @@
method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ method public void setDivider(android.graphics.drawable.Drawable);
+ method public void setDividerHeight(int);
method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
method public void setPreferencesFromResource(int, java.lang.String);
field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index 772b353..b5129b1 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -54,3 +54,37 @@
abortOnError false
}
}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: uri(rootProject.ext.supportRepoOut)) {
+ }
+
+ pom.project {
+ name 'Android Support Preference v14'
+ description "Android Support Preference v14"
+ url 'http://developer.android.com/tools/extras/support-library.html'
+ inceptionYear '2015'
+
+ licenses {
+ license {
+ name 'The Apache Software License, Version 2.0'
+ url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ distribution 'repo'
+ }
+ }
+
+ scm {
+ url "http://source.android.com"
+ connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+ }
+ developers {
+ developer {
+ name 'The Android Open Source Project'
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/v14/preference/res/drawable/preference_list_divider_material.xml b/v14/preference/res/drawable/preference_list_divider_material.xml
new file mode 100644
index 0000000..a5913deb
--- /dev/null
+++ b/v14/preference/res/drawable/preference_list_divider_material.xml
@@ -0,0 +1,24 @@
+<?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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:tint="?android:attr/colorForeground">
+ <solid android:color="#1f000000" />
+ <size
+ android:height="1dp"
+ android:width="1dp" />
+</shape>
diff --git a/v14/preference/res/layout-v17/preference_information_material.xml b/v14/preference/res/layout-v17/preference_information_material.xml
index a376c6a..7b1d823 100644
--- a/v14/preference/res/layout-v17/preference_information_material.xml
+++ b/v14/preference/res/layout-v17/preference_information_material.xml
@@ -48,7 +48,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItem" />
+ android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead" />
<TextView android:id="@android:id/summary"
android:layout_width="wrap_content"
diff --git a/v14/preference/res/layout-v17/preference_material.xml b/v14/preference/res/layout-v17/preference_material.xml
index e624773..bc56718 100644
--- a/v14/preference/res/layout-v17/preference_material.xml
+++ b/v14/preference/res/layout-v17/preference_material.xml
@@ -23,7 +23,7 @@
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:background="?android:attr/activatedBackgroundIndicator"
+ android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false"
android:focusable="true" >
@@ -57,7 +57,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItem"
+ android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
android:ellipsize="marquee" />
<TextView android:id="@android:id/summary"
diff --git a/v14/preference/res/layout-v21/preference_material.xml b/v14/preference/res/layout-v21/preference_material.xml
index 392a2ea..da6b69f 100644
--- a/v14/preference/res/layout-v21/preference_material.xml
+++ b/v14/preference/res/layout-v21/preference_material.xml
@@ -23,7 +23,7 @@
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:background="?android:attr/activatedBackgroundIndicator"
+ android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false"
android:focusable="true" >
diff --git a/v14/preference/res/layout/preference_information_material.xml b/v14/preference/res/layout/preference_information_material.xml
index 54a577c..1090c61 100644
--- a/v14/preference/res/layout/preference_information_material.xml
+++ b/v14/preference/res/layout/preference_information_material.xml
@@ -48,7 +48,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItem" />
+ android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead" />
<TextView android:id="@android:id/summary"
android:layout_width="wrap_content"
diff --git a/v14/preference/res/layout/preference_material.xml b/v14/preference/res/layout/preference_material.xml
index 6135053..e25340e 100644
--- a/v14/preference/res/layout/preference_material.xml
+++ b/v14/preference/res/layout/preference_material.xml
@@ -23,7 +23,7 @@
android:gravity="center_vertical"
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
android:paddingRight="?android:attr/listPreferredItemPaddingRight"
- android:background="?android:attr/activatedBackgroundIndicator"
+ android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false"
android:focusable="true" >
@@ -57,7 +57,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItem"
+ android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
android:ellipsize="marquee" />
<TextView android:id="@android:id/summary"
diff --git a/v17/preference-leanback/res/values/ids.xml b/v14/preference/res/values-v17/styles.xml
similarity index 80%
rename from v17/preference-leanback/res/values/ids.xml
rename to v14/preference/res/values-v17/styles.xml
index 20c1eda..e0b478f 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v14/preference/res/values-v17/styles.xml
@@ -16,5 +16,9 @@
-->
<resources>
- <item name="transitionPosition" type="id" />
+ <style name="PreferenceFragmentList.Material">
+ <item name="android:paddingStart">0dp</item>
+ <item name="android:paddingEnd">0dp</item>
+ </style>
+
</resources>
diff --git a/v14/preference/res/values/attrs.xml b/v14/preference/res/values/attrs.xml
index 62d9e47..16f9699 100644
--- a/v14/preference/res/values/attrs.xml
+++ b/v14/preference/res/values/attrs.xml
@@ -1,19 +1,19 @@
<?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
- -->
+ 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
+ -->
<resources>
<declare-styleable name="SwitchPreference">
@@ -52,4 +52,15 @@
<attr name="entryValues" />
<attr name="android:entryValues" />
</declare-styleable>
+
+ <!-- Base attributes available to PreferenceFragment. -->
+ <declare-styleable name="PreferenceFragment">
+ <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
+ <attr name="android:layout" />
+ <!-- List separator to draw between preference views -->
+ <attr name="android:divider" />
+ <!-- List separator height -->
+ <attr name="android:dividerHeight" />
+ </declare-styleable>
+
</resources>
diff --git a/v14/preference/res/values/styles.xml b/v14/preference/res/values/styles.xml
index daf683c..c197121 100644
--- a/v14/preference/res/values/styles.xml
+++ b/v14/preference/res/values/styles.xml
@@ -17,53 +17,70 @@
<resources>
<style name="Preference.SwitchPreference">
- <item name="widgetLayout">@layout/preference_widget_switch</item>
- <item name="switchTextOn">@string/v7_preference_on</item>
- <item name="switchTextOff">@string/v7_preference_off</item>
+ <item name="android:widgetLayout">@layout/preference_widget_switch</item>
+ <item name="android:switchTextOn">@string/v7_preference_on</item>
+ <item name="android:switchTextOff">@string/v7_preference_off</item>
</style>
<style name="Preference.Material">
- <item name="layout">@layout/preference_material</item>
+ <item name="android:layout">@layout/preference_material</item>
</style>
<style name="Preference.Information.Material">
- <item name="layout">@layout/preference_information_material</item>
- <item name="enabled">false</item>
- <item name="shouldDisableView">false</item>
+ <item name="android:layout">@layout/preference_information_material</item>
+ <item name="android:enabled">false</item>
+ <item name="android:shouldDisableView">false</item>
</style>
<style name="Preference.Category.Material">
- <item name="layout">@layout/preference_category_material</item>
+ <item name="android:layout">@layout/preference_category_material</item>
</style>
<style name="Preference.CheckBoxPreference.Material">
- <item name="layout">@layout/preference_material</item>
+ <item name="android:layout">@layout/preference_material</item>
</style>
<style name="Preference.SwitchPreferenceCompat.Material">
- <item name="layout">@layout/preference_material</item>
+ <item name="android:layout">@layout/preference_material</item>
</style>
<style name="Preference.SwitchPreference.Material">
- <item name="layout">@layout/preference_material</item>
+ <item name="android:layout">@layout/preference_material</item>
</style>
<style name="Preference.PreferenceScreen.Material">
- <item name="layout">@layout/preference_material</item>
+ <item name="android:layout">@layout/preference_material</item>
</style>
<style name="Preference.DialogPreference.Material">
- <item name="layout">@layout/preference_material</item>
+ <item name="android:layout">@layout/preference_material</item>
</style>
<style name="Preference.DialogPreference.EditTextPreference.Material">
- <item name="layout">@layout/preference_material</item>
+ <item name="android:layout">@layout/preference_material</item>
</style>
<style name="Preference_TextAppearanceMaterialBody2">
<item name="android:textSize">14sp</item>
- <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:fontFamily">sans-serif</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textStyle">normal</item>
+ </style>
+
+ <style name="Preference_TextAppearanceMaterialSubhead">
+ <item name="android:textSize">16sp</item>
+ <item name="android:fontFamily">sans-serif</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textStyle">normal</item>
+ </style>
+
+ <style name="PreferenceFragment.Material">
+ <item name="android:divider">@drawable/preference_list_divider_material</item>
+ </style>
+
+ <style name="PreferenceFragmentList.Material">
+ <item name="android:paddingLeft">0dp</item>
+ <item name="android:paddingRight">0dp</item>
</style>
</resources>
diff --git a/v14/preference/res/values/themes.xml b/v14/preference/res/values/themes.xml
index 2bfe623..64bc91e 100644
--- a/v14/preference/res/values/themes.xml
+++ b/v14/preference/res/values/themes.xml
@@ -18,10 +18,13 @@
<resources>
<style name="PreferenceThemeOverlay.v14">
<item name="switchPreferenceStyle">@style/Preference.SwitchPreference</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
</style>
<style name="PreferenceThemeOverlay.v14.Material">
<item name="preferenceScreenStyle">@style/Preference.PreferenceScreen.Material</item>
+ <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment.Material</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
<item name="preferenceCategoryStyle">@style/Preference.Category.Material</item>
<item name="preferenceStyle">@style/Preference.Material</item>
<item name="preferenceInformationStyle">@style/Preference.Information.Material</item>
@@ -30,5 +33,6 @@
<item name="switchPreferenceStyle">@style/Preference.SwitchPreference.Material</item>
<item name="dialogPreferenceStyle">@style/Preference.DialogPreference.Material</item>
<item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference.Material</item>
+ <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
</style>
</resources>
diff --git a/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
index caf08a8..498b874 100644
--- a/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
+++ b/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
@@ -19,8 +19,6 @@
import android.os.Bundle;
import android.support.v7.preference.EditTextPreference;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
import android.widget.EditText;
public class EditTextPreferenceDialogFragment extends PreferenceDialogFragment {
@@ -40,19 +38,14 @@
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
- mEditText = new EditText(view.getContext());
- // Give it an ID so it can be saved/restored
- mEditText.setId(android.R.id.edit);
+ mEditText = (EditText) view.findViewById(android.R.id.edit);
+
+ if (mEditText == null) {
+ throw new IllegalStateException("Dialog view must contain an EditText with id" +
+ " @android:id/edit");
+ }
mEditText.setText(getEditTextPreference().getText());
-
- ViewParent oldParent = mEditText.getParent();
- if (oldParent != view) {
- if (oldParent != null) {
- ((ViewGroup) oldParent).removeView(mEditText);
- }
- onAddEditTextToDialogView(view, mEditText);
- }
}
private EditTextPreference getEditTextPreference() {
@@ -66,20 +59,6 @@
return true;
}
- /**
- * Adds the EditText widget of this preference to the dialog's view.
- *
- * @param dialogView The dialog view.
- */
- protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
- ViewGroup container = (ViewGroup) dialogView
- .findViewById(R.id.edittext_container);
- if (container != null) {
- container.addView(editText, ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- }
- }
-
@Override
public void onDialogClosed(boolean positiveResult) {
diff --git a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
index 838d32d..b9fc935 100644
--- a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
+++ b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
@@ -20,11 +20,15 @@
import android.app.Fragment;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.annotation.XmlRes;
+import android.support.v4.view.ViewCompat;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.EditTextPreference;
import android.support.v7.preference.ListPreference;
@@ -32,6 +36,7 @@
import android.support.v7.preference.PreferenceGroupAdapter;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
@@ -58,7 +63,7 @@
* hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
* denote a screen break--that is the preferences contained within subsequent
* {@link PreferenceScreen} should be shown on another screen. The preference
- * framework handles showing these other screens from the preference hierarchy.
+ * framework handles this by calling {@link #onNavigateToScreen(PreferenceScreen)}.
* <p>
* The preference hierarchy can be formed in multiple ways:
* <li> From an XML file specifying the hierarchy
@@ -130,10 +135,7 @@
private int mLayoutResId = R.layout.preference_list_fragment;
- /**
- * The starting request code given out to preference framework.
- */
- private static final int FIRST_REQUEST_CODE = 100;
+ private final DividerDecoration mDividerDecoration = new DividerDecoration();
private static final int MSG_BIND_PREFERENCES = 1;
private Handler mHandler = new Handler() {
@@ -239,16 +241,27 @@
Bundle savedInstanceState) {
TypedArray a = mStyledContext.obtainStyledAttributes(null,
- R.styleable.PreferenceFragmentCompat,
+ R.styleable.PreferenceFragment,
R.attr.preferenceFragmentStyle,
0);
- mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_layout,
- mLayoutResId);
+ mLayoutResId = a.getResourceId(R.styleable.PreferenceFragment_android_layout, mLayoutResId);
+
+ final Drawable divider = a.getDrawable(R.styleable.PreferenceFragment_android_divider);
+ final int dividerHeight = a.getInt(R.styleable.PreferenceFragment_android_dividerHeight,
+ -1);
a.recycle();
- final View view = inflater.inflate(mLayoutResId, container, false);
+ // Need to theme the inflater to pick up the preferenceFragmentListStyle
+ final TypedValue tv = new TypedValue();
+ getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
+ final int theme = tv.resourceId;
+
+ final Context themedContext = new ContextThemeWrapper(inflater.getContext(), theme);
+ final LayoutInflater themedInflater = inflater.cloneInContext(themedContext);
+
+ final View view = themedInflater.inflate(mLayoutResId, container, false);
final View rawListContainer = view.findViewById(R.id.list_container);
if (!(rawListContainer instanceof ViewGroup)) {
@@ -258,18 +271,49 @@
final ViewGroup listContainer = (ViewGroup) rawListContainer;
- final RecyclerView listView = onCreateRecyclerView(inflater, listContainer,
+ final RecyclerView listView = onCreateRecyclerView(themedInflater, listContainer,
savedInstanceState);
if (listView == null) {
throw new RuntimeException("Could not create RecyclerView");
}
mList = listView;
+
+ listView.addItemDecoration(mDividerDecoration);
+ setDivider(divider);
+ if (dividerHeight != -1) {
+ setDividerHeight(dividerHeight);
+ }
+
listContainer.addView(mList);
mHandler.post(mRequestFocus);
return view;
}
+ /**
+ * Sets the drawable that will be drawn between each item in the list.
+ * <p>
+ * <strong>Note:</strong> If the drawable does not have an intrinsic
+ * height, you should also call {@link #setDividerHeight(int)}.
+ *
+ * @param divider the drawable to use
+ * @attr ref R.styleable#PreferenceFragment_android_divider
+ */
+ public void setDivider(Drawable divider) {
+ mDividerDecoration.setDivider(divider);
+ }
+
+ /**
+ * Sets the height of the divider that will be drawn between each item in the list. Calling
+ * this will override the intrinsic height as set by {@link #setDivider(Drawable)}
+ *
+ * @param height The new height of the divider in pixels.
+ * @attr ref R.styleable#PreferenceFragment_android_dividerHeight
+ */
+ public void setDividerHeight(int height) {
+ mDividerDecoration.setDividerHeight(height);
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -583,4 +627,78 @@
public Fragment getCallbackFragment() {
return null;
}
+
+ private class DividerDecoration extends RecyclerView.ItemDecoration {
+
+ private Drawable mDivider;
+ private int mDividerHeight;
+
+ @Override
+ public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ if (mDivider == null) {
+ return;
+ }
+ final int childCount = parent.getChildCount();
+ final int width = parent.getWidth();
+ for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
+ final View view = parent.getChildAt(childViewIndex);
+ if (shouldDrawDividerAbove(view, parent)) {
+ int top = (int) ViewCompat.getY(view);
+ mDivider.setBounds(0, top, width, top + mDividerHeight);
+ mDivider.draw(c);
+ }
+ if (shouldDrawDividerBelow(view, parent)) {
+ int top = (int) ViewCompat.getY(view) + view.getHeight();
+ mDivider.setBounds(0, top, width, top + mDividerHeight);
+ mDivider.draw(c);
+ }
+ }
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+ RecyclerView.State state) {
+ if (shouldDrawDividerAbove(view, parent)) {
+ outRect.top = mDividerHeight;
+ }
+ if (shouldDrawDividerBelow(view, parent)) {
+ outRect.bottom = mDividerHeight;
+ }
+ }
+
+ private boolean shouldDrawDividerAbove(View view, RecyclerView parent) {
+ final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
+ return holder.getAdapterPosition() == 0 &&
+ ((PreferenceViewHolder) holder).isDividerAllowedAbove();
+ }
+
+ private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
+ final PreferenceViewHolder holder =
+ (PreferenceViewHolder) parent.getChildViewHolder(view);
+ boolean nextAllowed = true;
+ int index = parent.indexOfChild(view);
+ if (index < parent.getChildCount() - 1) {
+ final View nextView = parent.getChildAt(index + 1);
+ final PreferenceViewHolder nextHolder =
+ (PreferenceViewHolder) parent.getChildViewHolder(nextView);
+ nextAllowed = nextHolder.isDividerAllowedAbove();
+ }
+ return nextAllowed && holder.isDividerAllowedBelow();
+ }
+
+ public void setDivider(Drawable divider) {
+ if (divider != null) {
+ mDividerHeight = divider.getIntrinsicHeight();
+ } else {
+ mDividerHeight = 0;
+ }
+ mDivider = divider;
+ mList.invalidateItemDecorations();
+ }
+
+ public void setDividerHeight(int dividerHeight) {
+ mDividerHeight = dividerHeight;
+ mList.invalidateItemDecorations();
+ }
+ }
}
diff --git a/v17/leanback/.classpath b/v17/leanback/.classpath
index 7bc01d9..f568681 100644
--- a/v17/leanback/.classpath
+++ b/v17/leanback/.classpath
@@ -1,9 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="api21"/>
+ <classpathentry kind="src" path="api23"/>
+ <classpathentry kind="src" path="jbmr2"/>
+ <classpathentry kind="src" path="common"/>
+ <classpathentry kind="src" path="kitkat"/>
+ <classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
diff --git a/v17/leanback/Android.mk b/v17/leanback/Android.mk
index dd03d6a..2dc78a7 100644
--- a/v17/leanback/Android.mk
+++ b/v17/leanback/Android.mk
@@ -28,6 +28,8 @@
LOCAL_JAR_EXCLUDE_FILES := none
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files := $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# Base sub-library contains classes both needed by api-level specific libraries
@@ -38,6 +40,20 @@
LOCAL_SRC_FILES := $(call all-java-files-under, common)
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
+# -----------------------------------------------------------------------
+
+# A helper sub-library that makes direct use of API 23.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v17-leanback-api23
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, api23)
+LOCAL_JAVA_LIBRARIES := android-support-v17-leanback-res android-support-v17-leanback-common
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of API 21.
@@ -48,6 +64,8 @@
LOCAL_JAVA_LIBRARIES := android-support-v17-leanback-res android-support-v17-leanback-common
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of KitKat APIs.
@@ -58,6 +76,8 @@
LOCAL_JAVA_LIBRARIES := android-support-v17-leanback-res android-support-v17-leanback-common
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of JBMR2 APIs.
@@ -68,6 +88,8 @@
LOCAL_JAVA_LIBRARIES := android-support-v17-leanback-res android-support-v17-leanback-common
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# Here is the final static library that apps can link against.
@@ -79,6 +101,7 @@
LOCAL_SDK_VERSION := 17
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v17-leanback-kitkat android-support-v17-leanback-jbmr2 \
+ android-support-v17-leanback-api23 \
android-support-v17-leanback-api21 android-support-v17-leanback-common
LOCAL_JAVA_LIBRARIES := \
android-support-v4 \
@@ -86,6 +109,7 @@
android-support-v17-leanback-res
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
# ===========================================================
# Common Droiddoc vars
@@ -131,7 +155,6 @@
# ---------------------------------------------
support_module := $(LOCAL_MODULE)
support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(leanback.docs.src_files)
support_module_java_libraries := $(leanback.docs.java_libraries)
support_module_java_packages := android.support.v17.leanback*
include $(SUPPORT_API_CHECK)
diff --git a/v17/leanback/api/23.txt b/v17/leanback/api/23.0.0.txt
similarity index 100%
rename from v17/leanback/api/23.txt
rename to v17/leanback/api/23.0.0.txt
diff --git a/v17/leanback/api/23.1.0.txt b/v17/leanback/api/23.1.0.txt
new file mode 100644
index 0000000..962367d
--- /dev/null
+++ b/v17/leanback/api/23.1.0.txt
@@ -0,0 +1,1796 @@
+package android.support.v17.leanback.app {
+
+ public final class BackgroundManager {
+ method public void attach(android.view.Window);
+ method public final int getColor();
+ method public android.graphics.drawable.Drawable getDefaultDimLayer();
+ method public android.graphics.drawable.Drawable getDimLayer();
+ method public android.graphics.drawable.Drawable getDrawable();
+ method public static android.support.v17.leanback.app.BackgroundManager getInstance(android.app.Activity);
+ method public boolean isAttached();
+ method public void release();
+ method public void setBitmap(android.graphics.Bitmap);
+ method public void setColor(int);
+ method public void setDimLayer(android.graphics.drawable.Drawable);
+ method public void setDrawable(android.graphics.drawable.Drawable);
+ method public void setThemeDrawableResourceId(int);
+ }
+
+ abstract class BaseRowFragment extends android.app.Fragment {
+ method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+ method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+ method public void setSelectedPosition(int);
+ method public void setSelectedPosition(int, boolean);
+ }
+
+ abstract class BaseRowSupportFragment extends android.support.v4.app.Fragment {
+ method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+ method public final void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+ method public void setSelectedPosition(int);
+ method public void setSelectedPosition(int, boolean);
+ }
+
+ public class BrowseFragment extends android.support.v17.leanback.app.BrandedFragment {
+ ctor public BrowseFragment();
+ method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+ method protected java.lang.Object createEntranceTransition();
+ method public void enableRowScaling(boolean);
+ method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ method public int getBrandColor();
+ method public int getHeadersState();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+ method public final boolean isHeadersTransitionOnBackEnabled();
+ method public boolean isInHeadersTransition();
+ method public boolean isShowingHeaders();
+ method protected void onEntranceTransitionEnd();
+ method protected void onEntranceTransitionPrepare();
+ method protected void onEntranceTransitionStart();
+ method public void onSaveInstanceState(android.os.Bundle);
+ method public void onStart();
+ method protected void runEntranceTransition(java.lang.Object);
+ method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public void setBrandColor(int);
+ method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseFragment.BrowseTransitionListener);
+ method public void setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+ method public void setHeadersState(int);
+ method public final void setHeadersTransitionOnBackEnabled(boolean);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setSelectedPosition(int);
+ method public void setSelectedPosition(int, boolean);
+ method public void startHeadersTransition(boolean);
+ field public static final int HEADERS_DISABLED = 3; // 0x3
+ field public static final int HEADERS_ENABLED = 1; // 0x1
+ field public static final int HEADERS_HIDDEN = 2; // 0x2
+ }
+
+ public static class BrowseFragment.BrowseTransitionListener {
+ ctor public BrowseFragment.BrowseTransitionListener();
+ method public void onHeadersTransitionStart(boolean);
+ method public void onHeadersTransitionStop(boolean);
+ }
+
+ public class BrowseSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+ ctor public BrowseSupportFragment();
+ method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+ method protected java.lang.Object createEntranceTransition();
+ method public void enableRowScaling(boolean);
+ method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ method public int getBrandColor();
+ method public int getHeadersState();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+ method public final boolean isHeadersTransitionOnBackEnabled();
+ method public boolean isInHeadersTransition();
+ method public boolean isShowingHeaders();
+ method protected void onEntranceTransitionEnd();
+ method protected void onEntranceTransitionPrepare();
+ method protected void onEntranceTransitionStart();
+ method public void onSaveInstanceState(android.os.Bundle);
+ method public void onStart();
+ method protected void runEntranceTransition(java.lang.Object);
+ method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public void setBrandColor(int);
+ method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseSupportFragment.BrowseTransitionListener);
+ method public void setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+ method public void setHeadersState(int);
+ method public final void setHeadersTransitionOnBackEnabled(boolean);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setSelectedPosition(int);
+ method public void setSelectedPosition(int, boolean);
+ method public void startHeadersTransition(boolean);
+ field public static final int HEADERS_DISABLED = 3; // 0x3
+ field public static final int HEADERS_ENABLED = 1; // 0x1
+ field public static final int HEADERS_HIDDEN = 2; // 0x2
+ }
+
+ public static class BrowseSupportFragment.BrowseTransitionListener {
+ ctor public BrowseSupportFragment.BrowseTransitionListener();
+ method public void onHeadersTransitionStart(boolean);
+ method public void onHeadersTransitionStop(boolean);
+ }
+
+ public class DetailsFragment extends android.support.v17.leanback.app.BrandedFragment {
+ ctor public DetailsFragment();
+ method protected java.lang.Object createEntranceTransition();
+ method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method protected android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method protected void onEntranceTransitionEnd();
+ method protected void onEntranceTransitionPrepare();
+ method protected void onEntranceTransitionStart();
+ method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
+ method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+ method public void onStart();
+ method protected void runEntranceTransition(java.lang.Object);
+ method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setSelectedPosition(int);
+ method public void setSelectedPosition(int, boolean);
+ method protected void setupDetailsOverviewRowPresenter(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+ method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
+ }
+
+ public class DetailsSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+ ctor public DetailsSupportFragment();
+ method protected java.lang.Object createEntranceTransition();
+ method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method protected android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method protected void onEntranceTransitionEnd();
+ method protected void onEntranceTransitionPrepare();
+ method protected void onEntranceTransitionStart();
+ method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
+ method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+ method public void onStart();
+ method protected void runEntranceTransition(java.lang.Object);
+ method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setSelectedPosition(int);
+ method public void setSelectedPosition(int, boolean);
+ method protected void setupDetailsOverviewRowPresenter(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+ method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
+ }
+
+ public class ErrorFragment extends android.app.Fragment {
+ ctor public ErrorFragment();
+ method public android.graphics.drawable.Drawable getBackgroundDrawable();
+ method public android.graphics.drawable.Drawable getBadgeDrawable();
+ method public android.view.View.OnClickListener getButtonClickListener();
+ method public java.lang.String getButtonText();
+ method public android.graphics.drawable.Drawable getImageDrawable();
+ method public java.lang.CharSequence getMessage();
+ method public java.lang.String getTitle();
+ method public boolean isBackgroundTranslucent();
+ method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+ method public void setButtonClickListener(android.view.View.OnClickListener);
+ method public void setButtonText(java.lang.String);
+ method public void setDefaultBackground(boolean);
+ method public void setImageDrawable(android.graphics.drawable.Drawable);
+ method public void setMessage(java.lang.CharSequence);
+ method public void setTitle(java.lang.String);
+ }
+
+ public class ErrorSupportFragment extends android.support.v4.app.Fragment {
+ ctor public ErrorSupportFragment();
+ method public android.graphics.drawable.Drawable getBackgroundDrawable();
+ method public android.graphics.drawable.Drawable getBadgeDrawable();
+ method public android.view.View.OnClickListener getButtonClickListener();
+ method public java.lang.String getButtonText();
+ method public android.graphics.drawable.Drawable getImageDrawable();
+ method public java.lang.CharSequence getMessage();
+ method public java.lang.String getTitle();
+ method public boolean isBackgroundTranslucent();
+ method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+ method public void setButtonClickListener(android.view.View.OnClickListener);
+ method public void setButtonText(java.lang.String);
+ method public void setDefaultBackground(boolean);
+ method public void setImageDrawable(android.graphics.drawable.Drawable);
+ method public void setMessage(java.lang.CharSequence);
+ method public void setTitle(java.lang.String);
+ }
+
+ public class GuidedStepFragment extends android.app.Fragment {
+ ctor public GuidedStepFragment();
+ method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment);
+ method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment, int);
+ method public static int addAsRoot(android.app.Activity, android.support.v17.leanback.app.GuidedStepFragment, int);
+ method public android.view.View getActionItemView(int);
+ method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+ method protected int getContainerIdForBackground();
+ method public static android.support.v17.leanback.app.GuidedStepFragment getCurrentGuidedStepFragment(android.app.FragmentManager);
+ method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+ method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+ method public int getSelectedActionPosition();
+ method public int getUiStyle();
+ method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+ method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+ method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+ method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+ method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+ method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+ method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+ method protected android.app.Fragment onProvideBackgroundFragment();
+ method protected void onProvideFragmentTransitions();
+ method public int onProvideTheme();
+ method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+ method public void setSelectedActionPosition(int);
+ method public void setUiStyle(int);
+ field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+ field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+ field public static final int UI_STYLE_DEFAULT = 0; // 0x0
+ field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+ }
+
+ public static class GuidedStepFragment.GuidedStepBackgroundFragment extends android.app.Fragment {
+ ctor public GuidedStepFragment.GuidedStepBackgroundFragment();
+ method protected void onProvideFragmentTransitions();
+ }
+
+ public class GuidedStepSupportFragment extends android.support.v4.app.Fragment {
+ ctor public GuidedStepSupportFragment();
+ method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment);
+ method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+ method public static int addAsRoot(android.support.v4.app.FragmentActivity, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+ method public android.view.View getActionItemView(int);
+ method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+ method protected int getContainerIdForBackground();
+ method public static android.support.v17.leanback.app.GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(android.support.v4.app.FragmentManager);
+ method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+ method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+ method public int getSelectedActionPosition();
+ method public int getUiStyle();
+ method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+ method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+ method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+ method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+ method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+ method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+ method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+ method protected android.support.v4.app.Fragment onProvideBackgroundSupportFragment();
+ method protected void onProvideFragmentTransitions();
+ method public int onProvideTheme();
+ method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+ method public void setSelectedActionPosition(int);
+ method public void setUiStyle(int);
+ field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+ field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+ field public static final int UI_STYLE_DEFAULT = 0; // 0x0
+ field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+ }
+
+ public static class GuidedStepSupportFragment.GuidedStepBackgroundSupportFragment extends android.support.v4.app.Fragment {
+ ctor public GuidedStepSupportFragment.GuidedStepBackgroundSupportFragment();
+ method protected void onProvideFragmentTransitions();
+ }
+
+ public class HeadersFragment extends android.support.v17.leanback.app.BaseRowFragment {
+ ctor public HeadersFragment();
+ method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener);
+ method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener);
+ }
+
+ static abstract interface HeadersFragment.OnHeaderClickedListener {
+ method public abstract void onHeaderClicked();
+ }
+
+ static abstract interface HeadersFragment.OnHeaderViewSelectedListener {
+ method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+ }
+
+ public class HeadersSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment {
+ ctor public HeadersSupportFragment();
+ method public void setOnHeaderClickedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener);
+ method public void setOnHeaderViewSelectedListener(android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener);
+ }
+
+ static abstract interface HeadersSupportFragment.OnHeaderClickedListener {
+ method public abstract void onHeaderClicked();
+ }
+
+ static abstract interface HeadersSupportFragment.OnHeaderViewSelectedListener {
+ method public abstract void onHeaderSelected(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+ }
+
+ public abstract class MediaControllerGlue extends android.support.v17.leanback.app.PlaybackControlGlue {
+ ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+ ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+ method public void attachToMediaController(android.support.v4.media.session.MediaControllerCompat);
+ method public void detach();
+ method public int getCurrentPosition();
+ method public int getCurrentSpeedId();
+ method public android.graphics.drawable.Drawable getMediaArt();
+ method public final android.support.v4.media.session.MediaControllerCompat getMediaController();
+ method public int getMediaDuration();
+ method public java.lang.CharSequence getMediaSubtitle();
+ method public java.lang.CharSequence getMediaTitle();
+ method public long getSupportedActions();
+ method public boolean hasValidMedia();
+ method public boolean isMediaPlaying();
+ method protected void pausePlayback();
+ method protected void skipToNext();
+ method protected void skipToPrevious();
+ method protected void startPlayback(int);
+ }
+
+ public abstract class PlaybackControlGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+ ctor public PlaybackControlGlue(android.content.Context, int[]);
+ ctor public PlaybackControlGlue(android.content.Context, int[], int[]);
+ ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+ ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+ method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
+ method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
+ method public void enableProgressUpdating(boolean);
+ method public android.content.Context getContext();
+ method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
+ method public abstract int getCurrentPosition();
+ method public abstract int getCurrentSpeedId();
+ method public int[] getFastForwardSpeeds();
+ method public android.support.v17.leanback.app.PlaybackOverlayFragment getFragment();
+ method public abstract android.graphics.drawable.Drawable getMediaArt();
+ method public abstract int getMediaDuration();
+ method public abstract java.lang.CharSequence getMediaSubtitle();
+ method public abstract java.lang.CharSequence getMediaTitle();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public int[] getRewindSpeeds();
+ method public abstract long getSupportedActions();
+ method public int getUpdatePeriod();
+ method public abstract boolean hasValidMedia();
+ method public boolean isFadingEnabled();
+ method public abstract boolean isMediaPlaying();
+ method public void onActionClicked(android.support.v17.leanback.widget.Action);
+ method public boolean onKey(android.view.View, int, android.view.KeyEvent);
+ method protected void onMetadataChanged();
+ method protected abstract void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
+ method protected void onStateChanged();
+ method protected abstract void pausePlayback();
+ method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
+ method public void setFadingEnabled(boolean);
+ method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method protected abstract void skipToNext();
+ method protected abstract void skipToPrevious();
+ method protected abstract void startPlayback(int);
+ method public void updateProgress();
+ field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+ field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+ field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+ field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+ field public static final int ACTION_REWIND = 32; // 0x20
+ field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+ field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+ field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+ field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+ field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+ field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+ field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+ field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+ field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+ field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+ }
+
+ public abstract class PlaybackControlSupportGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+ ctor public PlaybackControlSupportGlue(android.content.Context, int[]);
+ ctor public PlaybackControlSupportGlue(android.content.Context, int[], int[]);
+ ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[]);
+ ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[], int[]);
+ method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
+ method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
+ method public void enableProgressUpdating(boolean);
+ method public android.content.Context getContext();
+ method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
+ method public abstract int getCurrentPosition();
+ method public abstract int getCurrentSpeedId();
+ method public int[] getFastForwardSpeeds();
+ method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment getFragment();
+ method public abstract android.graphics.drawable.Drawable getMediaArt();
+ method public abstract int getMediaDuration();
+ method public abstract java.lang.CharSequence getMediaSubtitle();
+ method public abstract java.lang.CharSequence getMediaTitle();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public int[] getRewindSpeeds();
+ method public abstract long getSupportedActions();
+ method public int getUpdatePeriod();
+ method public abstract boolean hasValidMedia();
+ method public boolean isFadingEnabled();
+ method public abstract boolean isMediaPlaying();
+ method public void onActionClicked(android.support.v17.leanback.widget.Action);
+ method public boolean onKey(android.view.View, int, android.view.KeyEvent);
+ method protected void onMetadataChanged();
+ method protected abstract void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
+ method protected void onStateChanged();
+ method protected abstract void pausePlayback();
+ method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
+ method public void setFadingEnabled(boolean);
+ method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method protected abstract void skipToNext();
+ method protected abstract void skipToPrevious();
+ method protected abstract void startPlayback(int);
+ method public void updateProgress();
+ field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+ field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+ field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+ field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+ field public static final int ACTION_REWIND = 32; // 0x20
+ field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+ field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+ field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+ field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+ field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+ field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+ field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+ field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+ field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+ field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+ }
+
+ public class PlaybackOverlayFragment extends android.support.v17.leanback.app.DetailsFragment {
+ ctor public PlaybackOverlayFragment();
+ method public int getBackgroundType();
+ method public android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener getFadeCompleteListener();
+ method public final android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler getInputEventHandler();
+ method public boolean isFadingEnabled();
+ method public void onDestroyView();
+ method public void onResume();
+ method public void setBackgroundType(int);
+ method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener);
+ method public void setFadingEnabled(boolean);
+ method public final void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler);
+ method public void tickle();
+ field public static final int BG_DARK = 1; // 0x1
+ field public static final int BG_LIGHT = 2; // 0x2
+ field public static final int BG_NONE = 0; // 0x0
+ }
+
+ public static abstract interface PlaybackOverlayFragment.InputEventHandler {
+ method public abstract boolean handleInputEvent(android.view.InputEvent);
+ }
+
+ public static class PlaybackOverlayFragment.OnFadeCompleteListener {
+ ctor public PlaybackOverlayFragment.OnFadeCompleteListener();
+ method public void onFadeInComplete();
+ method public void onFadeOutComplete();
+ }
+
+ public class PlaybackOverlaySupportFragment extends android.support.v17.leanback.app.DetailsSupportFragment {
+ ctor public PlaybackOverlaySupportFragment();
+ method public int getBackgroundType();
+ method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener getFadeCompleteListener();
+ method public final android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler getInputEventHandler();
+ method public boolean isFadingEnabled();
+ method public void onDestroyView();
+ method public void onResume();
+ method public void setBackgroundType(int);
+ method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener);
+ method public void setFadingEnabled(boolean);
+ method public final void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler);
+ method public void tickle();
+ field public static final int BG_DARK = 1; // 0x1
+ field public static final int BG_LIGHT = 2; // 0x2
+ field public static final int BG_NONE = 0; // 0x0
+ }
+
+ public static abstract interface PlaybackOverlaySupportFragment.InputEventHandler {
+ method public abstract boolean handleInputEvent(android.view.InputEvent);
+ }
+
+ public static class PlaybackOverlaySupportFragment.OnFadeCompleteListener {
+ ctor public PlaybackOverlaySupportFragment.OnFadeCompleteListener();
+ method public void onFadeInComplete();
+ method public void onFadeOutComplete();
+ }
+
+ public class RowsFragment extends android.support.v17.leanback.app.BaseRowFragment {
+ ctor public RowsFragment();
+ method public void enableRowScaling(boolean);
+ method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+ method public void setExpand(boolean);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ }
+
+ public class RowsSupportFragment extends android.support.v17.leanback.app.BaseRowSupportFragment {
+ ctor public RowsSupportFragment();
+ method public void enableRowScaling(boolean);
+ method protected android.support.v17.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+ method public void setExpand(boolean);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ }
+
+ public class SearchFragment extends android.app.Fragment {
+ ctor public SearchFragment();
+ method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
+ method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
+ method public void displayCompletions(java.util.List<java.lang.String>);
+ method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+ method public android.graphics.drawable.Drawable getBadgeDrawable();
+ method public android.content.Intent getRecognizerIntent();
+ method public java.lang.String getTitle();
+ method public static android.support.v17.leanback.app.SearchFragment newInstance(java.lang.String);
+ method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setSearchQuery(java.lang.String, boolean);
+ method public void setSearchQuery(android.content.Intent, boolean);
+ method public void setSearchResultProvider(android.support.v17.leanback.app.SearchFragment.SearchResultProvider);
+ method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+ method public void setTitle(java.lang.String);
+ method public void startRecognition();
+ }
+
+ public static abstract interface SearchFragment.SearchResultProvider {
+ method public abstract android.support.v17.leanback.widget.ObjectAdapter getResultsAdapter();
+ method public abstract boolean onQueryTextChange(java.lang.String);
+ method public abstract boolean onQueryTextSubmit(java.lang.String);
+ }
+
+ public class SearchSupportFragment extends android.support.v4.app.Fragment {
+ ctor public SearchSupportFragment();
+ method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
+ method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
+ method public void displayCompletions(java.util.List<java.lang.String>);
+ method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+ method public android.graphics.drawable.Drawable getBadgeDrawable();
+ method public android.content.Intent getRecognizerIntent();
+ method public java.lang.String getTitle();
+ method public static android.support.v17.leanback.app.SearchSupportFragment newInstance(java.lang.String);
+ method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setSearchQuery(java.lang.String, boolean);
+ method public void setSearchQuery(android.content.Intent, boolean);
+ method public void setSearchResultProvider(android.support.v17.leanback.app.SearchSupportFragment.SearchResultProvider);
+ method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+ method public void setTitle(java.lang.String);
+ method public void startRecognition();
+ }
+
+ public static abstract interface SearchSupportFragment.SearchResultProvider {
+ method public abstract android.support.v17.leanback.widget.ObjectAdapter getResultsAdapter();
+ method public abstract boolean onQueryTextChange(java.lang.String);
+ method public abstract boolean onQueryTextSubmit(java.lang.String);
+ }
+
+ public class VerticalGridFragment extends android.support.v17.leanback.app.BrandedFragment {
+ ctor public VerticalGridFragment();
+ method protected java.lang.Object createEntranceTransition();
+ method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public void onDestroyView();
+ method public void onStart();
+ method public void onViewCreated(android.view.View, android.os.Bundle);
+ method protected void runEntranceTransition(java.lang.Object);
+ method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setSelectedPosition(int);
+ }
+
+ public class VerticalGridSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
+ ctor public VerticalGridSupportFragment();
+ method protected java.lang.Object createEntranceTransition();
+ method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public void onDestroyView();
+ method public void onStart();
+ method public void onViewCreated(android.view.View, android.os.Bundle);
+ method protected void runEntranceTransition(java.lang.Object);
+ method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
+ method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setSelectedPosition(int);
+ }
+
+}
+
+package android.support.v17.leanback.database {
+
+ public abstract class CursorMapper {
+ ctor public CursorMapper();
+ method protected abstract java.lang.Object bind(android.database.Cursor);
+ method protected abstract void bindColumns(android.database.Cursor);
+ method public java.lang.Object convert(android.database.Cursor);
+ }
+
+}
+
+package android.support.v17.leanback.graphics {
+
+ public final class ColorFilterCache {
+ method public static android.support.v17.leanback.graphics.ColorFilterCache getColorFilterCache(int);
+ method public android.graphics.ColorFilter getFilterForLevel(float);
+ }
+
+ public final class ColorFilterDimmer {
+ method public void applyFilterToView(android.view.View);
+ method public static android.support.v17.leanback.graphics.ColorFilterDimmer create(android.support.v17.leanback.graphics.ColorFilterCache, float, float);
+ method public static android.support.v17.leanback.graphics.ColorFilterDimmer createDefault(android.content.Context);
+ method public android.graphics.ColorFilter getColorFilter();
+ method public android.graphics.Paint getPaint();
+ method public void setActiveLevel(float);
+ }
+
+ public final class ColorOverlayDimmer {
+ method public int applyToColor(int);
+ method public static android.support.v17.leanback.graphics.ColorOverlayDimmer createColorOverlayDimmer(int, float, float);
+ method public static android.support.v17.leanback.graphics.ColorOverlayDimmer createDefault(android.content.Context);
+ method public void drawColorOverlay(android.graphics.Canvas, android.view.View, boolean);
+ method public int getAlpha();
+ method public float getAlphaFloat();
+ method public android.graphics.Paint getPaint();
+ method public boolean needsDraw();
+ method public void setActiveLevel(float);
+ }
+
+}
+
+package android.support.v17.leanback.system {
+
+ public class Settings {
+ method public boolean getBoolean(java.lang.String);
+ method public static android.support.v17.leanback.system.Settings getInstance(android.content.Context);
+ method public void setBoolean(java.lang.String, boolean);
+ field public static final java.lang.String PREFER_STATIC_SHADOWS = "PREFER_STATIC_SHADOWS";
+ }
+
+}
+
+package android.support.v17.leanback.widget {
+
+ public abstract class AbstractDetailsDescriptionPresenter extends android.support.v17.leanback.widget.Presenter {
+ ctor public AbstractDetailsDescriptionPresenter();
+ method protected abstract void onBindDescription(android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder, java.lang.Object);
+ method public final void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+ method public final android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+ method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ }
+
+ public static class AbstractDetailsDescriptionPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+ ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View);
+ method public android.widget.TextView getBody();
+ method public android.widget.TextView getSubtitle();
+ method public android.widget.TextView getTitle();
+ }
+
+ public class Action {
+ ctor public Action(long);
+ ctor public Action(long, java.lang.CharSequence);
+ ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence);
+ ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence, android.graphics.drawable.Drawable);
+ method public final void addKeyCode(int);
+ method public final android.graphics.drawable.Drawable getIcon();
+ method public final long getId();
+ method public final java.lang.CharSequence getLabel1();
+ method public final java.lang.CharSequence getLabel2();
+ method public final void removeKeyCode(int);
+ method public final boolean respondsToKeyCode(int);
+ method public final void setIcon(android.graphics.drawable.Drawable);
+ method public final void setId(long);
+ method public final void setLabel1(java.lang.CharSequence);
+ method public final void setLabel2(java.lang.CharSequence);
+ }
+
+ public class ArrayObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+ ctor public ArrayObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+ ctor public ArrayObjectAdapter(android.support.v17.leanback.widget.Presenter);
+ ctor public ArrayObjectAdapter();
+ method public void add(java.lang.Object);
+ method public void add(int, java.lang.Object);
+ method public void addAll(int, java.util.Collection);
+ method public void clear();
+ method public java.lang.Object get(int);
+ method public int indexOf(java.lang.Object);
+ method public void notifyArrayItemRangeChanged(int, int);
+ method public boolean remove(java.lang.Object);
+ method public int removeItems(int, int);
+ method public void replace(int, java.lang.Object);
+ method public int size();
+ method public java.util.List<E> unmodifiableList();
+ }
+
+ public class BaseCardView extends android.widget.FrameLayout {
+ ctor public BaseCardView(android.content.Context);
+ ctor public BaseCardView(android.content.Context, android.util.AttributeSet);
+ ctor public BaseCardView(android.content.Context, android.util.AttributeSet, int);
+ method public int getCardType();
+ method public int getExtraVisibility();
+ method public int getInfoVisibility();
+ method public boolean isSelectedAnimationDelayed();
+ method public void setCardType(int);
+ method public void setExtraVisibility(int);
+ method public void setInfoVisibility(int);
+ method public void setSelectedAnimationDelayed(boolean);
+ field public static final int CARD_REGION_VISIBLE_ACTIVATED = 1; // 0x1
+ field public static final int CARD_REGION_VISIBLE_ALWAYS = 0; // 0x0
+ field public static final int CARD_REGION_VISIBLE_SELECTED = 2; // 0x2
+ field public static final int CARD_TYPE_INFO_OVER = 1; // 0x1
+ field public static final int CARD_TYPE_INFO_UNDER = 2; // 0x2
+ field public static final int CARD_TYPE_INFO_UNDER_WITH_EXTRA = 3; // 0x3
+ field public static final int CARD_TYPE_MAIN_ONLY = 0; // 0x0
+ }
+
+ public static class BaseCardView.LayoutParams extends android.widget.FrameLayout.LayoutParams {
+ ctor public BaseCardView.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public BaseCardView.LayoutParams(int, int);
+ ctor public BaseCardView.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public BaseCardView.LayoutParams(android.support.v17.leanback.widget.BaseCardView.LayoutParams);
+ field public static final int VIEW_TYPE_EXTRA = 2; // 0x2
+ field public static final int VIEW_TYPE_INFO = 1; // 0x1
+ field public static final int VIEW_TYPE_MAIN = 0; // 0x0
+ field public int viewType;
+ }
+
+ public class BrowseFrameLayout extends android.widget.FrameLayout {
+ ctor public BrowseFrameLayout(android.content.Context);
+ ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet);
+ ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet, int);
+ method public android.support.v17.leanback.widget.BrowseFrameLayout.OnChildFocusListener getOnChildFocusListener();
+ method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
+ method public void setOnChildFocusListener(android.support.v17.leanback.widget.BrowseFrameLayout.OnChildFocusListener);
+ method public void setOnFocusSearchListener(android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener);
+ }
+
+ public static abstract interface BrowseFrameLayout.OnChildFocusListener {
+ method public abstract void onRequestChildFocus(android.view.View, android.view.View);
+ method public abstract boolean onRequestFocusInDescendants(int, android.graphics.Rect);
+ }
+
+ public static abstract interface BrowseFrameLayout.OnFocusSearchListener {
+ method public abstract android.view.View onFocusSearch(android.view.View, int);
+ }
+
+ public final class ClassPresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+ ctor public ClassPresenterSelector();
+ method public void addClassPresenter(java.lang.Class<?>, android.support.v17.leanback.widget.Presenter);
+ method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+ }
+
+ public class ControlButtonPresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+ ctor public ControlButtonPresenterSelector();
+ method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+ method public android.support.v17.leanback.widget.Presenter getPrimaryPresenter();
+ method public android.support.v17.leanback.widget.Presenter getSecondaryPresenter();
+ }
+
+ public class CursorObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+ ctor public CursorObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+ ctor public CursorObjectAdapter(android.support.v17.leanback.widget.Presenter);
+ ctor public CursorObjectAdapter();
+ method public void changeCursor(android.database.Cursor);
+ method public void close();
+ method public java.lang.Object get(int);
+ method public final android.database.Cursor getCursor();
+ method public final android.support.v17.leanback.database.CursorMapper getMapper();
+ method protected final void invalidateCache(int);
+ method protected final void invalidateCache(int, int);
+ method public boolean isClosed();
+ method protected void onCursorChanged();
+ method protected void onMapperChanged();
+ method public final void setMapper(android.support.v17.leanback.database.CursorMapper);
+ method public int size();
+ method public android.database.Cursor swapCursor(android.database.Cursor);
+ }
+
+ public class DetailsOverviewLogoPresenter extends android.support.v17.leanback.widget.Presenter {
+ ctor public DetailsOverviewLogoPresenter();
+ method public boolean isBoundToImage(android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, android.support.v17.leanback.widget.DetailsOverviewRow);
+ method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+ method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+ method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public void setContext(android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter);
+ }
+
+ public static class DetailsOverviewLogoPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+ ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View);
+ field protected android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter mParentPresenter;
+ field protected android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder mParentViewHolder;
+ }
+
+ public class DetailsOverviewRow extends android.support.v17.leanback.widget.Row {
+ ctor public DetailsOverviewRow(java.lang.Object);
+ method public final deprecated void addAction(android.support.v17.leanback.widget.Action);
+ method public final deprecated void addAction(int, android.support.v17.leanback.widget.Action);
+ method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
+ method public final deprecated java.util.List<android.support.v17.leanback.widget.Action> getActions();
+ method public final android.support.v17.leanback.widget.ObjectAdapter getActionsAdapter();
+ method public final android.graphics.drawable.Drawable getImageDrawable();
+ method public final java.lang.Object getItem();
+ method public boolean isImageScaleUpAllowed();
+ method public final deprecated boolean removeAction(android.support.v17.leanback.widget.Action);
+ method public final void setActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
+ method public final void setImageDrawable(android.graphics.drawable.Drawable);
+ method public void setImageScaleUpAllowed(boolean);
+ method public final void setItem(java.lang.Object);
+ }
+
+ public static class DetailsOverviewRow.Listener {
+ ctor public DetailsOverviewRow.Listener();
+ method public void onActionsAdapterChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+ method public void onImageDrawableChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+ method public void onItemChanged(android.support.v17.leanback.widget.DetailsOverviewRow);
+ }
+
+ public deprecated class DetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+ ctor public DetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter);
+ method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+ method public int getBackgroundColor();
+ method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+ method public boolean isStyleLarge();
+ method public final boolean isUsingDefaultSelectEffect();
+ method public void setBackgroundColor(int);
+ method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+ method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
+ method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
+ method public void setStyleLarge(boolean);
+ }
+
+ public final class DetailsOverviewRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+ ctor public DetailsOverviewRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.Presenter);
+ field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDetailsDescriptionViewHolder;
+ }
+
+ public abstract interface FacetProvider {
+ method public abstract java.lang.Object getFacet(java.lang.Class<?>);
+ }
+
+ public abstract interface FacetProviderAdapter {
+ method public abstract android.support.v17.leanback.widget.FacetProvider getFacetProvider(int);
+ }
+
+ public abstract interface FocusHighlight {
+ field public static final int ZOOM_FACTOR_LARGE = 3; // 0x3
+ field public static final int ZOOM_FACTOR_MEDIUM = 2; // 0x2
+ field public static final int ZOOM_FACTOR_NONE = 0; // 0x0
+ field public static final int ZOOM_FACTOR_SMALL = 1; // 0x1
+ field public static final int ZOOM_FACTOR_XSMALL = 4; // 0x4
+ }
+
+ public class FocusHighlightHelper {
+ ctor public FocusHighlightHelper();
+ method public static void setupBrowseItemFocusHighlight(android.support.v17.leanback.widget.ItemBridgeAdapter, int, boolean);
+ method public static void setupHeaderItemFocusHighlight(android.support.v17.leanback.widget.VerticalGridView);
+ }
+
+ public abstract interface FragmentAnimationProvider {
+ method public abstract void onImeAppearing(java.util.List<android.animation.Animator>);
+ method public abstract void onImeDisappearing(java.util.List<android.animation.Animator>);
+ }
+
+ public class FullWidthDetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+ ctor public FullWidthDetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter);
+ ctor public FullWidthDetailsOverviewRowPresenter(android.support.v17.leanback.widget.Presenter, android.support.v17.leanback.widget.DetailsOverviewLogoPresenter);
+ method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+ method public final int getActionsBackgroundColor();
+ method public final int getAlignmentMode();
+ method public final int getBackgroundColor();
+ method public final int getInitialState();
+ method protected int getLayoutResourceId();
+ method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+ method public final boolean isParticipatingEntranceTransition();
+ method public final boolean isUsingDefaultSelectEffect();
+ method public final void notifyOnBindLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
+ method protected void onLayoutLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
+ method protected void onLayoutOverviewFrame(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
+ method protected void onStateChanged(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
+ method public final void setActionsBackgroundColor(int);
+ method public final void setAlignmentMode(int);
+ method public final void setBackgroundColor(int);
+ method public final void setInitialState(int);
+ method public final void setListener(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener);
+ method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+ method public final void setParticipatingEntranceTransition(boolean);
+ method public final void setState(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
+ field public static final int ALIGN_MODE_MIDDLE = 1; // 0x1
+ field public static final int ALIGN_MODE_START = 0; // 0x0
+ field public static final int STATE_FULL = 1; // 0x1
+ field public static final int STATE_HALF = 0; // 0x0
+ field public static final int STATE_SMALL = 2; // 0x2
+ field protected int mInitialState;
+ }
+
+ public static abstract class FullWidthDetailsOverviewRowPresenter.Listener {
+ ctor public FullWidthDetailsOverviewRowPresenter.Listener();
+ method public void onBindLogo(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
+ }
+
+ public class FullWidthDetailsOverviewRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+ ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.Presenter, android.support.v17.leanback.widget.DetailsOverviewLogoPresenter);
+ method protected android.support.v17.leanback.widget.DetailsOverviewRow.Listener createRowListener();
+ method public final android.view.ViewGroup getActionsRow();
+ method public final android.view.ViewGroup getDetailsDescriptionFrame();
+ method public final android.support.v17.leanback.widget.Presenter.ViewHolder getDetailsDescriptionViewHolder();
+ method public final android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder getLogoViewHolder();
+ method public final android.view.ViewGroup getOverviewView();
+ method public final int getState();
+ field protected final android.support.v17.leanback.widget.DetailsOverviewRow.Listener mRowListener;
+ }
+
+ public class FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener extends android.support.v17.leanback.widget.DetailsOverviewRow.Listener {
+ ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener();
+ }
+
+ public class FullWidthDetailsOverviewSharedElementHelper extends android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener {
+ ctor public FullWidthDetailsOverviewSharedElementHelper();
+ method public boolean getAutoStartSharedElementTransition();
+ method public void setAutoStartSharedElementTransition(boolean);
+ method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
+ method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
+ method public void startPostponedEnterTransition();
+ }
+
+ public class GuidanceStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
+ ctor public GuidanceStylist();
+ method public android.widget.TextView getBreadcrumbView();
+ method public android.widget.TextView getDescriptionView();
+ method public android.widget.ImageView getIconView();
+ method public android.widget.TextView getTitleView();
+ method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.support.v17.leanback.widget.GuidanceStylist.Guidance);
+ method public void onImeAppearing(java.util.List<android.animation.Animator>);
+ method public void onImeDisappearing(java.util.List<android.animation.Animator>);
+ method public int onProvideLayoutId();
+ }
+
+ public static class GuidanceStylist.Guidance {
+ ctor public GuidanceStylist.Guidance(java.lang.String, java.lang.String, java.lang.String, android.graphics.drawable.Drawable);
+ method public java.lang.String getBreadcrumb();
+ method public java.lang.String getDescription();
+ method public android.graphics.drawable.Drawable getIconDrawable();
+ method public java.lang.String getTitle();
+ }
+
+ public class GuidedAction extends android.support.v17.leanback.widget.Action {
+ method public int getCheckSetId();
+ method public java.lang.CharSequence getDescription();
+ method public java.lang.CharSequence getEditTitle();
+ method public android.content.Intent getIntent();
+ method public java.lang.CharSequence getTitle();
+ method public boolean hasMultilineDescription();
+ method public boolean hasNext();
+ method public boolean infoOnly();
+ method public boolean isChecked();
+ method public boolean isEditTitleUsed();
+ method public boolean isEditable();
+ method public boolean isEnabled();
+ method public void setChecked(boolean);
+ method public void setDescription(java.lang.CharSequence);
+ method public void setEditTitle(java.lang.CharSequence);
+ method public void setEnabled(boolean);
+ method public void setTitle(java.lang.CharSequence);
+ field public static final int DEFAULT_CHECK_SET_ID = 1; // 0x1
+ field public static final int NO_CHECK_SET = 0; // 0x0
+ field public static final int NO_DRAWABLE = 0; // 0x0
+ }
+
+ public static class GuidedAction.Builder {
+ ctor public GuidedAction.Builder();
+ method public android.support.v17.leanback.widget.GuidedAction build();
+ method public android.support.v17.leanback.widget.GuidedAction.Builder checkSetId(int);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder checked(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder description(java.lang.String);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder editTitle(java.lang.String);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder editable(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder enabled(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder hasNext(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder icon(android.graphics.drawable.Drawable);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder iconResourceId(int, android.content.Context);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder id(long);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder infoOnly(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder intent(android.content.Intent);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder multilineDescription(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder title(java.lang.String);
+ }
+
+ public class GuidedActionEditText extends android.widget.EditText implements android.support.v17.leanback.widget.ImeKeyMonitor {
+ ctor public GuidedActionEditText(android.content.Context);
+ ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet);
+ ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet, int);
+ method public void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+ }
+
+ public class GuidedActionsStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
+ ctor public GuidedActionsStylist();
+ method public android.support.v17.leanback.widget.VerticalGridView getActionsGridView();
+ method public void onAnimateItemChecked(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+ method public void onAnimateItemFocused(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+ method public void onAnimateItemPressed(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+ method public void onBindViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+ method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup);
+ method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+ method public void onImeAppearing(java.util.List<android.animation.Animator>);
+ method public void onImeDisappearing(java.util.List<android.animation.Animator>);
+ method public int onProvideItemLayoutId();
+ method public int onProvideLayoutId();
+ field protected android.support.v17.leanback.widget.VerticalGridView mActionsGridView;
+ field protected android.view.View mMainView;
+ field protected android.view.View mSelectorView;
+ }
+
+ public static class GuidedActionsStylist.ViewHolder {
+ ctor public GuidedActionsStylist.ViewHolder(android.view.View);
+ method public android.widget.ImageView getCheckmarkView();
+ method public android.widget.ImageView getChevronView();
+ method public android.view.View getContentView();
+ method public android.widget.TextView getDescriptionView();
+ method public android.widget.EditText getEditableTitleView();
+ method public android.widget.ImageView getIconView();
+ method public android.widget.TextView getTitleView();
+ field public final android.view.View view;
+ }
+
+ public class HeaderItem {
+ ctor public HeaderItem(long, java.lang.String);
+ ctor public HeaderItem(java.lang.String);
+ method public final long getId();
+ method public final java.lang.String getName();
+ }
+
+ public class HorizontalGridView extends android.support.v7.widget.RecyclerView {
+ ctor public HorizontalGridView(android.content.Context);
+ ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet);
+ ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet, int);
+ method public final boolean getFadingLeftEdge();
+ method public final int getFadingLeftEdgeLength();
+ method public final int getFadingLeftEdgeOffset();
+ method public final boolean getFadingRightEdge();
+ method public final int getFadingRightEdgeLength();
+ method public final int getFadingRightEdgeOffset();
+ method protected void initAttributes(android.content.Context, android.util.AttributeSet);
+ method public final void setFadingLeftEdge(boolean);
+ method public final void setFadingLeftEdgeLength(int);
+ method public final void setFadingLeftEdgeOffset(int);
+ method public final void setFadingRightEdge(boolean);
+ method public final void setFadingRightEdgeLength(int);
+ method public final void setFadingRightEdgeOffset(int);
+ method public void setNumRows(int);
+ method public void setRowHeight(int);
+ }
+
+ public final class HorizontalHoverCardSwitcher extends android.support.v17.leanback.widget.PresenterSwitcher {
+ ctor public HorizontalHoverCardSwitcher();
+ method protected void insertView(android.view.View);
+ method public void select(android.support.v17.leanback.widget.HorizontalGridView, android.view.View, java.lang.Object);
+ }
+
+ public class ImageCardView extends android.support.v17.leanback.widget.BaseCardView {
+ ctor public ImageCardView(android.content.Context, int);
+ ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
+ ctor public ImageCardView(android.content.Context);
+ ctor public ImageCardView(android.content.Context, android.util.AttributeSet);
+ method public android.graphics.drawable.Drawable getBadgeImage();
+ method public java.lang.CharSequence getContentText();
+ method public android.graphics.drawable.Drawable getInfoAreaBackground();
+ method public android.graphics.drawable.Drawable getMainImage();
+ method public final android.widget.ImageView getMainImageView();
+ method public java.lang.CharSequence getTitleText();
+ method public void setBadgeImage(android.graphics.drawable.Drawable);
+ method public void setContentText(java.lang.CharSequence);
+ method public void setInfoAreaBackground(android.graphics.drawable.Drawable);
+ method public void setInfoAreaBackgroundColor(int);
+ method public void setMainImage(android.graphics.drawable.Drawable);
+ method public void setMainImage(android.graphics.drawable.Drawable, boolean);
+ method public void setMainImageAdjustViewBounds(boolean);
+ method public void setMainImageDimensions(int, int);
+ method public void setMainImageScaleType(android.widget.ImageView.ScaleType);
+ method public void setTitleText(java.lang.CharSequence);
+ field public static final int CARD_TYPE_FLAG_CONTENT = 2; // 0x2
+ field public static final int CARD_TYPE_FLAG_ICON_LEFT = 8; // 0x8
+ field public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4; // 0x4
+ field public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0; // 0x0
+ field public static final int CARD_TYPE_FLAG_TITLE = 1; // 0x1
+ }
+
+ public abstract interface ImeKeyMonitor {
+ method public abstract void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+ }
+
+ public static abstract interface ImeKeyMonitor.ImeKeyListener {
+ method public abstract boolean onKeyPreIme(android.widget.EditText, int, android.view.KeyEvent);
+ }
+
+ public final class ItemAlignmentFacet {
+ ctor public ItemAlignmentFacet();
+ method public android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[] getAlignmentDefs();
+ method public boolean isMultiAlignment();
+ method public void setAlignmentDefs(android.support.v17.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[]);
+ field public static final float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1.0f;
+ }
+
+ public static class ItemAlignmentFacet.ItemAlignmentDef {
+ ctor public ItemAlignmentFacet.ItemAlignmentDef();
+ method public final int getItemAlignmentFocusViewId();
+ method public final int getItemAlignmentOffset();
+ method public final float getItemAlignmentOffsetPercent();
+ method public final int getItemAlignmentViewId();
+ method public final boolean isItemAlignmentOffsetWithPadding();
+ method public final void setItemAlignmentFocusViewId(int);
+ method public final void setItemAlignmentOffset(int);
+ method public final void setItemAlignmentOffsetPercent(float);
+ method public final void setItemAlignmentOffsetWithPadding(boolean);
+ method public final void setItemAlignmentViewId(int);
+ }
+
+ public class ItemBridgeAdapter extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.leanback.widget.FacetProviderAdapter {
+ ctor public ItemBridgeAdapter(android.support.v17.leanback.widget.ObjectAdapter, android.support.v17.leanback.widget.PresenterSelector);
+ ctor public ItemBridgeAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ ctor public ItemBridgeAdapter();
+ method public void clear();
+ method public android.support.v17.leanback.widget.FacetProvider getFacetProvider(int);
+ method public int getItemCount();
+ method public java.util.ArrayList<android.support.v17.leanback.widget.Presenter> getPresenterMapper();
+ method public android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper getWrapper();
+ method protected void onAddPresenter(android.support.v17.leanback.widget.Presenter, int);
+ method protected void onAttachedToWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method protected void onBind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method public final void onBindViewHolder(android.support.v7.widget.RecyclerView.ViewHolder, int);
+ method protected void onCreate(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method public final android.support.v7.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+ method protected void onDetachedFromWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method protected void onUnbind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method public final void onViewAttachedToWindow(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void onViewDetachedFromWindow(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void onViewRecycled(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public void setAdapterListener(android.support.v17.leanback.widget.ItemBridgeAdapter.AdapterListener);
+ method public void setPresenterMapper(java.util.ArrayList<android.support.v17.leanback.widget.Presenter>);
+ method public void setWrapper(android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper);
+ }
+
+ public static class ItemBridgeAdapter.AdapterListener {
+ ctor public ItemBridgeAdapter.AdapterListener();
+ method public void onAddPresenter(android.support.v17.leanback.widget.Presenter, int);
+ method public void onAttachedToWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method public void onBind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method public void onCreate(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method public void onDetachedFromWindow(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ method public void onUnbind(android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder);
+ }
+
+ public class ItemBridgeAdapter.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+ method public final java.lang.Object getExtraObject();
+ method public java.lang.Object getFacet(java.lang.Class<?>);
+ method public final java.lang.Object getItem();
+ method public final android.support.v17.leanback.widget.Presenter getPresenter();
+ method public final android.support.v17.leanback.widget.Presenter.ViewHolder getViewHolder();
+ method public void setExtraObject(java.lang.Object);
+ }
+
+ public static abstract class ItemBridgeAdapter.Wrapper {
+ ctor public ItemBridgeAdapter.Wrapper();
+ method public abstract android.view.View createWrapper(android.view.View);
+ method public abstract void wrap(android.view.View, android.view.View);
+ }
+
+ public class ItemBridgeAdapterShadowOverlayWrapper extends android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper {
+ ctor public ItemBridgeAdapterShadowOverlayWrapper(android.support.v17.leanback.widget.ShadowOverlayHelper);
+ method public android.view.View createWrapper(android.view.View);
+ method public void wrap(android.view.View, android.view.View);
+ }
+
+ public class ListRow extends android.support.v17.leanback.widget.Row {
+ ctor public ListRow(android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
+ ctor public ListRow(long, android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
+ ctor public ListRow(android.support.v17.leanback.widget.ObjectAdapter);
+ method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+ }
+
+ public final class ListRowHoverCardView extends android.widget.LinearLayout {
+ ctor public ListRowHoverCardView(android.content.Context);
+ ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet);
+ ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet, int);
+ method public final java.lang.CharSequence getDescription();
+ method public final java.lang.CharSequence getTitle();
+ method public final void setDescription(java.lang.CharSequence);
+ method public final void setTitle(java.lang.CharSequence);
+ }
+
+ public class ListRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+ ctor public ListRowPresenter();
+ ctor public ListRowPresenter(int);
+ ctor public ListRowPresenter(int, boolean);
+ method public final boolean areChildRoundedCornersEnabled();
+ method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+ method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
+ method public final void enableChildRoundedCorners(boolean);
+ method public int getExpandedRowHeight();
+ method public final int getFocusZoomFactor();
+ method public final android.support.v17.leanback.widget.PresenterSelector getHoverCardPresenterSelector();
+ method public int getRecycledPoolSize(android.support.v17.leanback.widget.Presenter);
+ method public int getRowHeight();
+ method public final boolean getShadowEnabled();
+ method public final deprecated int getZoomFactor();
+ method public final boolean isFocusDimmerUsed();
+ method public final boolean isKeepChildForeground();
+ method public boolean isUsingDefaultListSelectEffect();
+ method public final boolean isUsingDefaultSelectEffect();
+ method public boolean isUsingDefaultShadow();
+ method public boolean isUsingZOrder(android.content.Context);
+ method public void setExpandedRowHeight(int);
+ method public final void setHoverCardPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+ method public final void setKeepChildForeground(boolean);
+ method public void setRecycledPoolSize(android.support.v17.leanback.widget.Presenter, int);
+ method public void setRowHeight(int);
+ method public final void setShadowEnabled(boolean);
+ }
+
+ public static class ListRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+ ctor public ListRowPresenter.ViewHolder(android.view.View, android.support.v17.leanback.widget.HorizontalGridView, android.support.v17.leanback.widget.ListRowPresenter);
+ method public final android.support.v17.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
+ method public final android.support.v17.leanback.widget.HorizontalGridView getGridView();
+ method public final android.support.v17.leanback.widget.ListRowPresenter getListRowPresenter();
+ }
+
+ public final class ListRowView extends android.widget.LinearLayout {
+ ctor public ListRowView(android.content.Context);
+ ctor public ListRowView(android.content.Context, android.util.AttributeSet);
+ ctor public ListRowView(android.content.Context, android.util.AttributeSet, int);
+ method public android.support.v17.leanback.widget.HorizontalGridView getGridView();
+ }
+
+ public abstract class ObjectAdapter {
+ ctor public ObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+ ctor public ObjectAdapter(android.support.v17.leanback.widget.Presenter);
+ ctor public ObjectAdapter();
+ method public abstract java.lang.Object get(int);
+ method public long getId(int);
+ method public final android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+ method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
+ method public final boolean hasStableIds();
+ method protected final void notifyChanged();
+ method protected final void notifyItemRangeChanged(int, int);
+ method protected final void notifyItemRangeInserted(int, int);
+ method protected final void notifyItemRangeRemoved(int, int);
+ method protected void onHasStableIdsChanged();
+ method protected void onPresenterSelectorChanged();
+ method public final void registerObserver(android.support.v17.leanback.widget.ObjectAdapter.DataObserver);
+ method public final void setHasStableIds(boolean);
+ method public final void setPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+ method public abstract int size();
+ method public final void unregisterAllObservers();
+ method public final void unregisterObserver(android.support.v17.leanback.widget.ObjectAdapter.DataObserver);
+ field public static final int NO_ID = -1; // 0xffffffff
+ }
+
+ public static abstract class ObjectAdapter.DataObserver {
+ ctor public ObjectAdapter.DataObserver();
+ method public void onChanged();
+ method public void onItemRangeChanged(int, int);
+ method public void onItemRangeInserted(int, int);
+ method public void onItemRangeRemoved(int, int);
+ }
+
+ public abstract interface OnActionClickedListener {
+ method public abstract void onActionClicked(android.support.v17.leanback.widget.Action);
+ }
+
+ public abstract interface OnChildLaidOutListener {
+ method public abstract void onChildLaidOut(android.view.ViewGroup, android.view.View, int, long);
+ }
+
+ public abstract deprecated interface OnChildSelectedListener {
+ method public abstract void onChildSelected(android.view.ViewGroup, android.view.View, int, long);
+ }
+
+ public abstract class OnChildViewHolderSelectedListener {
+ ctor public OnChildViewHolderSelectedListener();
+ method public void onChildViewHolderSelected(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, int);
+ }
+
+ public abstract interface OnItemViewClickedListener {
+ method public abstract void onItemClicked(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object, android.support.v17.leanback.widget.RowPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+ }
+
+ public abstract interface OnItemViewSelectedListener {
+ method public abstract void onItemSelected(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object, android.support.v17.leanback.widget.RowPresenter.ViewHolder, android.support.v17.leanback.widget.Row);
+ }
+
+ public class PlaybackControlsRow extends android.support.v17.leanback.widget.Row {
+ ctor public PlaybackControlsRow(java.lang.Object);
+ ctor public PlaybackControlsRow();
+ method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
+ method public android.support.v17.leanback.widget.Action getActionForKeyCode(android.support.v17.leanback.widget.ObjectAdapter, int);
+ method public int getBufferedProgress();
+ method public int getCurrentTime();
+ method public final android.graphics.drawable.Drawable getImageDrawable();
+ method public final java.lang.Object getItem();
+ method public final android.support.v17.leanback.widget.ObjectAdapter getPrimaryActionsAdapter();
+ method public final android.support.v17.leanback.widget.ObjectAdapter getSecondaryActionsAdapter();
+ method public int getTotalTime();
+ method public void setBufferedProgress(int);
+ method public void setCurrentTime(int);
+ method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
+ method public final void setImageDrawable(android.graphics.drawable.Drawable);
+ method public final void setPrimaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public final void setSecondaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+ method public void setTotalTime(int);
+ }
+
+ public static class PlaybackControlsRow.ClosedCaptioningAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+ ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context);
+ ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context, int);
+ field public static int OFF;
+ field public static int ON;
+ }
+
+ public static class PlaybackControlsRow.FastForwardAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+ ctor public PlaybackControlsRow.FastForwardAction(android.content.Context);
+ ctor public PlaybackControlsRow.FastForwardAction(android.content.Context, int);
+ }
+
+ public static class PlaybackControlsRow.HighQualityAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+ ctor public PlaybackControlsRow.HighQualityAction(android.content.Context);
+ ctor public PlaybackControlsRow.HighQualityAction(android.content.Context, int);
+ field public static int OFF;
+ field public static int ON;
+ }
+
+ public static class PlaybackControlsRow.MoreActions extends android.support.v17.leanback.widget.Action {
+ ctor public PlaybackControlsRow.MoreActions(android.content.Context);
+ }
+
+ public static abstract class PlaybackControlsRow.MultiAction extends android.support.v17.leanback.widget.Action {
+ ctor public PlaybackControlsRow.MultiAction(int);
+ method public int getActionCount();
+ method public android.graphics.drawable.Drawable getDrawable(int);
+ method public int getIndex();
+ method public java.lang.String getLabel(int);
+ method public java.lang.String getSecondaryLabel(int);
+ method public void nextIndex();
+ method public void setDrawables(android.graphics.drawable.Drawable[]);
+ method public void setIndex(int);
+ method public void setLabels(java.lang.String[]);
+ method public void setSecondaryLabels(java.lang.String[]);
+ }
+
+ public static class PlaybackControlsRow.PlayPauseAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+ ctor public PlaybackControlsRow.PlayPauseAction(android.content.Context);
+ field public static int PAUSE;
+ field public static int PLAY;
+ }
+
+ public static class PlaybackControlsRow.RepeatAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+ ctor public PlaybackControlsRow.RepeatAction(android.content.Context);
+ ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int);
+ ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int, int);
+ field public static int ALL;
+ field public static int NONE;
+ field public static int ONE;
+ }
+
+ public static class PlaybackControlsRow.RewindAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+ ctor public PlaybackControlsRow.RewindAction(android.content.Context);
+ ctor public PlaybackControlsRow.RewindAction(android.content.Context, int);
+ }
+
+ public static class PlaybackControlsRow.ShuffleAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+ ctor public PlaybackControlsRow.ShuffleAction(android.content.Context);
+ ctor public PlaybackControlsRow.ShuffleAction(android.content.Context, int);
+ field public static int OFF;
+ field public static int ON;
+ }
+
+ public static class PlaybackControlsRow.SkipNextAction extends android.support.v17.leanback.widget.Action {
+ ctor public PlaybackControlsRow.SkipNextAction(android.content.Context);
+ }
+
+ public static class PlaybackControlsRow.SkipPreviousAction extends android.support.v17.leanback.widget.Action {
+ ctor public PlaybackControlsRow.SkipPreviousAction(android.content.Context);
+ }
+
+ public static abstract class PlaybackControlsRow.ThumbsAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
+ ctor public PlaybackControlsRow.ThumbsAction(int, android.content.Context, int, int);
+ field public static int OUTLINE;
+ field public static int SOLID;
+ }
+
+ public static class PlaybackControlsRow.ThumbsDownAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
+ ctor public PlaybackControlsRow.ThumbsDownAction(android.content.Context);
+ }
+
+ public static class PlaybackControlsRow.ThumbsUpAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
+ ctor public PlaybackControlsRow.ThumbsUpAction(android.content.Context);
+ }
+
+ public class PlaybackControlsRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+ ctor public PlaybackControlsRowPresenter(android.support.v17.leanback.widget.Presenter);
+ ctor public PlaybackControlsRowPresenter();
+ method public boolean areSecondaryActionsHidden();
+ method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+ method public int getBackgroundColor();
+ method public android.support.v17.leanback.widget.OnActionClickedListener getOnActionClickedListener();
+ method public int getProgressColor();
+ method public void setBackgroundColor(int);
+ method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+ method public void setProgressColor(int);
+ method public void setSecondaryActionsHidden(boolean);
+ method public void showBottomSpace(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder, boolean);
+ method public void showPrimaryActions(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
+ }
+
+ public class PlaybackControlsRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+ field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDescriptionViewHolder;
+ }
+
+ public abstract class Presenter implements android.support.v17.leanback.widget.FacetProvider {
+ ctor public Presenter();
+ method protected static void cancelAnimationsRecursive(android.view.View);
+ method public final java.lang.Object getFacet(java.lang.Class<?>);
+ method public abstract void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+ method public abstract android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+ method public abstract void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public void onViewAttachedToWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public void onViewDetachedFromWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public final void setFacet(java.lang.Class<?>, java.lang.Object);
+ method public void setOnClickListener(android.support.v17.leanback.widget.Presenter.ViewHolder, android.view.View.OnClickListener);
+ }
+
+ public static class Presenter.ViewHolder implements android.support.v17.leanback.widget.FacetProvider {
+ ctor public Presenter.ViewHolder(android.view.View);
+ method public final java.lang.Object getFacet(java.lang.Class<?>);
+ method public final void setFacet(java.lang.Class<?>, java.lang.Object);
+ field public final android.view.View view;
+ }
+
+ public abstract class PresenterSelector {
+ ctor public PresenterSelector();
+ method public abstract android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+ method public android.support.v17.leanback.widget.Presenter[] getPresenters();
+ }
+
+ public abstract class PresenterSwitcher {
+ ctor public PresenterSwitcher();
+ method public void clear();
+ method public final android.view.ViewGroup getParentViewGroup();
+ method public void init(android.view.ViewGroup, android.support.v17.leanback.widget.PresenterSelector);
+ method protected abstract void insertView(android.view.View);
+ method protected void onViewSelected(android.view.View);
+ method public void select(java.lang.Object);
+ method protected void showView(android.view.View, boolean);
+ method public void unselect();
+ }
+
+ public class Row {
+ ctor public Row(long, android.support.v17.leanback.widget.HeaderItem);
+ ctor public Row(android.support.v17.leanback.widget.HeaderItem);
+ ctor public Row();
+ method public final android.support.v17.leanback.widget.HeaderItem getHeaderItem();
+ method public final long getId();
+ method public final void setHeaderItem(android.support.v17.leanback.widget.HeaderItem);
+ method public final void setId(long);
+ }
+
+ public class RowHeaderPresenter extends android.support.v17.leanback.widget.Presenter {
+ ctor public RowHeaderPresenter();
+ method protected static float getFontDescent(android.widget.TextView, android.graphics.Paint);
+ method public int getSpaceUnderBaseline(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder);
+ method public boolean isNullItemVisibilityGone();
+ method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+ method public android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+ method protected void onSelectLevelChanged(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder);
+ method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public void setNullItemVisibilityGone(boolean);
+ method public final void setSelectLevel(android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder, float);
+ }
+
+ public static class RowHeaderPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+ ctor public RowHeaderPresenter.ViewHolder(android.view.View);
+ method public final float getSelectLevel();
+ }
+
+ public final class RowHeaderView extends android.widget.TextView {
+ ctor public RowHeaderView(android.content.Context);
+ ctor public RowHeaderView(android.content.Context, android.util.AttributeSet);
+ ctor public RowHeaderView(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public abstract class RowPresenter extends android.support.v17.leanback.widget.Presenter {
+ ctor public RowPresenter();
+ method protected abstract android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+ method protected void dispatchItemSelectedListener(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+ method public void freeze(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+ method public final android.support.v17.leanback.widget.RowHeaderPresenter getHeaderPresenter();
+ method public final android.support.v17.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public final boolean getSelectEffectEnabled();
+ method public final float getSelectLevel(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public final int getSyncActivatePolicy();
+ method protected void initializeRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+ method protected boolean isClippingChildren();
+ method public boolean isUsingDefaultSelectEffect();
+ method protected void onBindRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder, java.lang.Object);
+ method public final void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+ method public final android.support.v17.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+ method protected void onRowViewAttachedToWindow(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+ method protected void onRowViewDetachedFromWindow(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+ method protected void onRowViewExpanded(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+ method protected void onRowViewSelected(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+ method protected void onSelectLevelChanged(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+ method protected void onUnbindRowViewHolder(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+ method public final void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public final void onViewAttachedToWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public final void onViewDetachedFromWindow(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public void setEntranceTransitionState(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
+ method public final void setHeaderPresenter(android.support.v17.leanback.widget.RowHeaderPresenter);
+ method public final void setRowViewExpanded(android.support.v17.leanback.widget.Presenter.ViewHolder, boolean);
+ method public final void setRowViewSelected(android.support.v17.leanback.widget.Presenter.ViewHolder, boolean);
+ method public final void setSelectEffectEnabled(boolean);
+ method public final void setSelectLevel(android.support.v17.leanback.widget.Presenter.ViewHolder, float);
+ method public final void setSyncActivatePolicy(int);
+ field public static final int SYNC_ACTIVATED_CUSTOM = 0; // 0x0
+ field public static final int SYNC_ACTIVATED_TO_EXPANDED = 1; // 0x1
+ field public static final int SYNC_ACTIVATED_TO_EXPANDED_AND_SELECTED = 3; // 0x3
+ field public static final int SYNC_ACTIVATED_TO_SELECTED = 2; // 0x2
+ }
+
+ public static class RowPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+ ctor public RowPresenter.ViewHolder(android.view.View);
+ method public final android.support.v17.leanback.widget.RowHeaderPresenter.ViewHolder getHeaderViewHolder();
+ method public final android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public final android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+ method public android.view.View.OnKeyListener getOnKeyListener();
+ method public final android.support.v17.leanback.widget.Row getRow();
+ method public final float getSelectLevel();
+ method public final boolean isExpanded();
+ method public final boolean isSelected();
+ method public final void setActivated(boolean);
+ method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public void setOnKeyListener(android.view.View.OnKeyListener);
+ method public final void syncActivatedStatus(android.view.View);
+ field protected final android.support.v17.leanback.graphics.ColorOverlayDimmer mColorDimmer;
+ }
+
+ public class SearchBar extends android.widget.RelativeLayout {
+ ctor public SearchBar(android.content.Context);
+ ctor public SearchBar(android.content.Context, android.util.AttributeSet);
+ ctor public SearchBar(android.content.Context, android.util.AttributeSet, int);
+ method public void displayCompletions(java.util.List<java.lang.String>);
+ method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+ method public android.graphics.drawable.Drawable getBadgeDrawable();
+ method public java.lang.CharSequence getHint();
+ method public java.lang.String getTitle();
+ method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+ method public void setSearchBarListener(android.support.v17.leanback.widget.SearchBar.SearchBarListener);
+ method public void setSearchQuery(java.lang.String);
+ method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
+ method public void setSpeechRecognizer(android.speech.SpeechRecognizer);
+ method public void setTitle(java.lang.String);
+ method public void startRecognition();
+ method public void stopRecognition();
+ }
+
+ public static abstract interface SearchBar.SearchBarListener {
+ method public abstract void onKeyboardDismiss(java.lang.String);
+ method public abstract void onSearchQueryChange(java.lang.String);
+ method public abstract void onSearchQuerySubmit(java.lang.String);
+ }
+
+ public class SearchEditText extends android.support.v17.leanback.widget.StreamingTextView {
+ ctor public SearchEditText(android.content.Context);
+ ctor public SearchEditText(android.content.Context, android.util.AttributeSet);
+ ctor public SearchEditText(android.content.Context, android.util.AttributeSet, int);
+ method public void setOnKeyboardDismissListener(android.support.v17.leanback.widget.SearchEditText.OnKeyboardDismissListener);
+ }
+
+ public static abstract interface SearchEditText.OnKeyboardDismissListener {
+ method public abstract void onKeyboardDismiss();
+ }
+
+ public class SearchOrbView extends android.widget.FrameLayout implements android.view.View.OnClickListener {
+ ctor public SearchOrbView(android.content.Context);
+ ctor public SearchOrbView(android.content.Context, android.util.AttributeSet);
+ ctor public SearchOrbView(android.content.Context, android.util.AttributeSet, int);
+ method public void enableOrbColorAnimation(boolean);
+ method public int getOrbColor();
+ method public android.support.v17.leanback.widget.SearchOrbView.Colors getOrbColors();
+ method public android.graphics.drawable.Drawable getOrbIcon();
+ method public void onClick(android.view.View);
+ method public void setOnOrbClickedListener(android.view.View.OnClickListener);
+ method public void setOrbColor(int);
+ method public deprecated void setOrbColor(int, int);
+ method public void setOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+ method public void setOrbIcon(android.graphics.drawable.Drawable);
+ }
+
+ public static class SearchOrbView.Colors {
+ ctor public SearchOrbView.Colors(int);
+ ctor public SearchOrbView.Colors(int, int);
+ ctor public SearchOrbView.Colors(int, int, int);
+ method public static int getBrightColor(int);
+ field public int brightColor;
+ field public int color;
+ field public int iconColor;
+ }
+
+ public class ShadowOverlayContainer extends android.widget.FrameLayout {
+ ctor public ShadowOverlayContainer(android.content.Context);
+ ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet);
+ ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet, int);
+ method public int getShadowType();
+ method public android.view.View getWrappedView();
+ method public deprecated void initialize(boolean, boolean);
+ method public deprecated void initialize(boolean, boolean, boolean);
+ method public static void prepareParentForShadow(android.view.ViewGroup);
+ method public void setOverlayColor(int);
+ method public void setShadowFocusLevel(float);
+ method public static boolean supportsDynamicShadow();
+ method public static boolean supportsShadow();
+ method public void useDynamicShadow();
+ method public void useDynamicShadow(float, float);
+ method public void useStaticShadow();
+ method public void wrap(android.view.View);
+ field public static final int SHADOW_DYNAMIC = 3; // 0x3
+ field public static final int SHADOW_NONE = 1; // 0x1
+ field public static final int SHADOW_STATIC = 2; // 0x2
+ }
+
+ public final class ShadowOverlayHelper {
+ method public android.support.v17.leanback.widget.ShadowOverlayContainer createShadowOverlayContainer(android.content.Context);
+ method public int getShadowType();
+ method public boolean needsOverlay();
+ method public boolean needsRoundedCorner();
+ method public boolean needsWrapper();
+ method public void onViewCreated(android.view.View);
+ method public void prepareParentForShadow(android.view.ViewGroup);
+ method public static void setNoneWrapperOverlayColor(android.view.View, int);
+ method public static void setNoneWrapperShadowFocusLevel(android.view.View, float);
+ method public void setOverlayColor(android.view.View, int);
+ method public void setShadowFocusLevel(android.view.View, float);
+ method public static boolean supportsDynamicShadow();
+ method public static boolean supportsForeground();
+ method public static boolean supportsRoundedCorner();
+ method public static boolean supportsShadow();
+ field public static final int SHADOW_DYNAMIC = 3; // 0x3
+ field public static final int SHADOW_NONE = 1; // 0x1
+ field public static final int SHADOW_STATIC = 2; // 0x2
+ }
+
+ public static final class ShadowOverlayHelper.Builder {
+ ctor public ShadowOverlayHelper.Builder();
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper build(android.content.Context);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder keepForegroundDrawable(boolean);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsOverlay(boolean);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsRoundedCorner(boolean);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsShadow(boolean);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder options(android.support.v17.leanback.widget.ShadowOverlayHelper.Options);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder preferZOrder(boolean);
+ }
+
+ public static final class ShadowOverlayHelper.Options {
+ ctor public ShadowOverlayHelper.Options();
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options dynamicShadowZ(float, float);
+ method public final float getDynamicShadowFocusedZ();
+ method public final float getDynamicShadowUnfocusedZ();
+ method public final int getRoundedCornerRadius();
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options roundedCornerRadius(int);
+ field public static final android.support.v17.leanback.widget.ShadowOverlayHelper.Options DEFAULT;
+ }
+
+ public final class SinglePresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
+ ctor public SinglePresenterSelector(android.support.v17.leanback.widget.Presenter);
+ method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
+ }
+
+ public class SparseArrayObjectAdapter extends android.support.v17.leanback.widget.ObjectAdapter {
+ ctor public SparseArrayObjectAdapter(android.support.v17.leanback.widget.PresenterSelector);
+ ctor public SparseArrayObjectAdapter(android.support.v17.leanback.widget.Presenter);
+ ctor public SparseArrayObjectAdapter();
+ method public void clear(int);
+ method public void clear();
+ method public java.lang.Object get(int);
+ method public int indexOf(java.lang.Object);
+ method public int indexOf(int);
+ method public java.lang.Object lookup(int);
+ method public void notifyArrayItemRangeChanged(int, int);
+ method public void set(int, java.lang.Object);
+ method public int size();
+ }
+
+ public class SpeechOrbView extends android.support.v17.leanback.widget.SearchOrbView {
+ ctor public SpeechOrbView(android.content.Context);
+ ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet);
+ ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet, int);
+ method public void setSoundLevel(int);
+ method public void showListening();
+ method public void showNotListening();
+ }
+
+ public abstract interface SpeechRecognitionCallback {
+ method public abstract void recognizeSpeech();
+ }
+
+ class StreamingTextView extends android.widget.EditText {
+ ctor public StreamingTextView(android.content.Context, android.util.AttributeSet);
+ ctor public StreamingTextView(android.content.Context, android.util.AttributeSet, int);
+ method public static boolean isLayoutRtl(android.view.View);
+ method public void reset();
+ method public void setFinalRecognizedText(java.lang.CharSequence);
+ method public void updateRecognizedText(java.lang.String, java.lang.String);
+ method public void updateRecognizedText(java.lang.String, java.util.List<java.lang.Float>);
+ }
+
+ public class TitleHelper {
+ ctor public TitleHelper(android.view.ViewGroup, android.support.v17.leanback.widget.TitleView);
+ method public android.support.v17.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
+ method public android.view.ViewGroup getSceneRoot();
+ method public android.support.v17.leanback.widget.TitleView getTitleView();
+ method public void showTitle(boolean);
+ }
+
+ public class TitleView extends android.widget.FrameLayout {
+ ctor public TitleView(android.content.Context);
+ ctor public TitleView(android.content.Context, android.util.AttributeSet);
+ ctor public TitleView(android.content.Context, android.util.AttributeSet, int);
+ method public void enableAnimation(boolean);
+ method public android.graphics.drawable.Drawable getBadgeDrawable();
+ method public android.support.v17.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
+ method public android.view.View getSearchAffordanceView();
+ method public java.lang.CharSequence getTitle();
+ method public void setBadgeDrawable(android.graphics.drawable.Drawable);
+ method public void setOnSearchClickedListener(android.view.View.OnClickListener);
+ method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+ method public void setTitle(java.lang.String);
+ }
+
+ public class VerticalGridPresenter extends android.support.v17.leanback.widget.Presenter {
+ ctor public VerticalGridPresenter();
+ ctor public VerticalGridPresenter(int);
+ ctor public VerticalGridPresenter(int, boolean);
+ method public final boolean areChildRoundedCornersEnabled();
+ method protected android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder createGridViewHolder(android.view.ViewGroup);
+ method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
+ method public final void enableChildRoundedCorners(boolean);
+ method public final int getFocusZoomFactor();
+ method public final boolean getKeepChildForeground();
+ method public int getNumberOfColumns();
+ method public final android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public final android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
+ method public final boolean getShadowEnabled();
+ method protected void initializeGridViewHolder(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder);
+ method public final boolean isFocusDimmerUsed();
+ method public boolean isUsingDefaultShadow();
+ method public boolean isUsingZOrder(android.content.Context);
+ method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
+ method public final android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+ method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public void setEntranceTransitionState(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder, boolean);
+ method public final void setKeepChildForeground(boolean);
+ method public void setNumberOfColumns(int);
+ method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+ method public final void setShadowEnabled(boolean);
+ }
+
+ public static class VerticalGridPresenter.ViewHolder extends android.support.v17.leanback.widget.Presenter.ViewHolder {
+ ctor public VerticalGridPresenter.ViewHolder(android.support.v17.leanback.widget.VerticalGridView);
+ method public android.support.v17.leanback.widget.VerticalGridView getGridView();
+ }
+
+ public class VerticalGridView extends android.support.v7.widget.RecyclerView {
+ ctor public VerticalGridView(android.content.Context);
+ ctor public VerticalGridView(android.content.Context, android.util.AttributeSet);
+ ctor public VerticalGridView(android.content.Context, android.util.AttributeSet, int);
+ method protected void initAttributes(android.content.Context, android.util.AttributeSet);
+ method public void setColumnWidth(int);
+ method public void setNumColumns(int);
+ }
+
+}
+
diff --git a/v17/leanback/api/current.txt b/v17/leanback/api/current.txt
index fb2832d..a4decd8 100644
--- a/v17/leanback/api/current.txt
+++ b/v17/leanback/api/current.txt
@@ -37,6 +37,7 @@
public class BrowseFragment extends android.support.v17.leanback.app.BrandedFragment {
ctor public BrowseFragment();
method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+ method protected java.lang.Object createEntranceTransition();
method public void enableRowScaling(boolean);
method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
method public int getBrandColor();
@@ -46,6 +47,12 @@
method public final boolean isHeadersTransitionOnBackEnabled();
method public boolean isInHeadersTransition();
method public boolean isShowingHeaders();
+ method protected void onEntranceTransitionEnd();
+ method protected void onEntranceTransitionPrepare();
+ method protected void onEntranceTransitionStart();
+ method public void onSaveInstanceState(android.os.Bundle);
+ method public void onStart();
+ method protected void runEntranceTransition(java.lang.Object);
method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
method public void setBrandColor(int);
method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseFragment.BrowseTransitionListener);
@@ -71,6 +78,7 @@
public class BrowseSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
ctor public BrowseSupportFragment();
method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
+ method protected java.lang.Object createEntranceTransition();
method public void enableRowScaling(boolean);
method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
method public int getBrandColor();
@@ -80,6 +88,12 @@
method public final boolean isHeadersTransitionOnBackEnabled();
method public boolean isInHeadersTransition();
method public boolean isShowingHeaders();
+ method protected void onEntranceTransitionEnd();
+ method protected void onEntranceTransitionPrepare();
+ method protected void onEntranceTransitionStart();
+ method public void onSaveInstanceState(android.os.Bundle);
+ method public void onStart();
+ method protected void runEntranceTransition(java.lang.Object);
method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
method public void setBrandColor(int);
method public void setBrowseTransitionListener(android.support.v17.leanback.app.BrowseSupportFragment.BrowseTransitionListener);
@@ -104,11 +118,17 @@
public class DetailsFragment extends android.support.v17.leanback.app.BrandedFragment {
ctor public DetailsFragment();
+ method protected java.lang.Object createEntranceTransition();
method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
method protected android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method protected void onEntranceTransitionEnd();
+ method protected void onEntranceTransitionPrepare();
+ method protected void onEntranceTransitionStart();
method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+ method public void onStart();
+ method protected void runEntranceTransition(java.lang.Object);
method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
@@ -120,11 +140,17 @@
public class DetailsSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
ctor public DetailsSupportFragment();
+ method protected java.lang.Object createEntranceTransition();
method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
method protected android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method protected void onEntranceTransitionEnd();
+ method protected void onEntranceTransitionPrepare();
+ method protected void onEntranceTransitionStart();
method protected void onSetDetailsOverviewRowStatus(android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter, android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
method protected void onSetRowStatus(android.support.v17.leanback.widget.RowPresenter, android.support.v17.leanback.widget.RowPresenter.ViewHolder, int, int, int);
+ method public void onStart();
+ method protected void runEntranceTransition(java.lang.Object);
method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
@@ -177,23 +203,109 @@
public class GuidedStepFragment extends android.app.Fragment {
ctor public GuidedStepFragment();
method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment);
+ method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment, int);
+ method public static int addAsRoot(android.app.Activity, android.support.v17.leanback.app.GuidedStepFragment, int);
+ method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
+ method public int findActionPositionById(long);
+ method public android.support.v17.leanback.widget.GuidedAction findButtonActionById(long);
+ method public int findButtonActionPositionById(long);
+ method public void finishGuidedStepFragments();
+ method public java.lang.String generateStackEntryName();
+ method public static java.lang.String generateStackEntryName(int, java.lang.Class);
method public android.view.View getActionItemView(int);
method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+ method public android.view.View getButtonActionItemView(int);
+ method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
method public static android.support.v17.leanback.app.GuidedStepFragment getCurrentGuidedStepFragment(android.app.FragmentManager);
method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+ method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
+ method public static java.lang.String getGuidedStepFragmentClassName(java.lang.String);
method public int getSelectedActionPosition();
- method protected boolean isEntryTransitionEnabled();
+ method public int getSelectedButtonActionPosition();
+ method public int getUiStyle();
+ method public static boolean isUiStyleDefault(java.lang.String);
+ method public static boolean isUiStyleEntrance(java.lang.String);
+ method public void notifyActionChanged(int);
+ method public void notifyButtonActionChanged(int);
+ method protected void onAddSharedElementTransition(android.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepFragment);
method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+ method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+ method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+ method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+ method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+ method protected void onProvideFragmentTransitions();
method public int onProvideTheme();
+ method public void popBackStackToGuidedStepFragment(java.lang.Class, int);
method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
- method protected void setEntryTransitionEnabled(boolean);
+ method public void setButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
method public void setSelectedActionPosition(int);
+ method public void setSelectedButtonActionPosition(int);
+ method public void setUiStyle(int);
+ field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+ field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+ field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+ field public static final int UI_STYLE_REPLACE = 0; // 0x0
+ }
+
+ public class GuidedStepSupportFragment extends android.support.v4.app.Fragment {
+ ctor public GuidedStepSupportFragment();
+ method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment);
+ method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+ method public static int addAsRoot(android.support.v4.app.FragmentActivity, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+ method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
+ method public int findActionPositionById(long);
+ method public android.support.v17.leanback.widget.GuidedAction findButtonActionById(long);
+ method public int findButtonActionPositionById(long);
+ method public void finishGuidedStepSupportFragments();
+ method public java.lang.String generateStackEntryName();
+ method public static java.lang.String generateStackEntryName(int, java.lang.Class);
+ method public android.view.View getActionItemView(int);
+ method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
+ method public android.view.View getButtonActionItemView(int);
+ method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
+ method public static android.support.v17.leanback.app.GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(android.support.v4.app.FragmentManager);
+ method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
+ method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
+ method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
+ method public static java.lang.String getGuidedStepSupportFragmentClassName(java.lang.String);
+ method public int getSelectedActionPosition();
+ method public int getSelectedButtonActionPosition();
+ method public int getUiStyle();
+ method public static boolean isUiStyleDefault(java.lang.String);
+ method public static boolean isUiStyleEntrance(java.lang.String);
+ method public void notifyActionChanged(int);
+ method public void notifyButtonActionChanged(int);
+ method protected void onAddSharedElementTransition(android.support.v4.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepSupportFragment);
+ method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+ method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+ method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
+ method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
+ method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
+ method public android.support.v17.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
+ method public void onGuidedActionClicked(android.support.v17.leanback.widget.GuidedAction);
+ method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
+ method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
+ method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
+ method protected void onProvideFragmentTransitions();
+ method public int onProvideTheme();
+ method public void popBackStackToGuidedStepSupportFragment(java.lang.Class, int);
+ method public void setActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+ method public void setButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>);
+ method public void setSelectedActionPosition(int);
+ method public void setSelectedButtonActionPosition(int);
+ method public void setUiStyle(int);
+ field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
+ field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
+ field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
+ field public static final int UI_STYLE_REPLACE = 0; // 0x0
}
public class HeadersFragment extends android.support.v17.leanback.app.BaseRowFragment {
@@ -300,12 +412,69 @@
field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
}
+ public abstract class PlaybackControlSupportGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+ ctor public PlaybackControlSupportGlue(android.content.Context, int[]);
+ ctor public PlaybackControlSupportGlue(android.content.Context, int[], int[]);
+ ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[]);
+ ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[], int[]);
+ method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
+ method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
+ method public void enableProgressUpdating(boolean);
+ method public android.content.Context getContext();
+ method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
+ method public abstract int getCurrentPosition();
+ method public abstract int getCurrentSpeedId();
+ method public int[] getFastForwardSpeeds();
+ method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment getFragment();
+ method public abstract android.graphics.drawable.Drawable getMediaArt();
+ method public abstract int getMediaDuration();
+ method public abstract java.lang.CharSequence getMediaSubtitle();
+ method public abstract java.lang.CharSequence getMediaTitle();
+ method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public int[] getRewindSpeeds();
+ method public abstract long getSupportedActions();
+ method public int getUpdatePeriod();
+ method public abstract boolean hasValidMedia();
+ method public boolean isFadingEnabled();
+ method public abstract boolean isMediaPlaying();
+ method public void onActionClicked(android.support.v17.leanback.widget.Action);
+ method public boolean onKey(android.view.View, int, android.view.KeyEvent);
+ method protected void onMetadataChanged();
+ method protected abstract void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
+ method protected void onStateChanged();
+ method protected abstract void pausePlayback();
+ method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
+ method public void setFadingEnabled(boolean);
+ method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
+ method protected abstract void skipToNext();
+ method protected abstract void skipToPrevious();
+ method protected abstract void startPlayback(int);
+ method public void updateProgress();
+ field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
+ field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
+ field public static final int ACTION_FAST_FORWARD = 128; // 0x80
+ field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
+ field public static final int ACTION_REWIND = 32; // 0x20
+ field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
+ field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
+ field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
+ field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
+ field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
+ field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
+ field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
+ field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
+ field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
+ field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
+ }
+
public class PlaybackOverlayFragment extends android.support.v17.leanback.app.DetailsFragment {
ctor public PlaybackOverlayFragment();
method public int getBackgroundType();
method public android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener getFadeCompleteListener();
method public final android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler getInputEventHandler();
method public boolean isFadingEnabled();
+ method public void onDestroyView();
+ method public void onResume();
method public void setBackgroundType(int);
method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener);
method public void setFadingEnabled(boolean);
@@ -332,6 +501,8 @@
method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener getFadeCompleteListener();
method public final android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler getInputEventHandler();
method public boolean isFadingEnabled();
+ method public void onDestroyView();
+ method public void onResume();
method public void setBackgroundType(int);
method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener);
method public void setFadingEnabled(boolean);
@@ -379,6 +550,7 @@
method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
method public void displayCompletions(java.util.List<java.lang.String>);
+ method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
method public android.graphics.drawable.Drawable getBadgeDrawable();
method public android.content.Intent getRecognizerIntent();
method public java.lang.String getTitle();
@@ -405,6 +577,7 @@
method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
method public void displayCompletions(java.util.List<java.lang.String>);
+ method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
method public android.graphics.drawable.Drawable getBadgeDrawable();
method public android.content.Intent getRecognizerIntent();
method public java.lang.String getTitle();
@@ -426,11 +599,16 @@
method public abstract boolean onQueryTextSubmit(java.lang.String);
}
- public class VerticalGridFragment extends android.app.Fragment {
+ public class VerticalGridFragment extends android.support.v17.leanback.app.BrandedFragment {
ctor public VerticalGridFragment();
+ method protected java.lang.Object createEntranceTransition();
method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public void onDestroyView();
+ method public void onStart();
+ method public void onViewCreated(android.view.View, android.os.Bundle);
+ method protected void runEntranceTransition(java.lang.Object);
method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
@@ -438,11 +616,16 @@
method public void setSelectedPosition(int);
}
- public class VerticalGridSupportFragment extends android.support.v4.app.Fragment {
+ public class VerticalGridSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
ctor public VerticalGridSupportFragment();
+ method protected java.lang.Object createEntranceTransition();
method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
method public android.support.v17.leanback.widget.VerticalGridPresenter getGridPresenter();
method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+ method public void onDestroyView();
+ method public void onStart();
+ method public void onViewCreated(android.view.View, android.os.Bundle);
+ method protected void runEntranceTransition(java.lang.Object);
method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
method public void setGridPresenter(android.support.v17.leanback.widget.VerticalGridPresenter);
method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
@@ -722,12 +905,8 @@
}
public abstract interface FragmentAnimationProvider {
- method public abstract void onActivityEnter(java.util.List<android.animation.Animator>);
- method public abstract void onActivityExit(java.util.List<android.animation.Animator>);
- method public abstract void onFragmentEnter(java.util.List<android.animation.Animator>);
- method public abstract void onFragmentExit(java.util.List<android.animation.Animator>);
- method public abstract void onFragmentReenter(java.util.List<android.animation.Animator>);
- method public abstract void onFragmentReturn(java.util.List<android.animation.Animator>);
+ method public abstract void onImeAppearing(java.util.List<android.animation.Animator>);
+ method public abstract void onImeDisappearing(java.util.List<android.animation.Animator>);
}
public class FullWidthDetailsOverviewRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
@@ -798,13 +977,10 @@
method public android.widget.TextView getDescriptionView();
method public android.widget.ImageView getIconView();
method public android.widget.TextView getTitleView();
- method public void onActivityEnter(java.util.List<android.animation.Animator>);
- method public void onActivityExit(java.util.List<android.animation.Animator>);
method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.support.v17.leanback.widget.GuidanceStylist.Guidance);
- method public void onFragmentEnter(java.util.List<android.animation.Animator>);
- method public void onFragmentExit(java.util.List<android.animation.Animator>);
- method public void onFragmentReenter(java.util.List<android.animation.Animator>);
- method public void onFragmentReturn(java.util.List<android.animation.Animator>);
+ method public void onDestroyView();
+ method public void onImeAppearing(java.util.List<android.animation.Animator>);
+ method public void onImeDisappearing(java.util.List<android.animation.Animator>);
method public int onProvideLayoutId();
}
@@ -817,59 +993,112 @@
}
public class GuidedAction extends android.support.v17.leanback.widget.Action {
+ ctor protected GuidedAction();
method public int getCheckSetId();
method public java.lang.CharSequence getDescription();
+ method public int getDescriptionEditInputType();
+ method public int getDescriptionInputType();
+ method public java.lang.CharSequence getEditDescription();
+ method public int getEditInputType();
+ method public java.lang.CharSequence getEditTitle();
+ method public int getInputType();
method public android.content.Intent getIntent();
method public java.lang.CharSequence getTitle();
method public boolean hasMultilineDescription();
method public boolean hasNext();
method public boolean infoOnly();
method public boolean isChecked();
+ method public boolean isDescriptionEditable();
+ method public boolean isEditTitleUsed();
+ method public boolean isEditable();
method public boolean isEnabled();
+ method public boolean isFocusable();
method public void setChecked(boolean);
+ method public void setDescription(java.lang.CharSequence);
+ method public void setEditDescription(java.lang.CharSequence);
+ method public void setEditTitle(java.lang.CharSequence);
method public void setEnabled(boolean);
+ method public void setFocusable(boolean);
+ method public void setTitle(java.lang.CharSequence);
+ field public static final long ACTION_ID_CANCEL = -5L; // 0xfffffffffffffffbL
+ field public static final long ACTION_ID_CONTINUE = -7L; // 0xfffffffffffffff9L
+ field public static final long ACTION_ID_CURRENT = -3L; // 0xfffffffffffffffdL
+ field public static final long ACTION_ID_FINISH = -6L; // 0xfffffffffffffffaL
+ field public static final long ACTION_ID_NEXT = -2L; // 0xfffffffffffffffeL
+ field public static final long ACTION_ID_NO = -9L; // 0xfffffffffffffff7L
+ field public static final long ACTION_ID_OK = -4L; // 0xfffffffffffffffcL
+ field public static final long ACTION_ID_YES = -8L; // 0xfffffffffffffff8L
+ field public static final int CHECKBOX_CHECK_SET_ID = -1; // 0xffffffff
field public static final int DEFAULT_CHECK_SET_ID = 1; // 0x1
field public static final int NO_CHECK_SET = 0; // 0x0
- field public static final int NO_DRAWABLE = 0; // 0x0
}
public static class GuidedAction.Builder {
ctor public GuidedAction.Builder();
- method public android.support.v17.leanback.widget.GuidedAction build();
+ method protected final void applyValues(android.support.v17.leanback.widget.GuidedAction);
+ method public final android.support.v17.leanback.widget.GuidedAction build();
method public android.support.v17.leanback.widget.GuidedAction.Builder checkSetId(int);
method public android.support.v17.leanback.widget.GuidedAction.Builder checked(boolean);
- method public android.support.v17.leanback.widget.GuidedAction.Builder description(java.lang.String);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder constructCancel(android.content.Context);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder constructContinue(android.content.Context);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder constructFinish(android.content.Context);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder constructNo(android.content.Context);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder constructOK(android.content.Context);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder constructYes(android.content.Context);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder description(java.lang.CharSequence);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder descriptionEditInputType(int);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder descriptionEditable(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder descriptionInputType(int);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder editDescription(java.lang.CharSequence);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder editInputType(int);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder editTitle(java.lang.CharSequence);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder editable(boolean);
method public android.support.v17.leanback.widget.GuidedAction.Builder enabled(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder focusable(boolean);
method public android.support.v17.leanback.widget.GuidedAction.Builder hasNext(boolean);
method public android.support.v17.leanback.widget.GuidedAction.Builder icon(android.graphics.drawable.Drawable);
method public android.support.v17.leanback.widget.GuidedAction.Builder iconResourceId(int, android.content.Context);
method public android.support.v17.leanback.widget.GuidedAction.Builder id(long);
method public android.support.v17.leanback.widget.GuidedAction.Builder infoOnly(boolean);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder inputType(int);
method public android.support.v17.leanback.widget.GuidedAction.Builder intent(android.content.Intent);
method public android.support.v17.leanback.widget.GuidedAction.Builder multilineDescription(boolean);
- method public android.support.v17.leanback.widget.GuidedAction.Builder title(java.lang.String);
+ method public android.support.v17.leanback.widget.GuidedAction.Builder title(java.lang.CharSequence);
+ }
+
+ public class GuidedActionEditText extends android.widget.EditText implements android.support.v17.leanback.widget.ImeKeyMonitor {
+ ctor public GuidedActionEditText(android.content.Context);
+ ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet);
+ ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet, int);
+ method public void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
}
public class GuidedActionsStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
ctor public GuidedActionsStylist();
method public android.support.v17.leanback.widget.VerticalGridView getActionsGridView();
- method public void onActivityEnter(java.util.List<android.animation.Animator>);
- method public void onActivityExit(java.util.List<android.animation.Animator>);
+ method public int getItemViewType(android.support.v17.leanback.widget.GuidedAction);
+ method public boolean isButtonActions();
method public void onAnimateItemChecked(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
method public void onAnimateItemFocused(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
method public void onAnimateItemPressed(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
+ method public void onAnimateItemPressedCancelled(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+ method public void onBindCheckMarkView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+ method public void onBindChevronView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
method public void onBindViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup);
method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
- method public void onFragmentEnter(java.util.List<android.animation.Animator>);
- method public void onFragmentExit(java.util.List<android.animation.Animator>);
- method public void onFragmentReenter(java.util.List<android.animation.Animator>);
- method public void onFragmentReturn(java.util.List<android.animation.Animator>);
+ method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+ method public void onDestroyView();
+ method protected void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+ method public void onImeAppearing(java.util.List<android.animation.Animator>);
+ method public void onImeDisappearing(java.util.List<android.animation.Animator>);
method public int onProvideItemLayoutId();
+ method public int onProvideItemLayoutId(int);
method public int onProvideLayoutId();
- field protected android.support.v17.leanback.widget.VerticalGridView mActionsGridView;
- field protected android.view.View mMainView;
- field protected android.view.View mSelectorView;
+ method public void setAsButtonActions();
+ method public void setEditingMode(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+ method protected void setupImeOptions(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+ field public static final int VIEW_TYPE_DEFAULT = 0; // 0x0
}
public static class GuidedActionsStylist.ViewHolder {
@@ -878,8 +1107,13 @@
method public android.widget.ImageView getChevronView();
method public android.view.View getContentView();
method public android.widget.TextView getDescriptionView();
+ method public android.widget.EditText getEditableDescriptionView();
+ method public android.widget.EditText getEditableTitleView();
+ method public android.view.View getEditingView();
method public android.widget.ImageView getIconView();
method public android.widget.TextView getTitleView();
+ method public boolean isInEditing();
+ method public boolean isInEditingDescription();
field public final android.view.View view;
}
@@ -918,9 +1152,10 @@
}
public class ImageCardView extends android.support.v17.leanback.widget.BaseCardView {
+ ctor public ImageCardView(android.content.Context, int);
+ ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
ctor public ImageCardView(android.content.Context);
ctor public ImageCardView(android.content.Context, android.util.AttributeSet);
- ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
method public android.graphics.drawable.Drawable getBadgeImage();
method public java.lang.CharSequence getContentText();
method public android.graphics.drawable.Drawable getInfoAreaBackground();
@@ -937,6 +1172,19 @@
method public void setMainImageDimensions(int, int);
method public void setMainImageScaleType(android.widget.ImageView.ScaleType);
method public void setTitleText(java.lang.CharSequence);
+ field public static final int CARD_TYPE_FLAG_CONTENT = 2; // 0x2
+ field public static final int CARD_TYPE_FLAG_ICON_LEFT = 8; // 0x8
+ field public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4; // 0x4
+ field public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0; // 0x0
+ field public static final int CARD_TYPE_FLAG_TITLE = 1; // 0x1
+ }
+
+ public abstract interface ImeKeyMonitor {
+ method public abstract void setImeKeyListener(android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener);
+ }
+
+ public static abstract interface ImeKeyMonitor.ImeKeyListener {
+ method public abstract boolean onKeyPreIme(android.widget.EditText, int, android.view.KeyEvent);
}
public final class ItemAlignmentFacet {
@@ -1012,6 +1260,12 @@
method public abstract void wrap(android.view.View, android.view.View);
}
+ public class ItemBridgeAdapterShadowOverlayWrapper extends android.support.v17.leanback.widget.ItemBridgeAdapter.Wrapper {
+ ctor public ItemBridgeAdapterShadowOverlayWrapper(android.support.v17.leanback.widget.ShadowOverlayHelper);
+ method public android.view.View createWrapper(android.view.View);
+ method public void wrap(android.view.View, android.view.View);
+ }
+
public class ListRow extends android.support.v17.leanback.widget.Row {
ctor public ListRow(android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
ctor public ListRow(long, android.support.v17.leanback.widget.HeaderItem, android.support.v17.leanback.widget.ObjectAdapter);
@@ -1035,6 +1289,7 @@
ctor public ListRowPresenter(int, boolean);
method public final boolean areChildRoundedCornersEnabled();
method protected android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
+ method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
method public final void enableChildRoundedCorners(boolean);
method public int getExpandedRowHeight();
method public final int getFocusZoomFactor();
@@ -1044,12 +1299,14 @@
method public final boolean getShadowEnabled();
method public final deprecated int getZoomFactor();
method public final boolean isFocusDimmerUsed();
+ method public final boolean isKeepChildForeground();
method public boolean isUsingDefaultListSelectEffect();
method public final boolean isUsingDefaultSelectEffect();
method public boolean isUsingDefaultShadow();
method public boolean isUsingZOrder(android.content.Context);
method public void setExpandedRowHeight(int);
method public final void setHoverCardPresenterSelector(android.support.v17.leanback.widget.PresenterSelector);
+ method public final void setKeepChildForeground(boolean);
method public void setRecycledPoolSize(android.support.v17.leanback.widget.Presenter, int);
method public void setRowHeight(int);
method public final void setShadowEnabled(boolean);
@@ -1327,7 +1584,6 @@
public abstract class RowPresenter extends android.support.v17.leanback.widget.Presenter {
ctor public RowPresenter();
- method public boolean canDrawOutOfBounds();
method protected abstract android.support.v17.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
method protected void dispatchItemSelectedListener(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
method public void freeze(android.support.v17.leanback.widget.RowPresenter.ViewHolder, boolean);
@@ -1387,6 +1643,7 @@
ctor public SearchBar(android.content.Context, android.util.AttributeSet);
ctor public SearchBar(android.content.Context, android.util.AttributeSet, int);
method public void displayCompletions(java.util.List<java.lang.String>);
+ method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
method public android.graphics.drawable.Drawable getBadgeDrawable();
method public java.lang.CharSequence getHint();
method public java.lang.String getTitle();
@@ -1443,15 +1700,14 @@
field public int iconColor;
}
- public class ShadowOverlayContainer extends android.view.ViewGroup {
+ public class ShadowOverlayContainer extends android.widget.FrameLayout {
ctor public ShadowOverlayContainer(android.content.Context);
ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet);
ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet, int);
method public int getShadowType();
method public android.view.View getWrappedView();
method public deprecated void initialize(boolean, boolean);
- method public void initialize(boolean, boolean, boolean);
- method protected void onLayout(boolean, int, int, int, int);
+ method public deprecated void initialize(boolean, boolean, boolean);
method public static void prepareParentForShadow(android.view.ViewGroup);
method public void setOverlayColor(int);
method public void setShadowFocusLevel(float);
@@ -1466,6 +1722,48 @@
field public static final int SHADOW_STATIC = 2; // 0x2
}
+ public final class ShadowOverlayHelper {
+ method public android.support.v17.leanback.widget.ShadowOverlayContainer createShadowOverlayContainer(android.content.Context);
+ method public int getShadowType();
+ method public boolean needsOverlay();
+ method public boolean needsRoundedCorner();
+ method public boolean needsWrapper();
+ method public void onViewCreated(android.view.View);
+ method public void prepareParentForShadow(android.view.ViewGroup);
+ method public static void setNoneWrapperOverlayColor(android.view.View, int);
+ method public static void setNoneWrapperShadowFocusLevel(android.view.View, float);
+ method public void setOverlayColor(android.view.View, int);
+ method public void setShadowFocusLevel(android.view.View, float);
+ method public static boolean supportsDynamicShadow();
+ method public static boolean supportsForeground();
+ method public static boolean supportsRoundedCorner();
+ method public static boolean supportsShadow();
+ field public static final int SHADOW_DYNAMIC = 3; // 0x3
+ field public static final int SHADOW_NONE = 1; // 0x1
+ field public static final int SHADOW_STATIC = 2; // 0x2
+ }
+
+ public static final class ShadowOverlayHelper.Builder {
+ ctor public ShadowOverlayHelper.Builder();
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper build(android.content.Context);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder keepForegroundDrawable(boolean);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsOverlay(boolean);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsRoundedCorner(boolean);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder needsShadow(boolean);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder options(android.support.v17.leanback.widget.ShadowOverlayHelper.Options);
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Builder preferZOrder(boolean);
+ }
+
+ public static final class ShadowOverlayHelper.Options {
+ ctor public ShadowOverlayHelper.Options();
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options dynamicShadowZ(float, float);
+ method public final float getDynamicShadowFocusedZ();
+ method public final float getDynamicShadowUnfocusedZ();
+ method public final int getRoundedCornerRadius();
+ method public android.support.v17.leanback.widget.ShadowOverlayHelper.Options roundedCornerRadius(int);
+ field public static final android.support.v17.leanback.widget.ShadowOverlayHelper.Options DEFAULT;
+ }
+
public final class SinglePresenterSelector extends android.support.v17.leanback.widget.PresenterSelector {
ctor public SinglePresenterSelector(android.support.v17.leanback.widget.Presenter);
method public android.support.v17.leanback.widget.Presenter getPresenter(java.lang.Object);
@@ -1538,8 +1836,10 @@
ctor public VerticalGridPresenter(int, boolean);
method public final boolean areChildRoundedCornersEnabled();
method protected android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder createGridViewHolder(android.view.ViewGroup);
+ method protected android.support.v17.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
method public final void enableChildRoundedCorners(boolean);
method public final int getFocusZoomFactor();
+ method public final boolean getKeepChildForeground();
method public int getNumberOfColumns();
method public final android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
method public final android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
@@ -1551,6 +1851,8 @@
method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
method public final android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
method public void onUnbindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder);
+ method public void setEntranceTransitionState(android.support.v17.leanback.widget.VerticalGridPresenter.ViewHolder, boolean);
+ method public final void setKeepChildForeground(boolean);
method public void setNumberOfColumns(int);
method public final void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
method public final void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java b/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
new file mode 100644
index 0000000..1762c15
--- /dev/null
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.TimeInterpolator;
+import android.transition.Fade;
+import android.transition.Transition;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+
+/**
+ * Execute horizontal slide of 1/4 width and fade (to workaround bug 23718734)
+ * @hide
+ */
+public class FadeAndShortSlide extends Visibility {
+
+ private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
+ // private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
+ private static final String PROPNAME_SCREEN_POSITION =
+ "android:fadeAndShortSlideTransition:screenPosition";
+
+ private CalculateSlide mSlideCalculator = sCalculateEnd;
+ private Visibility mFade = new Fade();
+
+ private interface CalculateSlide {
+
+ /** Returns the translation value for view when it goes out of the scene */
+ float getGoneX(ViewGroup sceneRoot, View view, int[] position);
+ }
+
+ private static final CalculateSlide sCalculateStart = new CalculateSlide() {
+ @Override
+ public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+ final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ final float x;
+ if (isRtl) {
+ x = view.getTranslationX() + sceneRoot.getWidth() / 4;
+ } else {
+ x = view.getTranslationX() - sceneRoot.getWidth() / 4;
+ }
+ return x;
+ }
+ };
+
+ private static final CalculateSlide sCalculateEnd = new CalculateSlide() {
+ @Override
+ public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+ final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ final float x;
+ if (isRtl) {
+ x = view.getTranslationX() - sceneRoot.getWidth() / 4;
+ } else {
+ x = view.getTranslationX() + sceneRoot.getWidth() / 4;
+ }
+ return x;
+ }
+ };
+
+ private static final CalculateSlide sCalculateBoth = new CalculateSlide() {
+
+ @Override
+ public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+ final int viewCenter = position[0] + view.getWidth() / 2;
+ sceneRoot.getLocationOnScreen(position);
+ final int sceneRootCenter = position[0] + sceneRoot.getWidth() / 2;
+ if (viewCenter < sceneRootCenter) {
+ return view.getTranslationX() - sceneRoot.getWidth() / 2;
+ } else {
+ return view.getTranslationX() + sceneRoot.getWidth() / 2;
+ }
+ }
+ };
+
+ public FadeAndShortSlide() {
+ this(Gravity.START);
+ }
+
+ public FadeAndShortSlide(int slideEdge) {
+ setSlideEdge(slideEdge);
+ }
+
+ @Override
+ public void setEpicenterCallback(EpicenterCallback epicenterCallback) {
+ super.setEpicenterCallback(epicenterCallback);
+ mFade.setEpicenterCallback(epicenterCallback);
+ }
+
+ private void captureValues(TransitionValues transitionValues) {
+ View view = transitionValues.view;
+ int[] position = new int[2];
+ view.getLocationOnScreen(position);
+ transitionValues.values.put(PROPNAME_SCREEN_POSITION, position);
+ }
+
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ super.captureStartValues(transitionValues);
+ mFade.captureStartValues(transitionValues);
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ super.captureEndValues(transitionValues);
+ mFade.captureEndValues(transitionValues);
+ captureValues(transitionValues);
+ }
+
+ public void setSlideEdge(int slideEdge) {
+ switch (slideEdge) {
+ case Gravity.START:
+ mSlideCalculator = sCalculateStart;
+ break;
+ case Gravity.END:
+ mSlideCalculator = sCalculateEnd;
+ break;
+ case Gravity.START | Gravity.END:
+ mSlideCalculator = sCalculateBoth;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid slide direction");
+ }
+ // SidePropagation propagation = new SidePropagation();
+ // propagation.setSide(slideEdge);
+ // setPropagation(propagation);
+ }
+
+ @Override
+ public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (endValues == null) {
+ return null;
+ }
+ if (sceneRoot == view) {
+ // workaround b/25375640, avoid run animation on sceneRoot
+ return null;
+ }
+ int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
+ int left = position[0];
+ float endX = view.getTranslationX();
+ float startX = mSlideCalculator.getGoneX(sceneRoot, view, position);
+ final Animator slideAnimator = TranslationAnimationCreator.createAnimation(view, endValues,
+ left, startX, endX, sDecelerate, this);
+ final AnimatorSet set = new AnimatorSet();
+ set.play(slideAnimator).with(mFade.onAppear(sceneRoot, view, startValues, endValues));
+
+ return set;
+ }
+
+ @Override
+ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null) {
+ return null;
+ }
+ if (sceneRoot == view) {
+ // workaround b/25375640, avoid run animation on sceneRoot
+ return null;
+ }
+ int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
+ int left = position[0];
+ float startX = view.getTranslationX();
+ float endX = mSlideCalculator.getGoneX(sceneRoot, view, position);
+ final Animator slideAnimator = TranslationAnimationCreator.createAnimation(view,
+ startValues, left, startX, endX, sDecelerate /* sAccelerate */, this);
+ final AnimatorSet set = new AnimatorSet();
+ set.play(slideAnimator).with(mFade.onDisappear(sceneRoot, view, startValues, endValues));
+
+ return set;
+ }
+
+ @Override
+ public Transition addListener(TransitionListener listener) {
+ mFade.addListener(listener);
+ return super.addListener(listener);
+ }
+
+ @Override
+ public Transition removeListener(TransitionListener listener) {
+ mFade.removeListener(listener);
+ return super.removeListener(listener);
+ }
+
+ @Override
+ public Transition clone() {
+ FadeAndShortSlide clone = null;
+ clone = (FadeAndShortSlide) super.clone();
+ clone.mFade = (Visibility) mFade.clone();
+ return clone;
+ }
+}
+
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
index 00ebf4c..c5a33cb 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
@@ -14,8 +14,12 @@
package android.support.v17.leanback.transition;
import android.R;
+import android.app.Fragment;
import android.content.Context;
import android.transition.ChangeTransform;
+import android.transition.Transition;
+import android.view.View;
+import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.AnimationUtils;
@@ -24,6 +28,24 @@
TransitionHelperApi21() {
}
+ public static void setEnterTransition(android.app.Fragment fragment, Object transition) {
+ fragment.setEnterTransition((Transition)transition);
+ }
+
+ public static void setExitTransition(android.app.Fragment fragment, Object transition) {
+ fragment.setExitTransition((Transition)transition);
+ }
+
+ public static void setSharedElementEnterTransition(android.app.Fragment fragment,
+ Object transition) {
+ fragment.setSharedElementEnterTransition((Transition)transition);
+ }
+
+ public static void addSharedElement(android.app.FragmentTransaction ft,
+ View view, String transitionName) {
+ ft.addSharedElement(view, transitionName);
+ }
+
public static Object getSharedElementEnterTransition(Window window) {
return window.getSharedElementEnterTransition();
}
@@ -63,4 +85,12 @@
public static Object createDefaultInterpolator(Context context) {
return AnimationUtils.loadInterpolator(context, R.interpolator.fast_out_linear_in);
}
+
+ public static Object createFadeAndShortSlide(int edge) {
+ return new FadeAndShortSlide(edge);
+ }
+
+ public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
+ viewGroup.setTransitionGroup(transitionGroup);
+ }
}
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java b/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
new file mode 100644
index 0000000..2cc35452
--- /dev/null
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
@@ -0,0 +1,128 @@
+package android.support.v17.leanback.transition;
+
+import android.support.v17.leanback.R;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.graphics.Path;
+import android.transition.Transition;
+import android.transition.TransitionValues;
+import android.view.View;
+
+/**
+ * This class is used by Slide and Explode to create an animator that goes from the start position
+ * to the end position. It takes into account the canceled position so that it will not blink out or
+ * shift suddenly when the transition is interrupted.
+ * @hide
+ */
+class TranslationAnimationCreator {
+
+ /**
+ * Creates an animator that can be used for x and/or y translations. When interrupted, it sets a
+ * tag to keep track of the position so that it may be continued from position.
+ *
+ * @param view The view being moved. This may be in the overlay for onDisappear.
+ * @param values The values containing the view in the view hierarchy.
+ * @param viewPosX The x screen coordinate of view
+ * @param startX The start translation x of view
+ * @param endX The end translation x of view
+ * @param interpolator The interpolator to use with this animator.
+ * @return An animator that moves from (startX, startY) to (endX, endY) unless there was a
+ * previous interruption, in which case it moves from the current position to (endX,
+ * endY).
+ */
+ static Animator createAnimation(View view, TransitionValues values, int viewPosX, float startX,
+ float endX, TimeInterpolator interpolator, Transition transition) {
+ float terminalX = view.getTranslationX();
+ Integer startPosition = (Integer) values.view.getTag(R.id.transitionPosition);
+ if (startPosition != null) {
+ startX = startPosition - viewPosX + terminalX;
+ }
+ // Initial position is at translation startX, startY, so position is offset by that
+ // amount
+ int startPosX = viewPosX + Math.round(startX - terminalX);
+
+ view.setTranslationX(startX);
+ if (startX == endX) {
+ return null;
+ }
+ float y = view.getTranslationY();
+ Path path = new Path();
+ path.moveTo(startX, y);
+ path.lineTo(endX, y);
+ ObjectAnimator anim =
+ ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y, path);
+
+ TransitionPositionListener listener =
+ new TransitionPositionListener(view, values.view, startPosX, terminalX);
+ transition.addListener(listener);
+ anim.addListener(listener);
+ anim.addPauseListener(listener);
+ anim.setInterpolator(interpolator);
+ return anim;
+ }
+
+ private static class TransitionPositionListener extends AnimatorListenerAdapter
+ implements Transition.TransitionListener {
+
+ private final View mViewInHierarchy;
+ private final View mMovingView;
+ private final int mStartX;
+ private Integer mTransitionPosition;
+ private float mPausedX;
+ private final float mTerminalX;
+
+ private TransitionPositionListener(View movingView, View viewInHierarchy, int startX,
+ float terminalX) {
+ mMovingView = movingView;
+ mViewInHierarchy = viewInHierarchy;
+ mStartX = startX - Math.round(mMovingView.getTranslationX());
+ mTerminalX = terminalX;
+ mTransitionPosition = (Integer) mViewInHierarchy.getTag(R.id.transitionPosition);
+ if (mTransitionPosition != null) {
+ mViewInHierarchy.setTag(R.id.transitionPosition, null);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mTransitionPosition = Math.round(mStartX + mMovingView.getTranslationX());
+ mViewInHierarchy.setTag(R.id.transitionPosition, mTransitionPosition);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {}
+
+ @Override
+ public void onAnimationPause(Animator animator) {
+ mPausedX = mMovingView.getTranslationX();
+ mMovingView.setTranslationX(mTerminalX);
+ }
+
+ @Override
+ public void onAnimationResume(Animator animator) {
+ mMovingView.setTranslationX(mPausedX);
+ }
+
+ @Override
+ public void onTransitionStart(Transition transition) {}
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ mMovingView.setTranslationX(mTerminalX);
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {}
+
+ @Override
+ public void onTransitionPause(Transition transition) {}
+
+ @Override
+ public void onTransitionResume(Transition transition) {}
+ }
+
+}
+
diff --git a/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
index c7fa0f3..a013ba1 100644
--- a/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/widget/RoundedRectHelperApi21.java
@@ -13,31 +13,47 @@
*/
package android.support.v17.leanback.widget;
-import android.support.v17.leanback.R;
-import android.graphics.Color;
+import android.util.SparseArray;
import android.graphics.Outline;
-import android.graphics.drawable.GradientDrawable;
import android.view.ViewOutlineProvider;
import android.view.View;
class RoundedRectHelperApi21 {
- private static int sCornerRadius;
+ private static SparseArray<ViewOutlineProvider> sRoundedRectProvider;
+ private static final int MAX_CACHED_PROVIDER = 32;
- private static final ViewOutlineProvider sOutlineProvider = new ViewOutlineProvider() {
+ static final class RoundedRectOutlineProvider extends ViewOutlineProvider {
+
+ private int mRadius;
+
+ RoundedRectOutlineProvider(int radius) {
+ mRadius = radius;
+ }
+
@Override
public void getOutline(View view, Outline outline) {
- if (sCornerRadius == 0) {
- sCornerRadius = view.getResources().getDimensionPixelSize(
- R.dimen.lb_rounded_rect_corner_radius);
- }
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), sCornerRadius);
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mRadius);
outline.setAlpha(1f);
}
};
- public static void setClipToRoundedOutline(View view, boolean clip) {
- view.setOutlineProvider(clip ? sOutlineProvider : ViewOutlineProvider.BACKGROUND);
+ public static void setClipToRoundedOutline(View view, boolean clip, int roundedCornerRadius) {
+ if (clip) {
+ if (sRoundedRectProvider == null) {
+ sRoundedRectProvider = new SparseArray<ViewOutlineProvider>();
+ }
+ ViewOutlineProvider provider = sRoundedRectProvider.get(roundedCornerRadius);
+ if (provider == null) {
+ provider = new RoundedRectOutlineProvider(roundedCornerRadius);
+ if (sRoundedRectProvider.size() < MAX_CACHED_PROVIDER) {
+ sRoundedRectProvider.put(roundedCornerRadius, provider);
+ }
+ }
+ view.setOutlineProvider(provider);
+ } else {
+ view.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
+ }
view.setClipToOutline(clip);
}
}
diff --git a/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
index ab4d179..66f7687 100644
--- a/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/widget/ShadowHelperApi21.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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
@@ -13,20 +13,15 @@
*/
package android.support.v17.leanback.widget;
-import android.support.v17.leanback.R;
-import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.Outline;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.view.ViewGroup;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
class ShadowHelperApi21 {
static class ShadowImpl {
- ViewGroup mShadowContainer;
+ View mShadowContainer;
float mNormalZ;
float mFocusedZ;
}
@@ -41,9 +36,10 @@
/* add shadows and return a implementation detail object */
public static Object addDynamicShadow(
- ViewGroup shadowContainer, float unfocusedZ, float focusedZ, boolean roundedCorners) {
- if (roundedCorners) {
- RoundedRectHelperApi21.setClipToRoundedOutline(shadowContainer, true);
+ View shadowContainer, float unfocusedZ, float focusedZ, int roundedCornerRadius) {
+ if (roundedCornerRadius > 0) {
+ RoundedRectHelperApi21.setClipToRoundedOutline(shadowContainer, true,
+ roundedCornerRadius);
} else {
shadowContainer.setOutlineProvider(sOutlineProvider);
}
@@ -52,7 +48,6 @@
impl.mNormalZ = unfocusedZ;
impl.mFocusedZ = focusedZ;
shadowContainer.setZ(impl.mNormalZ);
- shadowContainer.setTransitionGroup(true);
return impl;
}
diff --git a/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java b/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java
new file mode 100644
index 0000000..c4760d4
--- /dev/null
+++ b/v17/leanback/api23/android/support/v17/leanback/widget/ForegroundHelperApi23.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import android.support.v17.leanback.R;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.ViewGroup;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+class ForegroundHelperApi23 {
+
+ public static Drawable getForeground(View view) {
+ return view.getForeground();
+ }
+
+ public static void setForeground(View view, Drawable drawable) {
+ view.setForeground(drawable);
+ }
+}
diff --git a/v17/leanback/build.gradle b/v17/leanback/build.gradle
index 8dc79e8..401a5c4 100644
--- a/v17/leanback/build.gradle
+++ b/v17/leanback/build.gradle
@@ -19,8 +19,8 @@
sourceSets {
main.manifest.srcFile 'AndroidManifest.xml'
- main.java.srcDirs = ['common', 'jbmr2', 'kitkat', 'api21', 'src']
- main.aidl.srcDirs = ['common', 'jbmr2', 'kitkat', 'api21', 'src']
+ main.java.srcDirs = ['common', 'jbmr2', 'kitkat', 'api21', 'api23', 'src']
+ main.aidl.srcDirs = ['common', 'jbmr2', 'kitkat', 'api21', 'api23', 'src']
main.res.srcDirs = ['res']
androidTest.setRoot('tests')
diff --git a/v17/leanback/common/android/support/v17/leanback/transition/TransitionListener.java b/v17/leanback/common/android/support/v17/leanback/transition/TransitionListener.java
index 80f05ed..6a4056e 100644
--- a/v17/leanback/common/android/support/v17/leanback/transition/TransitionListener.java
+++ b/v17/leanback/common/android/support/v17/leanback/transition/TransitionListener.java
@@ -19,10 +19,20 @@
*/
public class TransitionListener {
+ protected Object mImpl;
+
public void onTransitionStart(Object transition) {
}
public void onTransitionEnd(Object transition) {
}
+ public void onTransitionCancel(Object transition) {
+ }
+
+ public void onTransitionPause(Object transition) {
+ }
+
+ public void onTransitionResume(Object transition) {
+ }
}
diff --git a/v17/leanback/generatev4.py b/v17/leanback/generatev4.py
index 605e9a1..1b60b09e 100755
--- a/v17/leanback/generatev4.py
+++ b/v17/leanback/generatev4.py
@@ -20,7 +20,7 @@
print "Generate v4 fragment related code for leanback"
cls = ['Background', 'Base', 'BaseRow', 'Browse', 'Details', 'Error', 'Headers',
- 'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded']
+ 'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded', 'GuidedStep']
for w in cls:
print "copy {}Fragment to {}SupportFragment".format(w, w)
@@ -31,10 +31,24 @@
outfile.write("/* This file is auto-generated from {}Fragment.java. DO NOT MODIFY. */\n\n".format(w))
for line in file:
+ line = line.replace('IS_FRAMEWORK_FRAGMENT = true', 'IS_FRAMEWORK_FRAGMENT = false');
for w in cls:
line = line.replace('{}Fragment'.format(w), '{}SupportFragment'.format(w))
line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+ line = line.replace('activity.getFragmentManager()', 'activity.getSupportFragmentManager()')
+ line = line.replace('Activity activity', 'FragmentActivity activity')
+ line = line.replace('(Activity', '(FragmentActivity')
outfile.write(line)
file.close()
outfile.close()
+
+file = open('src/android/support/v17/leanback/app/PlaybackControlGlue.java', 'r')
+outfile = open('src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java', 'w')
+outfile.write("/* This file is auto-generated from PlaybackControlGlue.java. DO NOT MODIFY. */\n\n")
+for line in file:
+ line = line.replace('PlaybackControlGlue', 'PlaybackControlSupportGlue');
+ line = line.replace('PlaybackOverlayFragment', 'PlaybackOverlaySupportFragment');
+ outfile.write(line)
+file.close()
+outfile.close()
diff --git a/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java b/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
index b4b6abe..221b84a 100644
--- a/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
+++ b/v17/leanback/kitkat/android/support/v17/leanback/transition/TransitionHelperKitkat.java
@@ -185,9 +185,12 @@
((Transition) transition).addTarget(targetView);
}
- static void setTransitionListener(Object transition, final TransitionListener listener) {
+ static void addTransitionListener(Object transition, final TransitionListener listener) {
+ if (listener == null) {
+ return;
+ }
Transition t = (Transition) transition;
- t.addListener(new Transition.TransitionListener() {
+ listener.mImpl = new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
@@ -196,10 +199,12 @@
@Override
public void onTransitionResume(Transition transition) {
+ listener.onTransitionResume(transition);
}
@Override
public void onTransitionPause(Transition transition) {
+ listener.onTransitionPause(transition);
}
@Override
@@ -209,8 +214,19 @@
@Override
public void onTransitionCancel(Transition transition) {
+ listener.onTransitionCancel(transition);
}
- });
+ };
+ t.addListener((Transition.TransitionListener) listener.mImpl);
+ }
+
+ static void removeTransitionListener(Object transition, final TransitionListener listener) {
+ if (listener == null || listener.mImpl == null) {
+ return;
+ }
+ Transition t = (Transition) transition;
+ t.removeListener((Transition.TransitionListener) listener.mImpl);
+ listener.mImpl = null;
}
static void runTransition(Object scene, Object transition) {
diff --git a/v17/leanback/project.properties b/v17/leanback/project.properties
index 91d2b02..b2ef7dc 100644
--- a/v17/leanback/project.properties
+++ b/v17/leanback/project.properties
@@ -11,5 +11,5 @@
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
-target=android-19
+target=android-23
android.library=true
diff --git a/v17/leanback/res/animator/lb_guidance_entry.xml b/v17/leanback/res/animator/lb_guidance_entry.xml
deleted file mode 100644
index e10d2ef..0000000
--- a/v17/leanback/res/animator/lb_guidance_entry.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="sequentially">
-
- <set android:ordering="together">
- <objectAnimator
- android:duration="@integer/lb_guidedstep_entry_animation_delay"
- android:propertyName="translationX"
- android:valueFrom="@dimen/lb_guidance_entry_translationX"
- android:valueTo="@dimen/lb_guidance_entry_translationX"
- android:valueType="floatType" />
-
- <objectAnimator
- android:duration="@integer/lb_guidedstep_entry_animation_delay"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="0.0"
- android:valueType="floatType" />
- </set>
-
- <set android:ordering="together">
- <objectAnimator
- android:duration="@integer/lb_guidedstep_entry_animation_duration"
- android:interpolator="@android:interpolator/decelerate_quad"
- android:propertyName="translationX"
- android:valueFrom="@dimen/lb_guidance_entry_translationX"
- android:valueTo="0.0"
- android:valueType="floatType" />
-
- <objectAnimator
- android:duration="@integer/lb_guidedstep_entry_animation_duration"
- android:interpolator="@android:interpolator/decelerate_quad"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType" />
- </set>
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedactions_entry.xml b/v17/leanback/res/animator/lb_guidedactions_entry.xml
deleted file mode 100644
index ec6c655..0000000
--- a/v17/leanback/res/animator/lb_guidedactions_entry.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="sequentially">
-
- <set android:ordering="together">
- <objectAnimator
- android:duration="@integer/lb_guidedstep_entry_animation_delay"
- android:propertyName="translationX"
- android:valueFrom="@dimen/lb_guidedactions_entry_translationX"
- android:valueTo="@dimen/lb_guidedactions_entry_translationX"
- android:valueType="floatType" />
-
- <objectAnimator
- android:duration="@integer/lb_guidedstep_entry_animation_delay"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="0.0"
- android:valueType="floatType" />
- </set>
-
- <set android:ordering="together">
- <objectAnimator
- android:duration="@integer/lb_guidedstep_entry_animation_duration"
- android:interpolator="@android:interpolator/decelerate_quad"
- android:propertyName="translationX"
- android:valueFrom="@dimen/lb_guidedactions_entry_translationX"
- android:valueTo="0.0"
- android:valueType="floatType" />
-
- <objectAnimator
- android:duration="@integer/lb_guidedstep_entry_animation_duration"
- android:interpolator="@android:interpolator/decelerate_quad"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType" />
- </set>
-</set>
\ No newline at end of file
diff --git a/v17/leanback/res/animator/lb_guidedactions_selector_hide.xml b/v17/leanback/res/animator/lb_guidedactions_selector_hide.xml
index f829eb3..e5dafb0 100644
--- a/v17/leanback/res/animator/lb_guidedactions_selector_hide.xml
+++ b/v17/leanback/res/animator/lb_guidedactions_selector_hide.xml
@@ -17,7 +17,6 @@
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/lb_guidedactions_animation_duration"
android:propertyName="alpha"
- android:valueFrom="1.0"
android:valueTo="0.0"
android:interpolator="@animator/lb_decelerator_2"
android:valueType="floatType" />
diff --git a/v17/leanback/res/animator/lb_guidedactions_selector_show.xml b/v17/leanback/res/animator/lb_guidedactions_selector_show.xml
index e8d69e5..fcfd9fa 100644
--- a/v17/leanback/res/animator/lb_guidedactions_selector_show.xml
+++ b/v17/leanback/res/animator/lb_guidedactions_selector_show.xml
@@ -20,7 +20,6 @@
<objectAnimator
android:duration="@integer/lb_guidedactions_animation_duration"
android:propertyName="alpha"
- android:valueFrom="0"
android:valueTo="1.0"
android:interpolator="@animator/lb_decelerator_2"
android:valueType="floatType" />
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml b/v17/leanback/res/animator/lb_guidedstep_slide_down.xml
similarity index 82%
rename from v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml
rename to v17/leanback/res/animator/lb_guidedstep_slide_down.xml
index 86525c8..b31421f 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml
+++ b/v17/leanback/res/animator/lb_guidedstep_slide_down.xml
@@ -15,8 +15,8 @@
limitations under the License.
-->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="@integer/lb_guidedactions_item_animation_duration"
- android:propertyName="alpha"
- android:valueFrom="1.0"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:propertyName="translationY"
+ android:valueFrom="@dimen/lb_guidedstep_slide_ime_distance"
android:valueTo="0.0"
android:valueType="floatType" />
diff --git a/v17/leanback/res/animator/lb_guidedstep_slide_in_from_end.xml b/v17/leanback/res/animator/lb_guidedstep_slide_in_from_end.xml
deleted file mode 100644
index 1dacdbc..0000000
--- a/v17/leanback/res/animator/lb_guidedstep_slide_in_from_end.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
-
- <objectAnimator
- android:duration="@android:integer/config_longAnimTime"
- android:propertyName="translationX"
- android:valueFrom="@dimen/lb_guidedstep_slide_end_distance"
- android:valueTo="0.0"
- android:valueType="floatType" />
-
- <objectAnimator
- android:duration="@android:integer/config_longAnimTime"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType" />
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedstep_slide_in_from_start.xml b/v17/leanback/res/animator/lb_guidedstep_slide_in_from_start.xml
deleted file mode 100644
index 3c01324..0000000
--- a/v17/leanback/res/animator/lb_guidedstep_slide_in_from_start.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
-
- <objectAnimator
- android:duration="@android:integer/config_longAnimTime"
- android:propertyName="translationX"
- android:valueFrom="@dimen/lb_guidedstep_slide_start_distance"
- android:valueTo="0.0"
- android:valueType="floatType" />
-
- <objectAnimator
- android:duration="@android:integer/config_longAnimTime"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType" />
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedstep_slide_out_to_end.xml b/v17/leanback/res/animator/lb_guidedstep_slide_out_to_end.xml
deleted file mode 100644
index 879a0cf..0000000
--- a/v17/leanback/res/animator/lb_guidedstep_slide_out_to_end.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
-
- <objectAnimator
- android:duration="@android:integer/config_longAnimTime"
- android:propertyName="translationX"
- android:valueFrom="0.0"
- android:valueTo="@dimen/lb_guidedstep_slide_end_distance"
- android:valueType="floatType" />
-
- <objectAnimator
- android:duration="@android:integer/config_longAnimTime"
- android:propertyName="alpha"
- android:valueFrom="1.0"
- android:valueTo="0.0"
- android:valueType="floatType" />
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedstep_slide_out_to_start.xml b/v17/leanback/res/animator/lb_guidedstep_slide_out_to_start.xml
deleted file mode 100644
index 4c9af82..0000000
--- a/v17/leanback/res/animator/lb_guidedstep_slide_out_to_start.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
-
- <objectAnimator
- android:duration="@android:integer/config_longAnimTime"
- android:propertyName="translationX"
- android:valueFrom="0.0"
- android:valueTo="@dimen/lb_guidedstep_slide_start_distance"
- android:valueType="floatType" />
-
- <objectAnimator
- android:duration="@android:integer/config_longAnimTime"
- android:propertyName="alpha"
- android:valueFrom="1.0"
- android:valueTo="0.0"
- android:valueType="floatType" />
-
-</set>
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml b/v17/leanback/res/animator/lb_guidedstep_slide_up.xml
similarity index 83%
rename from v17/leanback/res/animator/lb_guidedactions_item_checked.xml
rename to v17/leanback/res/animator/lb_guidedstep_slide_up.xml
index 463b9f7..165fe18 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml
+++ b/v17/leanback/res/animator/lb_guidedstep_slide_up.xml
@@ -15,8 +15,8 @@
limitations under the License.
-->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="@integer/lb_guidedactions_item_animation_duration"
- android:propertyName="alpha"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:propertyName="translationY"
android:valueFrom="0.0"
- android:valueTo="1.0"
+ android:valueTo="@dimen/lb_guidedstep_slide_ime_distance"
android:valueType="floatType" />
diff --git a/v17/leanback/res/drawable/lb_headers_right_fading.xml b/v17/leanback/res/drawable/lb_headers_right_fading.xml
index 96794db..b20c4e8 100644
--- a/v17/leanback/res/drawable/lb_headers_right_fading.xml
+++ b/v17/leanback/res/drawable/lb_headers_right_fading.xml
@@ -20,6 +20,6 @@
<gradient
android:angle="0"
android:startColor="#00000000"
- android:endColor="@color/lb_default_brand_color"
+ android:endColor="?attr/defaultBrandColor"
/>
</shape>
diff --git a/v17/leanback/res/layout/lb_fullwidth_details_overview.xml b/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
index 8dbb630..415bd82 100644
--- a/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
+++ b/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
@@ -34,7 +34,7 @@
android:layout_height="@dimen/lb_details_v2_card_height"
android:layout_marginTop="@dimen/lb_details_v2_blank_height"
android:clipToPadding="false"
- android:foreground="#ffffff"
+ android:background="?attr/defaultBrandColor"
android:elevation="@dimen/lb_details_overview_z"
>
@@ -48,6 +48,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/details_overview_actions_background"
+ android:background="?attr/defaultBrandColorDark"
android:orientation="vertical" >
<android.support.v17.leanback.widget.HorizontalGridView
diff --git a/v17/leanback/res/layout/lb_guidedactions.xml b/v17/leanback/res/layout/lb_guidedactions.xml
index 43617c9..f2926d3 100644
--- a/v17/leanback/res/layout/lb_guidedactions.xml
+++ b/v17/leanback/res/layout/lb_guidedactions.xml
@@ -16,20 +16,36 @@
-->
<!-- Layout for the settings list fragment -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:id="@+id/guidedactions_root"
+ android:transitionName="guidedactions_root"
+ android:transitionGroup="false"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent">
- <RelativeLayout
- style="?attr/guidedActionsContainerStyle" >
+ <android.support.v17.leanback.widget.NonOverlappingView
+ android:id="@+id/guidedactions_list_background"
+ android:transitionName="guidedactions_list_background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:background="?attr/guidedActionsBackgroundDark" />
- <FrameLayout
- android:id="@+id/guidedactions_selector"
- style="?attr/guidedActionsSelectorStyle" />
-
+ <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+ android:id="@+id/guidedactions_content"
+ android:transitionName="guidedactions_content"
+ android:transitionGroup="false"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<android.support.v17.leanback.widget.VerticalGridView
+ android:transitionGroup="true"
android:id="@+id/guidedactions_list"
style="?attr/guidedActionsListStyle" />
- </RelativeLayout>
+ <android.support.v17.leanback.widget.NonOverlappingView
+ android:id="@+id/guidedactions_selector"
+ android:transitionName="guidedactions_selector"
+ style="?attr/guidedActionsSelectorStyle" />
+ </android.support.v17.leanback.widget.NonOverlappingFrameLayout>
</RelativeLayout>
diff --git a/v17/leanback/res/layout/lb_guidedactions_item.xml b/v17/leanback/res/layout/lb_guidedactions_item.xml
index 4e41454..831c355 100644
--- a/v17/leanback/res/layout/lb_guidedactions_item.xml
+++ b/v17/leanback/res/layout/lb_guidedactions_item.xml
@@ -20,7 +20,7 @@
xmlns:tools="http://schemas.android.com/tools"
style="?attr/guidedActionItemContainerStyle" >
- <ImageView
+ <android.support.v17.leanback.widget.CheckableImageView
android:id="@+id/guidedactions_item_checkmark"
style="?attr/guidedActionItemCheckmarkStyle"
tools:ignore="ContentDescription" />
@@ -34,13 +34,14 @@
android:id="@+id/guidedactions_item_content"
style="?attr/guidedActionItemContentStyle" >
- <TextView
+ <android.support.v17.leanback.widget.GuidedActionEditText
android:id="@+id/guidedactions_item_title"
style="?attr/guidedActionItemTitleStyle" />
- <TextView
+ <android.support.v17.leanback.widget.GuidedActionEditText
android:id="@+id/guidedactions_item_description"
style="?attr/guidedActionItemDescriptionStyle" />
+
</android.support.v17.leanback.widget.NonOverlappingLinearLayout>
<ImageView
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml b/v17/leanback/res/layout/lb_guidedstep_background.xml
similarity index 65%
copy from v17/leanback/res/animator/lb_guidedactions_item_checked.xml
copy to v17/leanback/res/layout/lb_guidedstep_background.xml
index 463b9f7..08ea47d 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml
+++ b/v17/leanback/res/layout/lb_guidedstep_background.xml
@@ -14,9 +14,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="@integer/lb_guidedactions_item_animation_duration"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType" />
+<android.support.v17.leanback.widget.NonOverlappingView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/guidedstep_background"
+ android:transitionName="guidedstep_background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/guidedStepBackground" />
+
diff --git a/v17/leanback/res/layout/lb_guidedstep_fragment.xml b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
index 6e0b7ad..a41d47d 100644
--- a/v17/leanback/res/layout/lb_guidedstep_fragment.xml
+++ b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
@@ -15,21 +15,57 @@
limitations under the License.
-->
<!-- Layout for the frame of a 2 pane actions fragment. -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content_frame"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/guidedstep_root"
+ android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
+ <LinearLayout
+ android:id="@+id/content_frame"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
- <FrameLayout
- android:id="@+id/content_fragment"
- android:layout_width="@dimen/lb_guidedstep_guidance_section_width"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true" />
+ <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+ android:id="@+id/content_fragment"
+ android:layout_toStartOf="@+id/action_fragment"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true" />
- <FrameLayout
- android:id="@+id/action_fragment"
- android:layout_width="@dimen/lb_guidedactions_section_width_with_shadow"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true" />
+ <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+ android:id="@+id/action_fragment_root"
+ android:transitionName="action_fragment_root"
+ android:transitionGroup="false"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ android:paddingStart="@dimen/lb_guidedactions_section_shadow_width"
+ android:layout_width="0dp"
+ android:layout_weight="?attr/guidedActionContentWidthWeight"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true">
-</RelativeLayout>
\ No newline at end of file
+ <android.support.v17.leanback.widget.NonOverlappingView
+ android:id="@+id/action_fragment_background"
+ android:transitionName="action_fragment_background"
+ android:orientation="horizontal"
+ android:outlineProvider="paddedBounds"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/guidedActionsBackground"
+ android:elevation="?attr/guidedActionsElevation" />
+
+ <android.support.v17.leanback.widget.NonOverlappingLinearLayout
+ android:id="@+id/action_fragment"
+ android:transitionName="action_fragment"
+ android:transitionGroup="false"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:elevation="?attr/guidedActionsElevation" />
+ </android.support.v17.leanback.widget.NonOverlappingFrameLayout>
+
+ </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_image_card_view.xml b/v17/leanback/res/layout/lb_image_card_view.xml
index 2261965..1bc23f8 100644
--- a/v17/leanback/res/layout/lb_image_card_view.xml
+++ b/v17/leanback/res/layout/lb_image_card_view.xml
@@ -15,59 +15,16 @@
limitations under the License.
-->
-<merge
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:lb="http://schemas.android.com/apk/res-auto">
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:lb="http://schemas.android.com/apk/res-auto" >
<ImageView
android:id="@+id/main_image"
- lb:layout_viewType="main"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scaleType="centerCrop"
- android:adjustViewBounds="true"
- android:contentDescription="@null" />
- <android.support.v17.leanback.widget.NonOverlappingRelativeLayout
- lb:layout_viewType="info"
- android:id="@+id/info_field"
- android:layout_width="match_parent"
- android:layout_height="@dimen/lb_basic_card_info_height"
- android:paddingStart="@dimen/lb_basic_card_info_padding_horizontal"
- android:paddingEnd="@dimen/lb_basic_card_info_padding_horizontal"
- android:paddingTop="@dimen/lb_basic_card_info_padding_top"
- android:layout_centerHorizontal="true" >
- <TextView
- android:id="@+id/title_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_marginBottom="@dimen/lb_basic_card_info_text_margin"
- android:maxLines="1"
- android:fontFamily="sans-serif-condensed"
- android:textColor="@color/lb_basic_card_title_text_color"
- android:textSize="@dimen/lb_basic_card_title_text_size"
- android:ellipsize="end" />
- <TextView
- android:id="@+id/content_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/title_text"
- android:layout_alignParentStart="true"
- android:layout_toStartOf="@+id/extra_badge"
- android:maxLines="1"
- android:fontFamily="sans-serif-condensed"
- android:textColor="@color/lb_basic_card_content_text_color"
- android:textSize="@dimen/lb_basic_card_content_text_size"
- android:ellipsize="none" />
- <ImageView
- android:id="@+id/extra_badge"
- android:layout_width="@dimen/lb_basic_card_info_badge_size"
- android:layout_height="@dimen/lb_basic_card_info_badge_size"
- android:layout_marginStart="@dimen/lb_basic_card_info_badge_margin"
- android:layout_alignBottom="@id/content_text"
- android:layout_alignParentEnd="true"
- android:scaleType="fitCenter"
- android:visibility="gone"
- android:contentDescription="@null" />
- </android.support.v17.leanback.widget.NonOverlappingRelativeLayout>
-</merge>
+ style="?attr/lbImageCardViewImageStyle" />
+
+ <android.support.v17.leanback.widget.NonOverlappingRelativeLayout
+ android:id="@+id/info_field"
+ style="?attr/lbImageCardViewInfoAreaStyle">
+ </android.support.v17.leanback.widget.NonOverlappingRelativeLayout>
+
+</merge>
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/layout/lb_image_card_view_themed_badge_left.xml
similarity index 68%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/layout/lb_image_card_view_themed_badge_left.xml
index 45a40e1..35d2da6 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/layout/lb_image_card_view_themed_badge_left.xml
@@ -15,7 +15,9 @@
limitations under the License.
-->
-<View
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/extra_badge"
+ android:layout_alignBottom="@+id/content_text"
+ android:layout_alignParentStart="true"
+ android:layout_marginEnd="@dimen/lb_basic_card_info_badge_margin"
+ style="?attr/lbImageCardViewBadgeStyle" />
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/layout/lb_image_card_view_themed_badge_right.xml
similarity index 68%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/layout/lb_image_card_view_themed_badge_right.xml
index 45a40e1..02dd917 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/layout/lb_image_card_view_themed_badge_right.xml
@@ -15,7 +15,9 @@
limitations under the License.
-->
-<View
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/extra_badge"
+ android:layout_alignBottom="@+id/content_text"
+ android:layout_alignParentEnd="true"
+ android:layout_marginStart="@dimen/lb_basic_card_info_badge_margin"
+ style="?attr/lbImageCardViewBadgeStyle" />
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/layout/lb_image_card_view_themed_content.xml
similarity index 80%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/layout/lb_image_card_view_themed_content.xml
index 45a40e1..5592371 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/layout/lb_image_card_view_themed_content.xml
@@ -15,7 +15,6 @@
limitations under the License.
-->
-<View
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content_text"
+ style="?attr/lbImageCardViewContentStyle" />
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/layout/lb_image_card_view_themed_title.xml
similarity index 80%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/layout/lb_image_card_view_themed_title.xml
index 45a40e1..67e2493 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/layout/lb_image_card_view_themed_title.xml
@@ -15,7 +15,6 @@
limitations under the License.
-->
-<View
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/title_text"
+ style="?attr/lbImageCardViewTitleStyle" />
diff --git a/v17/leanback/res/layout/lb_search_fragment.xml b/v17/leanback/res/layout/lb_search_fragment.xml
index 57a46b4..25150d3 100644
--- a/v17/leanback/res/layout/lb_search_fragment.xml
+++ b/v17/leanback/res/layout/lb_search_fragment.xml
@@ -18,8 +18,6 @@
android:id="@+id/lb_search_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="@dimen/lb_search_bar_padding_top"
- android:clipToPadding="false"
android:clipChildren="false"
>
<FrameLayout
@@ -28,6 +26,7 @@
android:layout_height="match_parent"/>
<android.support.v17.leanback.widget.SearchBar
android:id="@+id/lb_search_bar"
+ android:layout_marginTop="@dimen/lb_search_bar_padding_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false"
diff --git a/v17/leanback/res/transition-v21/lb_browse_entrance_transition.xml b/v17/leanback/res/transition-v21/lb_browse_entrance_transition.xml
index e26204b..9dd440b 100644
--- a/v17/leanback/res/transition-v21/lb_browse_entrance_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_browse_entrance_transition.xml
@@ -23,6 +23,6 @@
<slide
android:duration="350"
android:interpolator="@android:interpolator/linear_out_slow_in"
- android:slideEdge="right">
+ android:slideEdge="@integer/slideEdgeEnd">
</slide>
</transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v21/lb_browse_return_transition.xml b/v17/leanback/res/transition-v21/lb_browse_return_transition.xml
index 84ae993..6d341b5 100644
--- a/v17/leanback/res/transition-v21/lb_browse_return_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_browse_return_transition.xml
@@ -18,7 +18,7 @@
<slide
android:interpolator="@android:interpolator/fast_out_linear_in"
android:duration="350"
- android:slideEdge="left">
+ android:slideEdge="@integer/slideEdgeStart">
<targets>
<target android:targetId="@id/browse_headers_root" />
<target android:targetId="@id/title_orb" />
@@ -27,7 +27,7 @@
<slide
android:interpolator="@android:interpolator/fast_out_linear_in"
android:duration="350"
- android:slideEdge="right">
+ android:slideEdge="@integer/slideEdgeEnd">
<targets>
<target android:excludeId="@+id/browse_headers_root" />
<target android:excludeId="@+id/title_orb" />
diff --git a/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml b/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml
new file mode 100644
index 0000000..5ee74ee
--- /dev/null
+++ b/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" >
+ <fade
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:duration="@integer/lb_guidedstep_activity_background_fade_duration_ms">
+ <targets>
+ <target android:targetId="@id/guidedstep_background" />
+ </targets>
+ </fade>
+ <slide
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:duration="350"
+ android:slideEdge="@integer/slideEdgeStart">
+ <targets>
+ <target android:targetId="@id/guidance_icon" />
+ <target android:targetId="@id/guidance_title" />
+ <target android:targetId="@id/guidance_breadcrumb" />
+ <target android:targetId="@id/guidance_description" />
+ </targets>
+ </slide>
+ <slide
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:duration="350"
+ android:slideEdge="@integer/slideEdgeEnd">
+ <targets>
+ <target android:targetId="@id/action_fragment_background" />
+ <target android:targetId="@id/guidedactions_list_background" />
+ <target android:targetId="@id/guidedactions_content" />
+ <target android:targetId="@id/guidedactions_list" />
+ <target android:targetId="@id/guidedactions_selector" />
+ <target android:targetId="@id/guidedactions_list_background2" />
+ <target android:targetId="@id/guidedactions_content2" />
+ <target android:targetId="@id/guidedactions_list2" />
+ <target android:targetId="@id/guidedactions_selector2" />
+ </targets>
+ </slide>
+</transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml b/v17/leanback/res/transition-v21/lb_vertical_grid_enter_transition.xml
similarity index 74%
copy from v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml
copy to v17/leanback/res/transition-v21/lb_vertical_grid_enter_transition.xml
index 2068c64..00466cb 100644
--- a/v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_vertical_grid_enter_transition.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ 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.
@@ -16,13 +16,7 @@
-->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" >
- <changeBounds
- android:duration="350"
- android:interpolator="@android:interpolator/linear_out_slow_in">
- </changeBounds>
- <slide
- android:duration="350"
+ <fade
android:interpolator="@android:interpolator/linear_out_slow_in"
- android:slideEdge="end">
- </slide>
+ android:duration="150"/>
</transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml b/v17/leanback/res/transition-v21/lb_vertical_grid_entrance_transition.xml
similarity index 78%
rename from v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml
rename to v17/leanback/res/transition-v21/lb_vertical_grid_entrance_transition.xml
index 2068c64..ee06953 100644
--- a/v17/leanback/res/transition-v22/lb_browse_entrance_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_vertical_grid_entrance_transition.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ 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.
@@ -16,13 +16,9 @@
-->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" >
- <changeBounds
- android:duration="350"
- android:interpolator="@android:interpolator/linear_out_slow_in">
- </changeBounds>
<slide
android:duration="350"
android:interpolator="@android:interpolator/linear_out_slow_in"
- android:slideEdge="end">
+ android:slideEdge="bottom">
</slide>
</transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v22/lb_browse_return_transition.xml b/v17/leanback/res/transition-v21/lb_vertical_grid_return_transition.xml
similarity index 64%
rename from v17/leanback/res/transition-v22/lb_browse_return_transition.xml
rename to v17/leanback/res/transition-v21/lb_vertical_grid_return_transition.xml
index e8dbee0..edb3816 100644
--- a/v17/leanback/res/transition-v22/lb_browse_return_transition.xml
+++ b/v17/leanback/res/transition-v21/lb_vertical_grid_return_transition.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ 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.
@@ -18,26 +18,15 @@
<slide
android:interpolator="@android:interpolator/fast_out_linear_in"
android:duration="350"
- android:slideEdge="start">
+ android:slideEdge="bottom">
<targets>
- <target android:targetId="@id/browse_headers_root" />
- <target android:targetId="@id/title_orb" />
- </targets>
- </slide>
- <slide
- android:interpolator="@android:interpolator/fast_out_linear_in"
- android:duration="350"
- android:slideEdge="end">
- <targets>
- <target android:excludeId="@+id/browse_headers_root" />
<target android:excludeId="@+id/title_orb" />
+ <target android:excludeId="@+id/title_text" />
+ <target android:excludeId="@+id/title_badge" />
</targets>
</slide>
<fade
android:interpolator="@android:interpolator/fast_out_linear_in"
android:duration="350">
- <targets>
- <target android:excludeId="@+id/browse_headers_root" />
- </targets>
</fade>
</transitionSet>
\ No newline at end of file
diff --git a/v17/leanback/res/values-af/strings.xml b/v17/leanback/res/values-af/strings.xml
index c7109bb..0310403 100644
--- a/v17/leanback/res/values-af/strings.xml
+++ b/v17/leanback/res/values-af/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiveer hoë gehalte"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktiveer onderskrifte"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiveer onderskrifte"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Voltooi"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Gaan voort"</string>
</resources>
diff --git a/v17/leanback/res/values-am/strings.xml b/v17/leanback/res/values-am/strings.xml
index d5bf0f5..77d2993 100644
--- a/v17/leanback/res/values-am/strings.xml
+++ b/v17/leanback/res/values-am/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ከፍተኛ ጥራትን አሰናክል"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ዝግ የምስል ስር ጽሑፍ አጻጻፍን አንቃ"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ዝግ የምስል ስር ጽሑፍ አጻጻፍን አሰናክል"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ጨርስ"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ቀጥል"</string>
</resources>
diff --git a/v17/leanback/res/values-ar/strings.xml b/v17/leanback/res/values-ar/strings.xml
index 31f4d1a..c52be7f 100644
--- a/v17/leanback/res/values-ar/strings.xml
+++ b/v17/leanback/res/values-ar/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"تعطيل الجودة العالية"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"تمكين الترجمة المصاحبة"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"تعطيل الترجمة المصاحبة"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"إنهاء"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"متابعة"</string>
</resources>
diff --git a/v17/leanback/res/values-az-rAZ/strings.xml b/v17/leanback/res/values-az-rAZ/strings.xml
index d1e685f..cb558a0 100644
--- a/v17/leanback/res/values-az-rAZ/strings.xml
+++ b/v17/leanback/res/values-az-rAZ/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yüksək keyfiyyəti deaktiv edin"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Qapalı çəkilişi aktiv edin"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Qapalı çəkilişi deaktiv edin"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Bitir"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davam edin"</string>
</resources>
diff --git a/v17/leanback/res/values-bg/strings.xml b/v17/leanback/res/values-bg/strings.xml
index 74c01b6..6b16775 100644
--- a/v17/leanback/res/values-bg/strings.xml
+++ b/v17/leanback/res/values-bg/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Деактивиране на високото качество"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Активиране на субтитрите"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Деактивиране на субтитрите"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Край"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Напред"</string>
</resources>
diff --git a/v17/leanback/res/values-bn-rBD/strings.xml b/v17/leanback/res/values-bn-rBD/strings.xml
index 4f0526c..04669bd 100644
--- a/v17/leanback/res/values-bn-rBD/strings.xml
+++ b/v17/leanback/res/values-bn-rBD/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"উচ্চ গুণমান অক্ষম করুন"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"সাবটাইটেল সক্ষম করুন"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"সাবটাইটেল অক্ষম করুন"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"শেষ করুন"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"চালিয়ে যান"</string>
</resources>
diff --git a/v17/leanback/res/values-ca/strings.xml b/v17/leanback/res/values-ca/strings.xml
index dbf20a8..6578f3b 100644
--- a/v17/leanback/res/values-ca/strings.xml
+++ b/v17/leanback/res/values-ca/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desactiva l\'alta qualitat"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activa els subtítols tancats"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactiva els subtítols tancats"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalitza"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continua"</string>
</resources>
diff --git a/v17/leanback/res/values-cs/strings.xml b/v17/leanback/res/values-cs/strings.xml
index 13f9689..8ffb4f3 100644
--- a/v17/leanback/res/values-cs/strings.xml
+++ b/v17/leanback/res/values-cs/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Vypnout vysokou kvalitu"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnout titulky"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnout titulky"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončit"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Pokračovat"</string>
</resources>
diff --git a/v17/leanback/res/values-da/strings.xml b/v17/leanback/res/values-da/strings.xml
index 701138f..87c507b 100644
--- a/v17/leanback/res/values-da/strings.xml
+++ b/v17/leanback/res/values-da/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiver høj kvalitet"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér undertekster"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver undertekster"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Afslut"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsæt"</string>
</resources>
diff --git a/v17/leanback/res/values-de/strings.xml b/v17/leanback/res/values-de/strings.xml
index db0c3e0..9d018c6 100644
--- a/v17/leanback/res/values-de/strings.xml
+++ b/v17/leanback/res/values-de/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Hohe Qualität deaktivieren"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Untertitel aktivieren"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Untertitel deaktivieren"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fertigstellen"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Weiter"</string>
</resources>
diff --git a/v17/leanback/res/values-el/strings.xml b/v17/leanback/res/values-el/strings.xml
index 6c4f603..310b6a9 100644
--- a/v17/leanback/res/values-el/strings.xml
+++ b/v17/leanback/res/values-el/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Απενεργοποίηση Υψηλής ποιότητας"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ενεργοποίηση υποτίτλων"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Απενεργοποίηση υποτίτλων"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Τέλος"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Συνέχεια"</string>
</resources>
diff --git a/v17/leanback/res/values-en-rAU/strings.xml b/v17/leanback/res/values-en-rAU/strings.xml
index ed22ccd..0097135 100644
--- a/v17/leanback/res/values-en-rAU/strings.xml
+++ b/v17/leanback/res/values-en-rAU/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
</resources>
diff --git a/v17/leanback/res/values-en-rGB/strings.xml b/v17/leanback/res/values-en-rGB/strings.xml
index ed22ccd..0097135 100644
--- a/v17/leanback/res/values-en-rGB/strings.xml
+++ b/v17/leanback/res/values-en-rGB/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
</resources>
diff --git a/v17/leanback/res/values-en-rIN/strings.xml b/v17/leanback/res/values-en-rIN/strings.xml
index ed22ccd..0097135 100644
--- a/v17/leanback/res/values-en-rIN/strings.xml
+++ b/v17/leanback/res/values-en-rIN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finish"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continue"</string>
</resources>
diff --git a/v17/leanback/res/values-es-rUS/strings.xml b/v17/leanback/res/values-es-rUS/strings.xml
index ab05f83..8341a4d 100644
--- a/v17/leanback/res/values-es-rUS/strings.xml
+++ b/v17/leanback/res/values-es-rUS/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inhabilitar calidad alta"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
</resources>
diff --git a/v17/leanback/res/values-es/strings.xml b/v17/leanback/res/values-es/strings.xml
index 9e6c526..9f308c0 100644
--- a/v17/leanback/res/values-es/strings.xml
+++ b/v17/leanback/res/values-es/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inhabilitar alta calidad"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
</resources>
diff --git a/v17/leanback/res/values-et-rEE/strings.xml b/v17/leanback/res/values-et-rEE/strings.xml
index cfda00e..a97c385 100644
--- a/v17/leanback/res/values-et-rEE/strings.xml
+++ b/v17/leanback/res/values-et-rEE/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Keela kõrgkvaliteetne taasesitus"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Luba subtiitrid"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Keela subtiitrid"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Lõpeta"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jätka"</string>
</resources>
diff --git a/v17/leanback/res/values-eu-rES/strings.xml b/v17/leanback/res/values-eu-rES/strings.xml
index d9f9bf7..c22f172 100644
--- a/v17/leanback/res/values-eu-rES/strings.xml
+++ b/v17/leanback/res/values-eu-rES/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desgaitu kalitate handiko erreprodukzioa"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Gaitu azpitituluak"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desgaitu azpitituluak"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Amaitu"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jarraitu"</string>
</resources>
diff --git a/v17/leanback/res/values-fa/strings.xml b/v17/leanback/res/values-fa/strings.xml
index 0a2ceff..58e823f 100644
--- a/v17/leanback/res/values-fa/strings.xml
+++ b/v17/leanback/res/values-fa/strings.xml
@@ -25,7 +25,7 @@
<string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
<string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
<string name="lb_playback_controls_play" msgid="731953341987346903">"پخش"</string>
- <string name="lb_playback_controls_pause" msgid="6189521112079849518">"مکث"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"توقف موقت"</string>
<string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"جلو بردن سریع"</string>
<string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"بازارسال سریع %1$dX"</string>
<string name="lb_playback_controls_rewind" msgid="2227196334132350684">"عقب بردن"</string>
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"غیرفعال کردن کیفیت بالا"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"فعال کردن زیرنویس"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"غیرفعال کردن زیرنویس"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"پایان"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ادامه"</string>
</resources>
diff --git a/v17/leanback/res/values-fi/strings.xml b/v17/leanback/res/values-fi/strings.xml
index 92b5f12..0c55e6f 100644
--- a/v17/leanback/res/values-fi/strings.xml
+++ b/v17/leanback/res/values-fi/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Poista korkea laatu käytöstä"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ota tekstitys käyttöön"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Poista tekstitys käytöstä"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Valmis"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Jatka"</string>
</resources>
diff --git a/v17/leanback/res/values-fr-rCA/strings.xml b/v17/leanback/res/values-fr-rCA/strings.xml
index bbd3eea..b28beae 100644
--- a/v17/leanback/res/values-fr-rCA/strings.xml
+++ b/v17/leanback/res/values-fr-rCA/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Désactiver la lecture haute qualité"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer le sous-titrage"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver le sous-titrage"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Terminer"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuer"</string>
</resources>
diff --git a/v17/leanback/res/values-fr/strings.xml b/v17/leanback/res/values-fr/strings.xml
index 0a3e6fe..914bf08 100644
--- a/v17/leanback/res/values-fr/strings.xml
+++ b/v17/leanback/res/values-fr/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Désactiver la haute qualité"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer les sous-titres"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver les sous-titres"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Terminer"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuer"</string>
</resources>
diff --git a/v17/leanback/res/values-gl-rES/strings.xml b/v17/leanback/res/values-gl-rES/strings.xml
index 717b994..62b3a2b 100644
--- a/v17/leanback/res/values-gl-rES/strings.xml
+++ b/v17/leanback/res/values-gl-rES/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desactivar alta calidade"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activar subtítulos"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactivar subtítulos"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizar"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
</resources>
diff --git a/v17/leanback/res/values-gu-rIN/strings.xml b/v17/leanback/res/values-gu-rIN/strings.xml
index 2e4f30f..afec9da9 100644
--- a/v17/leanback/res/values-gu-rIN/strings.xml
+++ b/v17/leanback/res/values-gu-rIN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ઉચ્ચ ગુણવત્તા અક્ષમ કરો"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ઉપશીર્ષક સક્ષમ કરો"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"વિગતવાર ઉપશીર્ષકોને અક્ષમ કરો"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"સમાપ્ત કરો"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ચાલુ રાખો"</string>
</resources>
diff --git a/v17/leanback/res/values-hi/strings.xml b/v17/leanback/res/values-hi/strings.xml
index a926396..c243c17 100644
--- a/v17/leanback/res/values-hi/strings.xml
+++ b/v17/leanback/res/values-hi/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करें"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षक सक्षम करें"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षक अक्षम करें"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त करें"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"जारी रखें"</string>
</resources>
diff --git a/v17/leanback/res/values-hr/strings.xml b/v17/leanback/res/values-hr/strings.xml
index 974de0a..bb6ebcc 100644
--- a/v17/leanback/res/values-hr/strings.xml
+++ b/v17/leanback/res/values-hr/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogući visoku kvalitetu"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogući titlove"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogući titlove"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Završi"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Nastavi"</string>
</resources>
diff --git a/v17/leanback/res/values-hu/strings.xml b/v17/leanback/res/values-hu/strings.xml
index 427f1cd..cfeb2ad 100644
--- a/v17/leanback/res/values-hu/strings.xml
+++ b/v17/leanback/res/values-hu/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Jó minőségű lejátszás letiltása"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Feliratok engedélyezése"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Feliratok letiltása"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Befejezés"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Folytatás"</string>
</resources>
diff --git a/v17/leanback/res/values-hy-rAM/strings.xml b/v17/leanback/res/values-hy-rAM/strings.xml
index 7e8112e..1ac5dd8 100644
--- a/v17/leanback/res/values-hy-rAM/strings.xml
+++ b/v17/leanback/res/values-hy-rAM/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Անջատել բարձր որակը"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Միացնել խորագրերը"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Անջատել խորագրերը"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Վերջ"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Շարունակել"</string>
</resources>
diff --git a/v17/leanback/res/values-in/strings.xml b/v17/leanback/res/values-in/strings.xml
index 2dca7d3..6569825 100644
--- a/v17/leanback/res/values-in/strings.xml
+++ b/v17/leanback/res/values-in/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Nonaktifkan Kualitas Tinggi"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktifkan Pembuatan Teks"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Nonaktifkan Pembuatan Teks"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Selesai"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Lanjutkan"</string>
</resources>
diff --git a/v17/leanback/res/values-is-rIS/strings.xml b/v17/leanback/res/values-is-rIS/strings.xml
index c84a4c6..830b11e 100644
--- a/v17/leanback/res/values-is-rIS/strings.xml
+++ b/v17/leanback/res/values-is-rIS/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Slökkva á miklum gæðum"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Kveikja á skjátextum"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Slökkva á skjátextum"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Ljúka"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Halda áfram"</string>
</resources>
diff --git a/v17/leanback/res/values-it/strings.xml b/v17/leanback/res/values-it/strings.xml
index 1b58e0c..2f0ca47 100644
--- a/v17/leanback/res/values-it/strings.xml
+++ b/v17/leanback/res/values-it/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disattiva alta qualità"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Attiva sottotitoli"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disattiva sottotitoli"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fine"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continua"</string>
</resources>
diff --git a/v17/leanback/res/values-iw/strings.xml b/v17/leanback/res/values-iw/strings.xml
index f102498..f2bda58 100644
--- a/v17/leanback/res/values-iw/strings.xml
+++ b/v17/leanback/res/values-iw/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"השבת איכות גבוהה"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"הפעל כתוביות"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"השבת כתוביות"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"סיום"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"המשך"</string>
</resources>
diff --git a/v17/leanback/res/values-ja/strings.xml b/v17/leanback/res/values-ja/strings.xml
index 802631c..09faa8b 100644
--- a/v17/leanback/res/values-ja/strings.xml
+++ b/v17/leanback/res/values-ja/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"高品質を無効にする"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"字幕を有効にする"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"字幕を無効にする"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完了"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"続行"</string>
</resources>
diff --git a/v17/leanback/res/values-ka-rGE/strings.xml b/v17/leanback/res/values-ka-rGE/strings.xml
index 70aeada..ac9f4cd 100644
--- a/v17/leanback/res/values-ka-rGE/strings.xml
+++ b/v17/leanback/res/values-ka-rGE/strings.xml
@@ -50,4 +50,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"მაღალი ხარისხის გამორთვა"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"დახურული წარწერების ჩართვა"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"დახურული წარწერების გაუქმება"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"დასრულება"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"გაგრძელება"</string>
</resources>
diff --git a/v17/leanback/res/values-kk-rKZ/strings.xml b/v17/leanback/res/values-kk-rKZ/strings.xml
index 9ed6ce2..380695b 100644
--- a/v17/leanback/res/values-kk-rKZ/strings.xml
+++ b/v17/leanback/res/values-kk-rKZ/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Жоғары сапаны өшіру"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Жасырын титрлерді қосу"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Жасырын титрлерді өшіру"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Аяқтау"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Жалғастыру"</string>
</resources>
diff --git a/v17/leanback/res/values-km-rKH/strings.xml b/v17/leanback/res/values-km-rKH/strings.xml
index 7874af2..60f90e5 100644
--- a/v17/leanback/res/values-km-rKH/strings.xml
+++ b/v17/leanback/res/values-km-rKH/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"បិទគុណភាពខ្ពស់"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"បើកការដាក់ចំណងដែលបានបិទ"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"បិទការដាក់ចំណងដែលបានបិទ"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"បញ្ចប់"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"បន្ត"</string>
</resources>
diff --git a/v17/leanback/res/values-kn-rIN/strings.xml b/v17/leanback/res/values-kn-rIN/strings.xml
index 196b154..18206ed 100644
--- a/v17/leanback/res/values-kn-rIN/strings.xml
+++ b/v17/leanback/res/values-kn-rIN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ಹೆಚ್ಚು ಗುಣಮಟ್ಟವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ಪೂರ್ಣಗೊಳಿಸು"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ಮುಂದುವರಿಸು"</string>
</resources>
diff --git a/v17/leanback/res/values-ko/strings.xml b/v17/leanback/res/values-ko/strings.xml
index c244dbf..e262b1c 100644
--- a/v17/leanback/res/values-ko/strings.xml
+++ b/v17/leanback/res/values-ko/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"고화질 사용 중지"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"자막 사용 설정"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"자막 사용 중지"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"완료"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"계속"</string>
</resources>
diff --git a/v17/leanback/res/values-ky-rKG/strings.xml b/v17/leanback/res/values-ky-rKG/strings.xml
index 4ddb284..74cc841 100644
--- a/v17/leanback/res/values-ky-rKG/strings.xml
+++ b/v17/leanback/res/values-ky-rKG/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Жогорку сапатты өчүрүү"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Жабык субтитрлерди иштетүү"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Жабык субтитрлерди өчүрүү"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Бүтүрүү"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Улантуу"</string>
</resources>
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v17/leanback/res/values-ldrtl/integers.xml
similarity index 72%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to v17/leanback/res/values-ldrtl/integers.xml
index a4614f6..250523d 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v17/leanback/res/values-ldrtl/integers.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+ 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.
@@ -13,7 +14,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<resources>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_setting_light" />
-</selector>
+ <!-- Gravity.RIGHT -->
+ <integer name="slideEdgeStart">5</integer>
+ <!-- Gravity.LEFT -->
+ <integer name="slideEdgeEnd">3</integer>
+
+</resources>
\ No newline at end of file
diff --git a/v17/leanback/res/values-lo-rLA/strings.xml b/v17/leanback/res/values-lo-rLA/strings.xml
index 35f519b..d919e93 100644
--- a/v17/leanback/res/values-lo-rLA/strings.xml
+++ b/v17/leanback/res/values-lo-rLA/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ປິດນຳໃຊ້ການຫຼິ້ນດ້ວຍຄຸນນະພາບສູງ"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ເປີດນຳໃຊ້ຄຳບັນຍາຍແບບປິດ"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ປິດນຳໃຊ້ຄຳບັນຍາຍແບບປິດ"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ສໍາເລັດ"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ສືບຕໍ່"</string>
</resources>
diff --git a/v17/leanback/res/values-lt/strings.xml b/v17/leanback/res/values-lt/strings.xml
index 6ca2bab..415fc25 100644
--- a/v17/leanback/res/values-lt/strings.xml
+++ b/v17/leanback/res/values-lt/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Išjungti aukštą kokybę"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Įgalinti subtitrus"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Išjungti subtitrus"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Baigti"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Tęsti"</string>
</resources>
diff --git a/v17/leanback/res/values-lv/strings.xml b/v17/leanback/res/values-lv/strings.xml
index 7d3bc2b..3979e43 100644
--- a/v17/leanback/res/values-lv/strings.xml
+++ b/v17/leanback/res/values-lv/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Atspējot augstas kvalitātes vienumu atskaņošanu"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Iespējot slēgtos parakstus"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Atspējot slēgtos parakstus"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Pabeigt"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Turpināt"</string>
</resources>
diff --git a/v17/leanback/res/values-mk-rMK/strings.xml b/v17/leanback/res/values-mk-rMK/strings.xml
index 75666e0..ccf6d62 100644
--- a/v17/leanback/res/values-mk-rMK/strings.xml
+++ b/v17/leanback/res/values-mk-rMK/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Оневозможи висок квалитет"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Овозможи затворено објаснување"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Оневозможи затворено објаснување"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Заврши"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Продолжи"</string>
</resources>
diff --git a/v17/leanback/res/values-ml-rIN/strings.xml b/v17/leanback/res/values-ml-rIN/strings.xml
index b900f09..356b0e9 100644
--- a/v17/leanback/res/values-ml-rIN/strings.xml
+++ b/v17/leanback/res/values-ml-rIN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ഉയർന്ന നിലവാരം പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"അടച്ച അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"അടച്ച അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനരഹിതമാക്കുക"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"പൂര്ത്തിയാക്കുക"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"തുടരുക"</string>
</resources>
diff --git a/v17/leanback/res/values-mn-rMN/strings.xml b/v17/leanback/res/values-mn-rMN/strings.xml
index e4a8fcd..a7a640f 100644
--- a/v17/leanback/res/values-mn-rMN/strings.xml
+++ b/v17/leanback/res/values-mn-rMN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Өндөр чанарыг идэвхгүйжүүлэх"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Текст тайлбарыг идэвхжүүлэх"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Текст тайлбарыг идэвхгүйжүүлэх"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Дуусгах"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Үргэлжлүүлэх"</string>
</resources>
diff --git a/v17/leanback/res/values-mr-rIN/strings.xml b/v17/leanback/res/values-mr-rIN/strings.xml
index 11748ec..b9b568a 100644
--- a/v17/leanback/res/values-mr-rIN/strings.xml
+++ b/v17/leanback/res/values-mr-rIN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करा"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षके सक्षम करा"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षके अक्षम करा"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"सुरू ठेवा"</string>
</resources>
diff --git a/v17/leanback/res/values-ms-rMY/strings.xml b/v17/leanback/res/values-ms-rMY/strings.xml
index c073e43..0a5f8bd 100644
--- a/v17/leanback/res/values-ms-rMY/strings.xml
+++ b/v17/leanback/res/values-ms-rMY/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Lumpuhkan Kualiti Tinggi"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Dayakan Kapsyen Tertutup"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Lumpuhkan Kapsyen Tertutup"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Selesai"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Teruskan"</string>
</resources>
diff --git a/v17/leanback/res/values-my-rMM/strings.xml b/v17/leanback/res/values-my-rMM/strings.xml
index 2efaf7f..1b3cdee 100644
--- a/v17/leanback/res/values-my-rMM/strings.xml
+++ b/v17/leanback/res/values-my-rMM/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"အရည်အသွေးကောင်းအား ပိတ်ထားရန်"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"စာတမ်းထိုး ဖွင့်ရန်"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"စာတမ်းထိုးအား ပိတ်ထားရန်"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ပြီးပြီ"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ဆက်လုပ်ရန်"</string>
</resources>
diff --git a/v17/leanback/res/values-nb/strings.xml b/v17/leanback/res/values-nb/strings.xml
index f5ab2e1..c58544d 100644
--- a/v17/leanback/res/values-nb/strings.xml
+++ b/v17/leanback/res/values-nb/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiver høy kvalitet"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér teksting"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver teksting"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Fullfør"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsett"</string>
</resources>
diff --git a/v17/leanback/res/values-ne-rNP/strings.xml b/v17/leanback/res/values-ne-rNP/strings.xml
index c399985..54c92856 100644
--- a/v17/leanback/res/values-ne-rNP/strings.xml
+++ b/v17/leanback/res/values-ne-rNP/strings.xml
@@ -48,4 +48,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणस्तर असक्षम"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"बन्द क्याप्सनहरु सक्षम"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"बन्द क्याप्सनहरु असक्षम"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"समाप्त गर्नुहोस्"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"जारी राख्नुहोस्"</string>
</resources>
diff --git a/v17/leanback/res/values-nl/strings.xml b/v17/leanback/res/values-nl/strings.xml
index 1925e14..941aa79 100644
--- a/v17/leanback/res/values-nl/strings.xml
+++ b/v17/leanback/res/values-nl/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Hoge kwaliteit uitschakelen"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ondertiteling inschakelen"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Ondertiteling uitschakelen"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Voltooien"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Doorgaan"</string>
</resources>
diff --git a/v17/leanback/res/values-pa-rIN/strings.xml b/v17/leanback/res/values-pa-rIN/strings.xml
index f9c7c4b..f197657 100644
--- a/v17/leanback/res/values-pa-rIN/strings.xml
+++ b/v17/leanback/res/values-pa-rIN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ਉੱਚ ਗੁਣਵੱਤਾ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਸਮਰੱਥ ਬਣਾਓ"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ਖ਼ਤਮ"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ਜਾਰੀ ਰੱਖੋ"</string>
</resources>
diff --git a/v17/leanback/res/values-pl/strings.xml b/v17/leanback/res/values-pl/strings.xml
index 18b8bf6..7598c73 100644
--- a/v17/leanback/res/values-pl/strings.xml
+++ b/v17/leanback/res/values-pl/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Wyłącz wysoką jakość"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Włącz napisy"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Wyłącz napisy"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Zakończ"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Dalej"</string>
</resources>
diff --git a/v17/leanback/res/values-pt-rBR/strings.xml b/v17/leanback/res/values-pt-rBR/strings.xml
index 79b9d40..12c9533 100644
--- a/v17/leanback/res/values-pt-rBR/strings.xml
+++ b/v17/leanback/res/values-pt-rBR/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
</resources>
diff --git a/v17/leanback/res/values-pt-rPT/strings.xml b/v17/leanback/res/values-pt-rPT/strings.xml
index f269712..7b12f5e 100644
--- a/v17/leanback/res/values-pt-rPT/strings.xml
+++ b/v17/leanback/res/values-pt-rPT/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar legendas"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar legendas"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
</resources>
diff --git a/v17/leanback/res/values-pt/strings.xml b/v17/leanback/res/values-pt/strings.xml
index 79b9d40..12c9533 100644
--- a/v17/leanback/res/values-pt/strings.xml
+++ b/v17/leanback/res/values-pt/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Concluir"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuar"</string>
</resources>
diff --git a/v17/leanback/res/values-ro/strings.xml b/v17/leanback/res/values-ro/strings.xml
index cb6aa4a..b4f9ee3 100644
--- a/v17/leanback/res/values-ro/strings.xml
+++ b/v17/leanback/res/values-ro/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Dezactivează calitatea înaltă"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activează subtitrările"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Dezactivează subtitrările"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Finalizați"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Continuați"</string>
</resources>
diff --git a/v17/leanback/res/values-ru/strings.xml b/v17/leanback/res/values-ru/strings.xml
index fdb453b..864054a 100644
--- a/v17/leanback/res/values-ru/strings.xml
+++ b/v17/leanback/res/values-ru/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Отключить высокое качество."</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Включить субтитры."</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Отключить субтитры."</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Готово"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Далее"</string>
</resources>
diff --git a/v17/leanback/res/values-si-rLK/strings.xml b/v17/leanback/res/values-si-rLK/strings.xml
index e5c0cf4..3db1293 100644
--- a/v17/leanback/res/values-si-rLK/strings.xml
+++ b/v17/leanback/res/values-si-rLK/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"උපරිම ගුණත්වය අබල කරන ලදි"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"වැසුණු ශිර්ෂ කිරීම සබල කරන ලදි"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"වැසුණු ශිර්ෂ කිරීම අබල කරන ලදි"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"අවසානය"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"දිගටම කර ගෙන යන්න"</string>
</resources>
diff --git a/v17/leanback/res/values-sk/strings.xml b/v17/leanback/res/values-sk/strings.xml
index 74a9044..a317d18 100644
--- a/v17/leanback/res/values-sk/strings.xml
+++ b/v17/leanback/res/values-sk/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Zakázať médiá vo vysokej kvalite"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnúť skryté titulky"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnúť skryté titulky"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončiť"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Pokračovať"</string>
</resources>
diff --git a/v17/leanback/res/values-sl/strings.xml b/v17/leanback/res/values-sl/strings.xml
index b5d0e1d..7b16952 100644
--- a/v17/leanback/res/values-sl/strings.xml
+++ b/v17/leanback/res/values-sl/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogoči visoko kakovost"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogoči podnapise"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogoči podnapise"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Dokončaj"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Naprej"</string>
</resources>
diff --git a/v17/leanback/res/values-sq-rAL/strings.xml b/v17/leanback/res/values-sq-rAL/strings.xml
index 28c313f..723b90c 100644
--- a/v17/leanback/res/values-sq-rAL/strings.xml
+++ b/v17/leanback/res/values-sq-rAL/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Çaktivizo \"Cilësinë e lartë\""</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivizo titrat"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Çaktivizo titrat me sekuencë kohore"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Përfundo"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Vazhdo"</string>
</resources>
diff --git a/v17/leanback/res/values-sr/strings.xml b/v17/leanback/res/values-sr/strings.xml
index bb5c32d..df6c6b1 100644
--- a/v17/leanback/res/values-sr/strings.xml
+++ b/v17/leanback/res/values-sr/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Онемогући висок квалитет"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Омогући титлове"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Онемогући титлове"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Доврши"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Настави"</string>
</resources>
diff --git a/v17/leanback/res/values-sv/strings.xml b/v17/leanback/res/values-sv/strings.xml
index 1a8e757..9b874ca 100644
--- a/v17/leanback/res/values-sv/strings.xml
+++ b/v17/leanback/res/values-sv/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inaktivera hög kvalitet"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivera textning"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inaktivera textning"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Slutför"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Fortsätt"</string>
</resources>
diff --git a/v17/leanback/res/values-sw/strings.xml b/v17/leanback/res/values-sw/strings.xml
index 0ad04d1..53ef95a 100644
--- a/v17/leanback/res/values-sw/strings.xml
+++ b/v17/leanback/res/values-sw/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Zima Ubora wa Juu"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Washa manukuu"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Zima manukuu"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Kamilisha"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Endelea"</string>
</resources>
diff --git a/v17/leanback/res/values-ta-rIN/strings.xml b/v17/leanback/res/values-ta-rIN/strings.xml
index f67ee4d..1cc2eea 100644
--- a/v17/leanback/res/values-ta-rIN/strings.xml
+++ b/v17/leanback/res/values-ta-rIN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"உயர் தரத்தை முடக்கு"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"விரிவான வசனங்களை இயக்கு"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"விரிவான வசனங்களை முடக்கு"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"முடி"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"தொடர்க"</string>
</resources>
diff --git a/v17/leanback/res/values-te-rIN/strings.xml b/v17/leanback/res/values-te-rIN/strings.xml
index f71e8cb..32d311d 100644
--- a/v17/leanback/res/values-te-rIN/strings.xml
+++ b/v17/leanback/res/values-te-rIN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"అధిక నాణ్యతను నిలిపివేయి"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"సంవృత శీర్షికలను ప్రారంభించు"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"సంవృత శీర్షికలను నిలిపివేయి"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"ముగించు"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"కొనసాగించు"</string>
</resources>
diff --git a/v17/leanback/res/values-th/strings.xml b/v17/leanback/res/values-th/strings.xml
index 093a529..d3eb2a3 100644
--- a/v17/leanback/res/values-th/strings.xml
+++ b/v17/leanback/res/values-th/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ปิดใช้คุณภาพสูง"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"เปิดใช้คำบรรยาย"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ปิดใช้คำบรรยาย"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"เสร็จสิ้น"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"ต่อไป"</string>
</resources>
diff --git a/v17/leanback/res/values-tl/strings.xml b/v17/leanback/res/values-tl/strings.xml
index a536298..f50b4d1 100644
--- a/v17/leanback/res/values-tl/strings.xml
+++ b/v17/leanback/res/values-tl/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"I-disable ang Mataas na Kalidad"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"I-enable ang Paglalagay ng Subtitle"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"I-disable ang Paglalagay ng Subtitle"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tapusin"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Magpatuloy"</string>
</resources>
diff --git a/v17/leanback/res/values-tr/strings.xml b/v17/leanback/res/values-tr/strings.xml
index 800436c..814cb29 100644
--- a/v17/leanback/res/values-tr/strings.xml
+++ b/v17/leanback/res/values-tr/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yüksek Kalitede Oynatmayı Devre Dışı Bırak"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Altyazıları Etkinleştir"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Altyazıları Devre Dışı Bırak"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Son"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Devam"</string>
</resources>
diff --git a/v17/leanback/res/values-uk/strings.xml b/v17/leanback/res/values-uk/strings.xml
index 79b2782..a38db30 100644
--- a/v17/leanback/res/values-uk/strings.xml
+++ b/v17/leanback/res/values-uk/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Вимкнути високу якість"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Увімкнути субтитри"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Вимкнути субтитри"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Закінчити"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Продовжити"</string>
</resources>
diff --git a/v17/leanback/res/values-ur-rPK/strings.xml b/v17/leanback/res/values-ur-rPK/strings.xml
index b670251..666cf71 100644
--- a/v17/leanback/res/values-ur-rPK/strings.xml
+++ b/v17/leanback/res/values-ur-rPK/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"اعلی معیار کو غیر فعال کریں"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"سب ٹائٹلز کو فعال کریں"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"سب ٹائٹلز کو غیر فعال کریں"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"مکمل کریں"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"جاری رکھیں"</string>
</resources>
diff --git a/v17/leanback/res/values-uz-rUZ/strings.xml b/v17/leanback/res/values-uz-rUZ/strings.xml
index c761244..d81d8de 100644
--- a/v17/leanback/res/values-uz-rUZ/strings.xml
+++ b/v17/leanback/res/values-uz-rUZ/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yuqori sifatni o‘chirib qo‘yish"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Taglavhalarni yoqish"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Taglavhalarni o‘chirib qo‘yish"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Tugatish"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Davom etish"</string>
</resources>
diff --git a/v17/leanback/res/values-v19/themes.xml b/v17/leanback/res/values-v19/themes.xml
index 53befec..74e0e2e9 100644
--- a/v17/leanback/res/values-v19/themes.xml
+++ b/v17/leanback/res/values-v19/themes.xml
@@ -20,6 +20,7 @@
<item name="playbackProgressPrimaryColor">@color/lb_playback_progress_color_no_theme</item>
<item name="playbackControlsIconHighlightColor">@color/lb_playback_icon_highlight_no_theme</item>
<item name="defaultBrandColor">@color/lb_default_brand_color</item>
+ <item name="defaultBrandColorDark">@color/lb_default_brand_color_dark</item>
<item name="android:windowOverscan">true</item>
<item name="guidedStepTheme">@style/Theme.Leanback.GuidedStep</item>
diff --git a/v17/leanback/res/values-v21/themes.xml b/v17/leanback/res/values-v21/themes.xml
index 3b48dae..1072b2b 100644
--- a/v17/leanback/res/values-v21/themes.xml
+++ b/v17/leanback/res/values-v21/themes.xml
@@ -21,6 +21,8 @@
<item name="playbackControlsIconHighlightColor">?android:attr/colorAccent</item>
<item name="defaultBrandColor">?android:attr/colorPrimary</item>
<item name="android:colorPrimary">@color/lb_default_brand_color</item>
+ <item name="defaultBrandColorDark">?android:attr/colorPrimaryDark</item>
+ <item name="android:colorPrimaryDark">@color/lb_default_brand_color_dark</item>
<item name="android:windowOverscan">true</item>
<item name="guidedStepTheme">@style/Theme.Leanback.GuidedStep</item>
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v17/leanback/res/values-v22/integers.xml
similarity index 71%
copy from v17/leanback/res/layout/lb_card_color_overlay.xml
copy to v17/leanback/res/values-v22/integers.xml
index 45a40e1..fdd7792 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v17/leanback/res/values-v22/integers.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ 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.
@@ -14,8 +14,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<resources>
-<View
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ <!-- Gravity.START -->
+ <integer name="slideEdgeStart">0x800003</integer>
+ <!-- Gravity.END -->
+ <integer name="slideEdgeEnd">0x800005</integer>
+
+</resources>
\ No newline at end of file
diff --git a/v17/leanback/res/values-vi/strings.xml b/v17/leanback/res/values-vi/strings.xml
index baf1c44..881734b 100644
--- a/v17/leanback/res/values-vi/strings.xml
+++ b/v17/leanback/res/values-vi/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Tắt chế độ chất lượng cao"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Bật phụ đề"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Tắt phụ đề"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Hoàn tất"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Tiếp tục"</string>
</resources>
diff --git a/v17/leanback/res/values-zh-rCN/strings.xml b/v17/leanback/res/values-zh-rCN/strings.xml
index 17c52b6..fc3fa10 100644
--- a/v17/leanback/res/values-zh-rCN/strings.xml
+++ b/v17/leanback/res/values-zh-rCN/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"关闭高画质模式"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"开启字幕"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"关闭字幕"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"继续"</string>
</resources>
diff --git a/v17/leanback/res/values-zh-rHK/strings.xml b/v17/leanback/res/values-zh-rHK/strings.xml
index 5e87989..7cba4b5 100644
--- a/v17/leanback/res/values-zh-rHK/strings.xml
+++ b/v17/leanback/res/values-zh-rHK/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"停用高畫質"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"啟用字幕"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"停用字幕"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"繼續"</string>
</resources>
diff --git a/v17/leanback/res/values-zh-rTW/strings.xml b/v17/leanback/res/values-zh-rTW/strings.xml
index 67efc40..dcca2db 100644
--- a/v17/leanback/res/values-zh-rTW/strings.xml
+++ b/v17/leanback/res/values-zh-rTW/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"停用高品質播放"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"啟用字幕"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"停用字幕"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"完成"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"繼續"</string>
</resources>
diff --git a/v17/leanback/res/values-zu/strings.xml b/v17/leanback/res/values-zu/strings.xml
index f17455d..f4c589d 100644
--- a/v17/leanback/res/values-zu/strings.xml
+++ b/v17/leanback/res/values-zu/strings.xml
@@ -46,4 +46,6 @@
<string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Khubaza ikhwalithi ephezulu"</string>
<string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Nika amandla imibhalo engezansi"</string>
<string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Khubaza imihbalo engezansi"</string>
+ <string name="lb_guidedaction_finish_title" msgid="4015190340667946245">"Qeda"</string>
+ <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"Qhubeka"</string>
</resources>
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index e7da321..90f010a 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -49,6 +49,10 @@
</declare-styleable>
<declare-styleable name="lbBaseCardView">
+ <!-- Defines the background of card -->
+ <attr name="cardForeground" format="reference|color"/>
+ <!-- Defines the background of card -->
+ <attr name="cardBackground" format="reference|color"/>
<!-- Defines the type of the card layout -->
<attr name="cardType" format="enum">
<!-- A simple card layout with a single layout region. -->
@@ -116,7 +120,23 @@
</declare-styleable>
<declare-styleable name="lbImageCardView">
+ <!-- Deprecated. Use 'lbImageCardViewInfoAreaStyle' instead. -->
<attr name="infoAreaBackground" format="reference|color"/>
+ <!-- Use these attributes to override a ImageCardView's component style. -->
+ <attr name="lbImageCardViewImageStyle" format="reference" />
+ <attr name="lbImageCardViewTitleStyle" format="reference" />
+ <attr name="lbImageCardViewContentStyle" format="reference" />
+ <attr name="lbImageCardViewBadgeStyle" format="reference" />
+ <attr name="lbImageCardViewInfoAreaStyle" format="reference" />
+ <!-- Defines what components the ImageCardView will use. -->
+ <attr name="lbImageCardViewType">
+ <flag name="Title" value="1" />
+ <flag name="Content" value="2" />
+ <flag name="IconOnRight" value="4" />
+ <flag name="IconOnLeft" value="8" />
+ <!-- Only display the main image. -->
+ <flag name="ImageOnly" value="0" />
+ </attr>
</declare-styleable>
<declare-styleable name="lbSearchOrbView">
@@ -258,6 +278,12 @@
b) SDK < 21: set the brand color explicitly via defaultBrandColor, or programatically.
-->
<attr name="defaultBrandColor" format="reference|color" />
+ <!-- Default dark brand color used for the background of certain leanback visual elements
+ such as the actions background. If your app runs on:
+ a) SDK 21+: set colorPrimaryDark, used by the leanback launcher and elsewhere, and defaultBrandColorDark will inherit it.
+ b) SDK < 21: set the brand color explicitly via defaultBrandColorDark, or programatically.
+ -->
+ <attr name="defaultBrandColorDark" format="reference|color" />
<!-- Default colors -->
<attr name="defaultSearchColor" format="reference|color" />
@@ -292,27 +318,18 @@
Theme attribute used to inspect theme inheritance. -->
<attr name="guidedStepThemeFlag" format="boolean" />
- <!-- Theme attribute for the animation used when a guided step element is animated in on
- fragment stack push. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedstep_slide_in_from_end}. -->
- <attr name="guidedStepEntryAnimation" format="reference" />
- <!-- Theme attribute for the animation used when a guided step element is animated out on
- fragment stack push. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedstep_slide_out_to_start}. -->
- <attr name="guidedStepExitAnimation" format="reference" />
- <!-- Theme attribute for the animation used when a guided step element is animated in on
- fragment stack pop. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedstep_slide_in_from_start}. -->
- <attr name="guidedStepReentryAnimation" format="reference" />
- <!-- Theme attribute for the animation used when a guided step element is animated out on
- fragment stack pop. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedstep_slide_out_to_end}. -->
- <attr name="guidedStepReturnAnimation" format="reference" />
+ <!-- Theme attribute of background drawable used by GuidedStepFragment. -->
+ <attr name="guidedStepBackground" format="reference|color" />
- <!-- Theme attribute for the animation used when the guidance is animated in at activity
- start. Default is {@link android.support.v17.leanback.R.animator#lb_guidance_entry}.
- -->
- <attr name="guidanceEntryAnimation" format="reference" />
+ <!-- Theme attribute for the animation used when a guided step element is animated in
+ response to the IME appearing. Default is {@link
+ android.support.v17.leanback.R.animator#lb_guidedstep_slide_up}. -->
+ <attr name="guidedStepImeAppearingAnimation" format="reference" />
+ <!-- Theme attribute for the animation used when a guided step element is animated in
+ response to the IME disappearing. Default is {@link
+ android.support.v17.leanback.R.animator#lb_guidedstep_slide_down}. -->
+ <attr name="guidedStepImeDisappearingAnimation" format="reference" />
+
<!-- Theme attribute for the style of the main container in a GuidanceStylist. Default is
{@link android.support.v17.leanback.R.style#Widget_Leanback_GuidanceContainerStyle}.-->
<attr name="guidanceContainerStyle" format="reference" />
@@ -329,10 +346,6 @@
{@link android.support.v17.leanback.R.style#Widget_Leanback_GuidanceIconStyle}. -->
<attr name="guidanceIconStyle" format="reference" />
- <!-- Theme attribute for the animation used in a GuidedActionsPresenter when the actions
- list is animated in at activity start. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedactions_entry}. -->
- <attr name="guidedActionsEntryAnimation" format="reference" />
<!-- Theme attribute for the animation used in a GuidedActionsPresenter when the action
selector is animated in at activity start. Default is {@link
android.support.v17.leanback.R.animator#lb_guidedactions_selector_show}. -->
@@ -341,12 +354,22 @@
selector is animated in at activity start. Default is {@link
android.support.v17.leanback.R.animator#lb_guidedactions_selector_hide}. -->
<attr name="guidedActionsSelectorHideAnimation" format="reference" />
- <!-- Theme attribute for the style of the container in a GuidedActionsPresenter. Default is
- {@link android.support.v17.leanback.R.style#Widget_Leanback_GuidedActionsContainerStyle}. -->
- <attr name="guidedActionsContainerStyle" format="reference" />
<!-- Theme attribute for the style of the item selector in a GuidedActionsPresenter. Default is
{@link android.support.v17.leanback.R.style#Widget_Leanback_GuidedActionsSelectorStyle}. -->
<attr name="guidedActionsSelectorStyle" format="reference" />
+
+ <!-- Theme attribute for the shadow elevation of GuidedActions. Default is
+ {@link android.support.v17.leanback.R.dimen#lb_guidedactions_elevation}.-->
+ <attr name="guidedActionsElevation" format="dimension|reference" />
+
+ <!-- Theme attribute for the background of GuidedActions. Default is
+ {@link android.support.v17.leanback.R.color#lb_guidedactions_background}.-->
+ <attr name="guidedActionsBackground" format="reference" />
+
+ <!-- Theme attribute for the dark version background of GuidedActions. Default is
+ {@link android.support.v17.leanback.R.color#lb_guidedactions_background_dark}.-->
+ <attr name="guidedActionsBackgroundDark" format="reference" />
+
<!-- Theme attribute for the style of the list in a GuidedActionsPresenter. Default is
{@link android.support.v17.leanback.R.style#Widget_Leanback_GuidedActionsListStyle}.-->
<attr name="guidedActionsListStyle" format="reference" />
@@ -381,14 +404,6 @@
<attr name="guidedActionItemChevronStyle" format="reference" />
<!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
- is checked. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedactions_item_checked}. -->
- <attr name="guidedActionCheckedAnimation" format="reference" />
- <!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
- is unchecked. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedactions_item_unchecked}. -->
- <attr name="guidedActionUncheckedAnimation" format="reference" />
- <!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
is pressed. Default is {@link
android.support.v17.leanback.R.animator#lb_guidedactions_item_pressed}. -->
<attr name="guidedActionPressedAnimation" format="reference" />
@@ -404,14 +419,12 @@
decoration when its action is disabled. Default is {@link
android.support.v17.leanback.R.string#lb_guidedactions_item_disabled_chevron_alpha}. -->
<attr name="guidedActionDisabledChevronAlpha" format="reference" />
- <!-- Theme attribute used in a GuidedActionsPresenter for the width of the text area of
- a single action when there is an icon present. Default is {@link
- android.support.v17.leanback.R.dimen#lb_guidedactions_item_text_width}. -->
- <attr name="guidedActionContentWidth" format="reference" />
- <!-- Theme attribute used in a GuidedActionsPresenter for the width of the text area of
- a single action when there is no icon present. Default is {@link
- android.support.v17.leanback.R.dimen#lb_guidedactions_item_text_width_no_icon}. -->
- <attr name="guidedActionContentWidthNoIcon" format="reference" />
+ <!-- Theme attribute used for the weight of actions. Default is {@link
+ android.support.v17.leanback.R.string#lb_guidedactions_width_weight}. -->
+ <attr name="guidedActionContentWidthWeight" format="reference" />
+ <!-- Theme attribute used for the weight of actions when there are two panels. Default is {@link
+ android.support.v17.leanback.R.string#lb_guidedactions_width_weight_two_panels}. -->
+ <attr name="guidedActionContentWidthWeightTwoPanels" format="reference" />
<!-- Theme attribute used in a GuidedActionsPresenter for the max lines of the title text
view when the action's isMultilineDescription is set to false. Default is {@link
android.support.v17.leanback.R.integer#lb_guidedactions_item_title_min_lines}. -->
@@ -431,4 +444,4 @@
</declare-styleable>
-</resources>
+</resources>
\ No newline at end of file
diff --git a/v17/leanback/res/values/colors.xml b/v17/leanback/res/values/colors.xml
index e63c58b..858ace5 100644
--- a/v17/leanback/res/values/colors.xml
+++ b/v17/leanback/res/values/colors.xml
@@ -52,6 +52,7 @@
<color name="lb_basic_card_content_text_color">#B3EEEEEE</color>
<color name="lb_default_brand_color">#FF455A64</color>
+ <color name="lb_default_brand_color_dark">#FF222D32</color>
<color name="lb_default_search_color">#FFFFAA3F</color>
<color name="lb_control_button_color">#66EEEEEE</color>
@@ -71,6 +72,7 @@
<!-- refactor naming here -->
<color name="lb_guidedactions_background">#FF111111</color>
+ <color name="lb_guidedactions_background_dark">#FF080808</color>
<color name="lb_guidedactions_selector_color">#26FFFFFF</color>
<color name="lb_guidedactions_item_unselected_text_color">#FFF1F1F1</color>
<!-- end refactor naming -->
diff --git a/v17/leanback/res/values/dimens.xml b/v17/leanback/res/values/dimens.xml
index 275612e..053c7e0 100644
--- a/v17/leanback/res/values/dimens.xml
+++ b/v17/leanback/res/values/dimens.xml
@@ -180,7 +180,7 @@
<!-- Search Fragment -->
- <dimen name="lb_search_browse_rows_align_top">120dp</dimen>
+ <dimen name="lb_search_browse_rows_align_top">147dp</dimen>
<dimen name="lb_search_browse_row_padding_start">56dp</dimen>
<dimen name="lb_search_orb_size">52dp</dimen>
@@ -203,6 +203,7 @@
<dimen name="lb_basic_card_info_height">52dp</dimen>
<dimen name="lb_basic_card_info_height_no_content">34dp</dimen>
<dimen name="lb_basic_card_info_padding_top">7dp</dimen>
+ <dimen name="lb_basic_card_info_padding_bottom">8dp</dimen>
<dimen name="lb_basic_card_info_padding_horizontal">11dp</dimen>
<dimen name="lb_basic_card_info_text_margin">1dp</dimen>
<dimen name="lb_basic_card_title_text_size">14sp</dimen>
@@ -223,19 +224,22 @@
<dimen name="lb_rounded_rect_corner_radius">2dp</dimen>
<!-- GuidedStepFragment -->
- <dimen name="lb_guidedstep_guidance_section_width">576dp</dimen>
<dimen name="lb_guidedstep_slide_start_distance">-200dp</dimen>
<dimen name="lb_guidedstep_slide_end_distance">200dp</dimen>
+ <dimen name="lb_guidedstep_slide_ime_distance">-100dp</dimen>
<dimen name="lb_guidance_entry_translationX">-120dp</dimen>
<dimen name="lb_guidedactions_entry_translationX">384dp</dimen>
- <dimen name="lb_guidedactions_section_width">384dp</dimen>
- <dimen name="lb_guidedactions_section_width_with_shadow">400dp</dimen>
+ <item name="lb_guidedactions_width_weight" format="float" type="string">0.666666667</item>
+ <item name="lb_guidedactions_width_weight_two_panels" format="float" type="string">1</item>
+ <dimen name="lb_guidedactions_section_shadow_width">16dp</dimen>
<dimen name="lb_guidedactions_elevation">12dp</dimen>
<dimen name="lb_guidedactions_selector_min_height">8dp</dimen>
<dimen name="lb_guidedactions_vertical_padding">12dp</dimen>
+ <item name="lb_guidedactions_item_disabled_text_alpha" format="float" type="string">0.25</item>
+ <item name="lb_guidedactions_item_disabled_description_text_alpha" format="float" type="string">0.25</item>
<item name="lb_guidedactions_item_unselected_text_alpha" format="float" type="string">1.00</item>
<item name="lb_guidedactions_item_unselected_description_text_alpha" format="float" type="string">0.50</item>
<item name="lb_guidedactions_item_enabled_chevron_alpha" format="float" type="string">1.00</item>
@@ -244,10 +248,10 @@
<dimen name="lb_guidedactions_item_text_width">248dp</dimen>
<dimen name="lb_guidedactions_item_text_width_no_icon">284dp</dimen>
<dimen name="lb_guidedactions_item_min_height">64dp</dimen>
- <dimen name="lb_guidedactions_item_start_padding">20dp</dimen>
+ <dimen name="lb_guidedactions_item_start_padding">28dp</dimen>
<dimen name="lb_guidedactions_item_end_padding">28dp</dimen>
<dimen name="lb_guidedactions_item_delimiter_padding">4dp</dimen>
- <dimen name="lb_guidedactions_item_checkmark_diameter">8dp</dimen>
+ <dimen name="lb_guidedactions_item_checkmark_diameter">16dp</dimen>
<dimen name="lb_guidedactions_item_icon_width">32dp</dimen>
<dimen name="lb_guidedactions_item_icon_height">32dp</dimen>
<dimen name="lb_guidedactions_item_title_font_size">18sp</dimen>
diff --git a/v17/leanback/res/values/ids.xml b/v17/leanback/res/values/ids.xml
index 6b67919..ca84efc8 100644
--- a/v17/leanback/res/values/ids.xml
+++ b/v17/leanback/res/values/ids.xml
@@ -16,7 +16,11 @@
-->
<resources>
<item type="id" name="lb_focus_animator" />
+ <item type="id" name="lb_shadow_impl" />
<item type="id" name="lb_slide_transition_value" />
+ <item type="id" name="transitionPosition" />
+
+ <item type="id" name="lb_guidedstep_background" />
<item type="id" name="lb_control_play_pause" />
<item type="id" name="lb_control_fast_forward" />
@@ -31,4 +35,10 @@
<item type="id" name="lb_control_high_quality" />
<item type="id" name="lb_control_closed_captioning" />
- </resources>
+ <item type="id" name="guidedactions_root2" />
+ <item type="id" name="guidedactions_list_background2" />
+ <item type="id" name="guidedactions_list2" />
+ <item type="id" name="guidedactions_selector2" />
+ <item type="id" name="guidedactions_content2" />
+
+</resources>
diff --git a/v17/leanback/res/values/integers.xml b/v17/leanback/res/values/integers.xml
index 8547e22..c9f3384 100644
--- a/v17/leanback/res/values/integers.xml
+++ b/v17/leanback/res/values/integers.xml
@@ -29,4 +29,11 @@
<integer name="lb_playback_rows_fade_out_ms">250</integer>
<integer name="lb_playback_rows_fade_delay_ms">100</integer>
<integer name="lb_playback_controls_show_time_ms">3000</integer>
+
+ <!-- Gravity.LEFT -->
+ <integer name="slideEdgeStart">3</integer>
+ <!-- Gravity.RIGHT -->
+ <integer name="slideEdgeEnd">5</integer>
+
+ <integer name="lb_guidedstep_activity_background_fade_duration_ms">350</integer>
</resources>
diff --git a/v17/leanback/res/values/strings.xml b/v17/leanback/res/values/strings.xml
index 2cd0ff11..3d93db2 100644
--- a/v17/leanback/res/values/strings.xml
+++ b/v17/leanback/res/values/strings.xml
@@ -75,4 +75,8 @@
<!-- Talkback label for the control button to disable closed captioning -->
<string name="lb_playback_controls_closed_captioning_disable">Disable Closed Captioning</string>
+ <!-- Title of standard Finish action for GuidedStepFragment -->
+ <string name="lb_guidedaction_finish_title">Finish</string>
+ <!-- Title of standard Continue action for GuidedStepFragment -->
+ <string name="lb_guidedaction_continue_title">Continue</string>
</resources>
diff --git a/v17/leanback/res/values/styles.xml b/v17/leanback/res/values/styles.xml
index 3ee2821..3904467 100644
--- a/v17/leanback/res/values/styles.xml
+++ b/v17/leanback/res/values/styles.xml
@@ -87,14 +87,8 @@
<style name="Widget.Leanback" parent="Widget.LeanbackBase" />
<style name="Widget.Leanback.BaseCardViewStyle">
- <item name="android:foreground">@drawable/lb_card_foreground</item>
- </style>
-
- <style name="Widget.Leanback.ImageCardViewStyle" parent="Widget.Leanback.BaseCardViewStyle">
- <item name="cardType">infoUnder</item>
- <item name="infoVisibility">activated</item>
- <item name="android:background">@color/lb_basic_card_bg_color</item>
- <item name="infoAreaBackground">@color/lb_basic_card_info_bg_color</item>
+ <item name="cardForeground">@drawable/lb_card_foreground</item>
+ <item name="cardBackground">@color/lb_basic_card_bg_color</item>
</style>
<style name="Widget.Leanback.TitleView" >
@@ -104,6 +98,77 @@
<item name="android:paddingEnd">?attr/browsePaddingEnd</item>
</style>
+ <style name="Widget.Leanback.ImageCardViewStyle" parent="Widget.Leanback.BaseCardViewStyle">
+ <item name="cardType">infoUnder</item>
+ <item name="infoVisibility">activated</item>
+ <!-- In order to keep backward compatibility we have to create an icon on right. -->
+ <item name="lbImageCardViewType">Title|Content|IconOnRight</item>
+ <item name="lbImageCardViewImageStyle">@style/Widget.Leanback.ImageCardView.ImageStyle</item>
+ <item name="lbImageCardViewTitleStyle">@style/Widget.Leanback.ImageCardView.TitleStyle</item>
+ <item name="lbImageCardViewContentStyle">@style/Widget.Leanback.ImageCardView.ContentStyle</item>
+ <item name="lbImageCardViewBadgeStyle">@style/Widget.Leanback.ImageCardView.BadgeStyle</item>
+ <item name="lbImageCardViewInfoAreaStyle">@style/Widget.Leanback.ImageCardView.InfoAreaStyle</item>
+ <!-- Deprecated. Use 'Widget.Leanback.ImageCardView.InfoAreaStyle' instead. -->
+ <item name="infoAreaBackground">@null</item>
+ </style>
+
+ <style name="Widget.Leanback.ImageCardView" />
+
+ <style name="Widget.Leanback.ImageCardView.ImageStyle">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:adjustViewBounds">true</item>
+ <item name="android:contentDescription">@null</item>
+ <item name="android:scaleType">centerCrop</item>
+ <item name="layout_viewType">main</item>
+ </style>
+
+ <style name="Widget.Leanback.ImageCardView.InfoAreaStyle">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_centerHorizontal">true</item>
+ <item name="layout_viewType">info</item>
+ <item name="android:paddingBottom">@dimen/lb_basic_card_info_padding_bottom</item>
+ <item name="android:paddingEnd">@dimen/lb_basic_card_info_padding_horizontal</item>
+ <item name="android:paddingStart">@dimen/lb_basic_card_info_padding_horizontal</item>
+ <item name="android:paddingTop">@dimen/lb_basic_card_info_padding_top</item>
+ <item name="android:background">@color/lb_basic_card_info_bg_color</item>
+ </style>
+
+ <style name="Widget.Leanback.ImageCardView.TitleStyle">
+ <item name="android:id">@id/title_text</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:maxLines">1</item>
+ <item name="android:layout_marginBottom">@dimen/lb_basic_card_info_text_margin</item>
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:textColor">@color/lb_basic_card_title_text_color</item>
+ <item name="android:textSize">@dimen/lb_basic_card_title_text_size</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="Widget.Leanback.ImageCardView.ContentStyle">
+ <item name="android:id">@id/content_text</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentStart">true</item>
+ <item name="android:layout_below">@+id/title_text</item>
+ <item name="android:layout_toStartOf">@+id/extra_badge</item>
+ <item name="android:maxLines">1</item>
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:textColor">@color/lb_basic_card_content_text_color</item>
+ <item name="android:textSize">@dimen/lb_basic_card_content_text_size</item>
+ <item name="android:ellipsize">none</item>
+ </style>
+
+ <style name="Widget.Leanback.ImageCardView.BadgeStyle">
+ <item name="android:id">@id/extra_badge</item>
+ <item name="android:layout_width">@dimen/lb_basic_card_info_badge_size</item>
+ <item name="android:layout_height">@dimen/lb_basic_card_info_badge_size</item>
+ <item name="android:contentDescription">@null</item>
+ <item name="android:scaleType">fitCenter</item>
+ </style>
+
<style name="Widget.Leanback.Title" />
<style name="Widget.Leanback.Title.Text">
@@ -130,6 +195,7 @@
<style name="Widget.Leanback.GridItems" />
<style name="Widget.Leanback.Headers.VerticalGridView" >
+ <item name="android:background">?attr/defaultBrandColor</item>
<item name="android:paddingStart">?attr/browsePaddingStart</item>
<item name="focusOutFront">true</item>
<item name="focusOutEnd">true</item>
@@ -357,21 +423,11 @@
<item name="android:scaleType">fitCenter</item>
</style>
- <!-- Style for the container view in a GuidedActionsStylist's default layout. -->
- <style name="Widget.Leanback.GuidedActionsContainerStyle">
- <item name="android:layout_width">@dimen/lb_guidedactions_section_width</item>
- <item name="android:layout_height">match_parent</item>
- <item name="android:layout_alignParentEnd">true</item>
- <item name="android:background">@color/lb_guidedactions_background</item>
- <item name="android:elevation">@dimen/lb_guidedactions_elevation</item>
- </style>
-
<!-- Style for the selector view in a GuidedActionsStylist's default layout. -->
<style name="Widget.Leanback.GuidedActionsSelectorStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">@dimen/lb_guidedactions_selector_min_height</item>
<item name="android:layout_centerVertical">true</item>
- <item name="android:alpha">0</item>
<item name="android:background">@color/lb_guidedactions_selector_color</item>
</style>
@@ -401,9 +457,8 @@
<item name="android:layout_height">@dimen/lb_guidedactions_item_checkmark_diameter</item>
<item name="android:layout_gravity">center</item>
<item name="android:layout_marginEnd">@dimen/lb_guidedactions_item_delimiter_padding</item>
- <item name="android:scaleType">center</item>
- <item name="android:src">@drawable/lb_guidedactions_item_checkmark</item>
- <item name="android:visibility">invisible</item>
+ <item name="android:scaleType">centerInside</item>
+ <item name="android:visibility">gone</item>
</style>
<!-- Style for an action's icon in a GuidedActionsStylist's default item layout. -->
@@ -418,7 +473,7 @@
<!-- Style for an action's text content in a GuidedActionsStylist's default item layout. -->
<style name="Widget.Leanback.GuidedActionItemContentStyle">
- <item name="android:layout_width">0dp</item>
+ <item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">start|center_vertical</item>
<item name="android:layout_weight">1</item>
@@ -430,11 +485,12 @@
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:alpha">@string/lb_guidedactions_item_unselected_text_alpha</item>
- <item name="android:ellipsize">marquee</item>
+ <item name="android:ellipsize">end</item>
<item name="android:fontFamily">sans-serif-condensed</item>
<item name="android:maxLines">@integer/lb_guidedactions_item_title_min_lines</item>
<item name="android:textColor">@color/lb_guidedactions_item_unselected_text_color</item>
<item name="android:textSize">@dimen/lb_guidedactions_item_title_font_size</item>
+ <item name="android:background">@null</item>
</style>
<!-- Style for an action's description in a GuidedActionsStylist's default item layout. -->
@@ -442,12 +498,13 @@
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:alpha">@string/lb_guidedactions_item_unselected_description_text_alpha</item>
- <item name="android:ellipsize">marquee</item>
+ <item name="android:ellipsize">end</item>
<item name="android:fontFamily">sans-serif-condensed</item>
<item name="android:maxLines">@integer/lb_guidedactions_item_description_min_lines</item>
<item name="android:textColor">@color/lb_guidedactions_item_unselected_text_color</item>
<item name="android:textSize">@dimen/lb_guidedactions_item_description_font_size</item>
<item name="android:visibility">gone</item>
+ <item name="android:background">@null</item>
</style>
<!-- Style for an action's chevron in a GuidedActionsStylist's default item layout. -->
diff --git a/v17/leanback/res/values/themes.xml b/v17/leanback/res/values/themes.xml
index 8178c50..36362dd 100644
--- a/v17/leanback/res/values/themes.xml
+++ b/v17/leanback/res/values/themes.xml
@@ -15,13 +15,14 @@
limitations under the License.
-->
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- LeanbackBase may be overridden for specific api levels -->
<style name="Theme.LeanbackBase" parent="android:Theme.Holo.NoActionBar">
<item name="playbackProgressPrimaryColor">@color/lb_playback_progress_color_no_theme</item>
<item name="playbackControlsIconHighlightColor">@color/lb_playback_icon_highlight_no_theme</item>
<item name="defaultBrandColor">@color/lb_default_brand_color</item>
+ <item name="defaultBrandColorDark">@color/lb_default_brand_color_dark</item>
<item name="android:windowOverscan">true</item>
<item name="guidedStepTheme">@style/Theme.Leanback.GuidedStep</item>
@@ -95,6 +96,11 @@
<item name="android:windowReturnTransition">@transition/lb_browse_return_transition</item>
</style>
+ <style name="Theme.Leanback.VerticalGrid" parent="Theme.Leanback">
+ <item name="android:windowEnterTransition">@transition/lb_vertical_grid_enter_transition</item>
+ <item name="android:windowReturnTransition">@transition/lb_vertical_grid_return_transition</item>
+ </style>
+
<style name="Theme.Leanback.Details" parent="Theme.Leanback">
<item name="android:windowEnterTransition">@transition/lb_details_enter_transition</item>
<item name="android:windowReturnTransition">@transition/lb_details_return_transition</item>
@@ -111,12 +117,18 @@
<style name="Theme.Leanback.GuidedStep" parent="Theme.LeanbackBase">
<item name="guidedStepThemeFlag">true</item>
- <item name="guidedStepEntryAnimation">@animator/lb_guidedstep_slide_in_from_end</item>
- <item name="guidedStepExitAnimation">@animator/lb_guidedstep_slide_out_to_start</item>
- <item name="guidedStepReentryAnimation">@animator/lb_guidedstep_slide_in_from_start</item>
- <item name="guidedStepReturnAnimation">@animator/lb_guidedstep_slide_out_to_end</item>
- <item name="guidanceEntryAnimation">@animator/lb_guidance_entry</item>
- <item name="guidedActionsEntryAnimation">@animator/lb_guidedactions_entry</item>
+ <item name="android:windowEnterTransition">@transition/lb_guidedstep_activity_enter</item>
+
+ <!-- background applied to each GuidedStepFragment by default-->
+ <item name="guidedStepBackground">?android:attr/colorBackground</item>
+ <!-- Each GuidedStepFragment has a background so activity does not need a background.
+ But We still need a dumb background to keep the temporary translucent state last
+ as long as the background view fade-in transition -->
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowTransitionBackgroundFadeDuration">@integer/lb_guidedstep_activity_background_fade_duration_ms</item>
+
+ <item name="guidedStepImeAppearingAnimation">@animator/lb_guidedstep_slide_up</item>
+ <item name="guidedStepImeDisappearingAnimation">@animator/lb_guidedstep_slide_down</item>
<item name="guidanceContainerStyle">@style/Widget.Leanback.GuidanceContainerStyle</item>
<item name="guidanceIconStyle">@style/Widget.Leanback.GuidanceIconStyle</item>
@@ -124,7 +136,9 @@
<item name="guidanceBreadcrumbStyle">@style/Widget.Leanback.GuidanceBreadcrumbStyle</item>
<item name="guidanceDescriptionStyle">@style/Widget.Leanback.GuidanceDescriptionStyle</item>
- <item name="guidedActionsContainerStyle">@style/Widget.Leanback.GuidedActionsContainerStyle</item>
+ <item name="guidedActionsElevation">@dimen/lb_guidedactions_elevation</item>
+ <item name="guidedActionsBackground">@color/lb_guidedactions_background</item>
+ <item name="guidedActionsBackgroundDark">@color/lb_guidedactions_background_dark</item>
<item name="guidedActionsSelectorStyle">@style/Widget.Leanback.GuidedActionsSelectorStyle</item>
<item name="guidedActionsListStyle">@style/Widget.Leanback.GuidedActionsListStyle</item>
<item name="guidedActionsSelectorShowAnimation">@animator/lb_guidedactions_selector_show</item>
@@ -138,14 +152,12 @@
<item name="guidedActionItemDescriptionStyle">@style/Widget.Leanback.GuidedActionItemDescriptionStyle</item>
<item name="guidedActionItemChevronStyle">@style/Widget.Leanback.GuidedActionItemChevronStyle</item>
- <item name="guidedActionCheckedAnimation">@animator/lb_guidedactions_item_checked</item>
- <item name="guidedActionUncheckedAnimation">@animator/lb_guidedactions_item_unchecked</item>
<item name="guidedActionPressedAnimation">@animator/lb_guidedactions_item_pressed</item>
<item name="guidedActionUnpressedAnimation">@animator/lb_guidedactions_item_unpressed</item>
<item name="guidedActionEnabledChevronAlpha">@string/lb_guidedactions_item_enabled_chevron_alpha</item>
<item name="guidedActionDisabledChevronAlpha">@string/lb_guidedactions_item_disabled_chevron_alpha</item>
- <item name="guidedActionContentWidth">@dimen/lb_guidedactions_item_text_width</item>
- <item name="guidedActionContentWidthNoIcon">@dimen/lb_guidedactions_item_text_width_no_icon</item>
+ <item name="guidedActionContentWidthWeight">@string/lb_guidedactions_width_weight</item>
+ <item name="guidedActionContentWidthWeightTwoPanels">@string/lb_guidedactions_width_weight_two_panels</item>
<item name="guidedActionTitleMinLines">@integer/lb_guidedactions_item_title_min_lines</item>
<item name="guidedActionTitleMaxLines">@integer/lb_guidedactions_item_title_max_lines</item>
<item name="guidedActionDescriptionMinLines">@integer/lb_guidedactions_item_description_min_lines</item>
diff --git a/v17/leanback/src/android/support/v17/leanback/animation/UntargetableAnimatorSet.java b/v17/leanback/src/android/support/v17/leanback/animation/UntargetableAnimatorSet.java
deleted file mode 100644
index 9cdbc0c..0000000
--- a/v17/leanback/src/android/support/v17/leanback/animation/UntargetableAnimatorSet.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.
- */
-package android.support.v17.leanback.animation;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.TimeInterpolator;
-
-import java.util.ArrayList;
-
-/**
- * Custom fragment animations supplied by Fragment.onCreateAnimator have their targets set to the
- * fragment's main view by the fragment manager. Sometimes, this isn't what you want; you may be
- * supplying a heterogeneous collection of animations that already have targets. This class helps
- * you return such a collection of animations from onCreateAnimator without having their targets
- * reset.
- *
- * Note that one does not simply subclass AnimatorSet and override setTarget() because AnimatorSet
- * is final.
- * @hide
- */
-public class UntargetableAnimatorSet extends Animator {
-
- private final AnimatorSet mAnimatorSet;
-
- public UntargetableAnimatorSet(AnimatorSet animatorSet) {
- mAnimatorSet = animatorSet;
- }
-
- @Override
- public void addListener(Animator.AnimatorListener listener) {
- mAnimatorSet.addListener(listener);
- }
-
- @Override
- public void cancel() {
- mAnimatorSet.cancel();
- }
-
- @Override
- public Animator clone() {
- return mAnimatorSet.clone();
- }
-
- @Override
- public void end() {
- mAnimatorSet.end();
- }
-
- @Override
- public long getDuration() {
- return mAnimatorSet.getDuration();
- }
-
- @Override
- public ArrayList<Animator.AnimatorListener> getListeners() {
- return mAnimatorSet.getListeners();
- }
-
- @Override
- public long getStartDelay() {
- return mAnimatorSet.getStartDelay();
- }
-
- @Override
- public boolean isRunning() {
- return mAnimatorSet.isRunning();
- }
-
- @Override
- public boolean isStarted() {
- return mAnimatorSet.isStarted();
- }
-
- @Override
- public void removeAllListeners() {
- mAnimatorSet.removeAllListeners();
- }
-
- @Override
- public void removeListener(Animator.AnimatorListener listener) {
- mAnimatorSet.removeListener(listener);
- }
-
- @Override
- public Animator setDuration(long duration) {
- return mAnimatorSet.setDuration(duration);
- }
-
- @Override
- public void setInterpolator(TimeInterpolator value) {
- mAnimatorSet.setInterpolator(value);
- }
-
- @Override
- public void setStartDelay(long startDelay) {
- mAnimatorSet.setStartDelay(startDelay);
- }
-
- @Override
- public void setTarget(Object target) {
- // ignore
- }
-
- @Override
- public void setupEndValues() {
- mAnimatorSet.setupEndValues();
- }
-
- @Override
- public void setupStartValues() {
- mAnimatorSet.setupStartValues();
- }
-
- @Override
- public void start() {
- mAnimatorSet.start();
- }
-}
-
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
index 5b2deac..c878a86 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
@@ -30,8 +30,6 @@
private boolean mEntranceTransitionPreparePending = false;
private Object mEntranceTransition;
- static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
-
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -176,7 +174,7 @@
if (mEntranceTransition == null) {
return;
}
- sTransitionHelper.setTransitionListener(mEntranceTransition, new TransitionListener() {
+ TransitionHelper.addTransitionListener(mEntranceTransition, new TransitionListener() {
@Override
public void onTransitionEnd(Object transition) {
mEntranceTransition = null;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
index a72bb5b..b9c7d58 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
@@ -32,8 +32,6 @@
private boolean mEntranceTransitionPreparePending = false;
private Object mEntranceTransition;
- static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
-
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -178,7 +176,7 @@
if (mEntranceTransition == null) {
return;
}
- sTransitionHelper.setTransitionListener(mEntranceTransition, new TransitionListener() {
+ TransitionHelper.addTransitionListener(mEntranceTransition, new TransitionListener() {
@Override
public void onTransitionEnd(Object transition) {
mEntranceTransition = null;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
index 7e8f02f..8c417a4 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -425,7 +425,7 @@
if (mBrowseTransitionListener != null) {
mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
}
- sTransitionHelper.runTransition(withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders,
+ TransitionHelper.runTransition(withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders,
mHeadersTransition);
if (mHeadersBackStackEnabled) {
if (!withHeaders) {
@@ -622,19 +622,19 @@
mHeadersFragment.setBackgroundColor(mBrandColor);
}
- mSceneWithHeaders = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+ mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
@Override
public void run() {
showHeaders(true);
}
});
- mSceneWithoutHeaders = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+ mSceneWithoutHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
@Override
public void run() {
showHeaders(false);
}
});
- mSceneAfterEntranceTransition = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+ mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
@Override
public void run() {
setEntranceTransitionEndState();
@@ -644,11 +644,11 @@
}
private void createHeadersTransition() {
- mHeadersTransition = sTransitionHelper.loadTransition(getActivity(),
+ mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
mShowingHeaders ?
R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
- sTransitionHelper.setTransitionListener(mHeadersTransition, new TransitionListener() {
+ TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
@Override
public void onTransitionStart(Object transition) {
}
@@ -891,14 +891,13 @@
@Override
protected Object createEntranceTransition() {
- return sTransitionHelper.loadTransition(getActivity(),
+ return TransitionHelper.loadTransition(getActivity(),
R.transition.lb_browse_entrance_transition);
}
@Override
protected void runEntranceTransition(Object entranceTransition) {
- sTransitionHelper.runTransition(mSceneAfterEntranceTransition,
- entranceTransition);
+ TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
}
@Override
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
index 44deec4..fa7f61e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -427,7 +427,7 @@
if (mBrowseTransitionListener != null) {
mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
}
- sTransitionHelper.runTransition(withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders,
+ TransitionHelper.runTransition(withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders,
mHeadersTransition);
if (mHeadersBackStackEnabled) {
if (!withHeaders) {
@@ -624,19 +624,19 @@
mHeadersSupportFragment.setBackgroundColor(mBrandColor);
}
- mSceneWithHeaders = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+ mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
@Override
public void run() {
showHeaders(true);
}
});
- mSceneWithoutHeaders = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+ mSceneWithoutHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
@Override
public void run() {
showHeaders(false);
}
});
- mSceneAfterEntranceTransition = sTransitionHelper.createScene(mBrowseFrame, new Runnable() {
+ mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
@Override
public void run() {
setEntranceTransitionEndState();
@@ -646,11 +646,11 @@
}
private void createHeadersTransition() {
- mHeadersTransition = sTransitionHelper.loadTransition(getActivity(),
+ mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
mShowingHeaders ?
R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
- sTransitionHelper.setTransitionListener(mHeadersTransition, new TransitionListener() {
+ TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
@Override
public void onTransitionStart(Object transition) {
}
@@ -893,14 +893,13 @@
@Override
protected Object createEntranceTransition() {
- return sTransitionHelper.loadTransition(getActivity(),
+ return TransitionHelper.loadTransition(getActivity(),
R.transition.lb_browse_entrance_transition);
}
@Override
protected void runEntranceTransition(Object entranceTransition) {
- sTransitionHelper.runTransition(mSceneAfterEntranceTransition,
- entranceTransition);
+ TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
}
@Override
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
index d415de0..ddafd5f 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
@@ -14,6 +14,7 @@
package android.support.v17.leanback.app;
import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.widget.BrowseFrameLayout;
import android.support.v17.leanback.widget.DetailsOverviewRow;
import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
@@ -200,7 +201,7 @@
}
}
- mSceneAfterEntranceTransition = sTransitionHelper.createScene(
+ mSceneAfterEntranceTransition = TransitionHelper.createScene(
(ViewGroup) view, new Runnable() {
@Override
public void run() {
@@ -394,25 +395,20 @@
super.onStart();
setupChildFragmentLayout();
setupFocusSearchListener();
- mRowsFragment.getView().requestFocus();
if (isEntranceTransitionEnabled()) {
- // make sure recycler view animation is disabled
- mRowsFragment.onTransitionPrepare();
- mRowsFragment.onTransitionStart();
mRowsFragment.setEntranceTransitionState(false);
}
}
@Override
protected Object createEntranceTransition() {
- return sTransitionHelper.loadTransition(getActivity(),
+ return TransitionHelper.loadTransition(getActivity(),
R.transition.lb_details_enter_transition);
}
@Override
protected void runEntranceTransition(Object entranceTransition) {
- sTransitionHelper.runTransition(mSceneAfterEntranceTransition,
- entranceTransition);
+ TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
}
@Override
@@ -420,4 +416,13 @@
mRowsFragment.onTransitionEnd();
}
+ @Override
+ protected void onEntranceTransitionPrepare() {
+ mRowsFragment.onTransitionPrepare();
+ }
+
+ @Override
+ protected void onEntranceTransitionStart() {
+ mRowsFragment.onTransitionStart();
+ }
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
index afaf5a8..7532d79 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
@@ -16,6 +16,7 @@
package android.support.v17.leanback.app;
import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.widget.BrowseFrameLayout;
import android.support.v17.leanback.widget.DetailsOverviewRow;
import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
@@ -202,7 +203,7 @@
}
}
- mSceneAfterEntranceTransition = sTransitionHelper.createScene(
+ mSceneAfterEntranceTransition = TransitionHelper.createScene(
(ViewGroup) view, new Runnable() {
@Override
public void run() {
@@ -396,25 +397,20 @@
super.onStart();
setupChildFragmentLayout();
setupFocusSearchListener();
- mRowsSupportFragment.getView().requestFocus();
if (isEntranceTransitionEnabled()) {
- // make sure recycler view animation is disabled
- mRowsSupportFragment.onTransitionPrepare();
- mRowsSupportFragment.onTransitionStart();
mRowsSupportFragment.setEntranceTransitionState(false);
}
}
@Override
protected Object createEntranceTransition() {
- return sTransitionHelper.loadTransition(getActivity(),
+ return TransitionHelper.loadTransition(getActivity(),
R.transition.lb_details_enter_transition);
}
@Override
protected void runEntranceTransition(Object entranceTransition) {
- sTransitionHelper.runTransition(mSceneAfterEntranceTransition,
- entranceTransition);
+ TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
}
@Override
@@ -422,4 +418,13 @@
mRowsSupportFragment.onTransitionEnd();
}
+ @Override
+ protected void onEntranceTransitionPrepare() {
+ mRowsSupportFragment.onTransitionPrepare();
+ }
+
+ @Override
+ protected void onEntranceTransitionStart() {
+ mRowsSupportFragment.onTransitionStart();
+ }
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
index 41ecac9..142e971 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
@@ -19,6 +19,7 @@
import android.support.v17.leanback.R;
import android.support.v17.leanback.widget.GuidedAction;
import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.support.v17.leanback.widget.ImeKeyMonitor;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.util.Log;
@@ -26,9 +27,14 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
import java.util.ArrayList;
import java.util.List;
@@ -43,6 +49,9 @@
private static final String TAG = "GuidedActionAdapter";
private static final boolean DEBUG = false;
+ private static final String TAG_EDIT = "EditableAction";
+ private static final boolean DEBUG_EDIT = false;
+
/**
* Object listening for click events within a {@link GuidedActionAdapter}.
*/
@@ -66,11 +75,32 @@
}
/**
+ * Object listening for edit events within a {@link GuidedActionAdapter}.
+ */
+ public interface EditListener {
+
+ /**
+ * Called when the user exits edit mode on an action.
+ */
+ public long onGuidedActionEdited(GuidedAction action);
+
+ /**
+ * Called when Ime Open
+ */
+ public void onImeOpen();
+
+ /**
+ * Called when Ime Close
+ */
+ public void onImeClose();
+ }
+
+ /**
* View holder containing a {@link GuidedAction}.
*/
- private static class ActionViewHolder extends ViewHolder {
+ static class ActionViewHolder extends ViewHolder {
- private final GuidedActionsStylist.ViewHolder mStylistViewHolder;
+ final GuidedActionsStylist.ViewHolder mStylistViewHolder;
private GuidedAction mAction;
/**
@@ -98,30 +128,36 @@
}
}
- private RecyclerView mRecyclerView;
private final ActionOnKeyListener mActionOnKeyListener;
private final ActionOnFocusListener mActionOnFocusListener;
+ private final ActionEditListener mActionEditListener;
private final List<GuidedAction> mActions;
private ClickListener mClickListener;
- private GuidedActionsStylist mStylist;
+ private final GuidedActionsStylist mStylist;
private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- if (v != null && v.getWindowToken() != null && mClickListener != null) {
- ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
+ if (v != null && v.getWindowToken() != null && getRecyclerView() != null) {
+ ActionViewHolder avh = (ActionViewHolder)getRecyclerView().getChildViewHolder(v);
GuidedAction action = avh.getAction();
- if (action.isEnabled() && !action.infoOnly()) {
- mClickListener.onGuidedActionClicked(action);
+ if (action.isEditable() || action.isDescriptionEditable()) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme by click");
+ mGroup.openIme(GuidedActionAdapter.this, avh);
+ } else {
+ handleCheckedActions(avh);
+ if (action.isEnabled() && !action.infoOnly()) {
+ performOnActionClick(avh);
+ }
}
}
}
};
+ GuidedActionAdapterGroup mGroup;
/**
* Constructs a GuidedActionAdapter with the given list of guided actions, the given click and
* focus listeners, and the given presenter.
* @param actions The list of guided actions this adapter will manage.
- * @param clickListener The click listener for items in this adapter.
* @param focusListener The focus listener for items in this adapter.
* @param presenter The presenter that will manage the display of items in this adapter.
*/
@@ -131,8 +167,9 @@
mActions = new ArrayList<GuidedAction>(actions);
mClickListener = clickListener;
mStylist = presenter;
- mActionOnKeyListener = new ActionOnKeyListener(clickListener, mActions);
+ mActionOnKeyListener = new ActionOnKeyListener();
mActionOnFocusListener = new ActionOnFocusListener(focusListener);
+ mActionEditListener = new ActionEditListener();
}
/**
@@ -164,12 +201,27 @@
}
/**
+ * Return index of action in array
+ * @param action Action to search index.
+ * @return Index of Action in array.
+ */
+ public int indexOf(GuidedAction action) {
+ return mActions.indexOf(action);
+ }
+
+ /**
+ * @return GuidedActionsStylist used to build the actions list UI.
+ */
+ public GuidedActionsStylist getGuidedActionsStylist() {
+ return mStylist;
+ }
+
+ /**
* Sets the click listener for items managed by this adapter.
* @param clickListener The click listener for this adapter.
*/
public void setClickListener(ClickListener clickListener) {
mClickListener = clickListener;
- mActionOnKeyListener.setListener(clickListener);
}
/**
@@ -192,16 +244,12 @@
* {@inheritDoc}
*/
@Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mRecyclerView = recyclerView;
+ public int getItemViewType(int position) {
+ return mStylist.getItemViewType(mActions.get(position));
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
- mRecyclerView = null;
+ private RecyclerView getRecyclerView() {
+ return mStylist.getActionsGridView();
}
/**
@@ -209,15 +257,29 @@
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- GuidedActionsStylist.ViewHolder vh = mStylist.onCreateViewHolder(parent);
+ GuidedActionsStylist.ViewHolder vh = mStylist.onCreateViewHolder(parent, viewType);
View v = vh.view;
v.setOnKeyListener(mActionOnKeyListener);
v.setOnClickListener(mOnClickListener);
v.setOnFocusChangeListener(mActionOnFocusListener);
+ setupListeners(vh.getEditableTitleView());
+ setupListeners(vh.getEditableDescriptionView());
+
return new ActionViewHolder(v, vh);
}
+ private void setupListeners(EditText edit) {
+ if (edit != null) {
+ edit.setPrivateImeOptions("EscapeNorth=1;");
+ edit.setOnEditorActionListener(mActionEditListener);
+ if (edit instanceof ImeKeyMonitor) {
+ ImeKeyMonitor monitor = (ImeKeyMonitor)edit;
+ monitor.setImeKeyListener(mActionEditListener);
+ }
+ }
+ }
+
/**
* {@inheritDoc}
*/
@@ -226,7 +288,7 @@
if (position >= mActions.size()) {
return;
}
- ActionViewHolder avh = (ActionViewHolder)holder;
+ final ActionViewHolder avh = (ActionViewHolder)holder;
GuidedAction action = mActions.get(position);
avh.setAction(action);
mStylist.onBindViewHolder(avh.mStylistViewHolder, action);
@@ -254,8 +316,8 @@
}
public void unFocus() {
- if (mSelectedView != null) {
- ViewHolder vh = mRecyclerView.getChildViewHolder(mSelectedView);
+ if (mSelectedView != null && getRecyclerView() != null) {
+ ViewHolder vh = getRecyclerView().getChildViewHolder(mSelectedView);
if (vh != null) {
ActionViewHolder avh = (ActionViewHolder)vh;
mStylist.onAnimateItemFocused(avh.mStylistViewHolder, false);
@@ -268,8 +330,10 @@
@Override
public void onFocusChange(View v, boolean hasFocus) {
- ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
- mStylist.onAnimateItemFocused(avh.mStylistViewHolder, hasFocus);
+ if (getRecyclerView() == null) {
+ return;
+ }
+ ActionViewHolder avh = (ActionViewHolder) getRecyclerView().getChildViewHolder(v);
if (hasFocus) {
mSelectedView = v;
if (mFocusListener != null) {
@@ -279,27 +343,74 @@
}
} else {
if (mSelectedView == v) {
+ mStylist.onAnimateItemPressedCancelled(avh.mStylistViewHolder);
mSelectedView = null;
}
}
+ mStylist.onAnimateItemFocused(avh.mStylistViewHolder, hasFocus);
+ }
+ }
+
+ public ActionViewHolder findSubChildViewHolder(View v) {
+ // Needed because RecyclerView.getChildViewHolder does not traverse the hierarchy
+ if (getRecyclerView() == null) {
+ return null;
+ }
+ ActionViewHolder result = null;
+ ViewParent parent = v.getParent();
+ while (parent != getRecyclerView() && parent != null && v != null) {
+ v = (View)parent;
+ parent = parent.getParent();
+ }
+ if (parent != null && v != null) {
+ result = (ActionViewHolder)getRecyclerView().getChildViewHolder(v);
+ }
+ return result;
+ }
+
+ public void handleCheckedActions(ActionViewHolder avh) {
+ GuidedAction action = avh.getAction();
+ int actionCheckSetId = action.getCheckSetId();
+ if (getRecyclerView() != null && actionCheckSetId != GuidedAction.NO_CHECK_SET) {
+ // Find any actions that are checked and are in the same group
+ // as the selected action. Fade their checkmarks out.
+ if (actionCheckSetId != GuidedAction.CHECKBOX_CHECK_SET_ID) {
+ for (int i = 0, size = mActions.size(); i < size; i++) {
+ GuidedAction a = mActions.get(i);
+ if (a != action && a.getCheckSetId() == actionCheckSetId && a.isChecked()) {
+ a.setChecked(false);
+ ViewHolder vh = getRecyclerView().findViewHolderForPosition(i);
+ if (vh != null) {
+ GuidedActionsStylist.ViewHolder subViewHolder =
+ ((ActionViewHolder)vh).mStylistViewHolder;
+ mStylist.onAnimateItemChecked(subViewHolder, false);
+ }
+ }
+ }
+ }
+
+ // If we we'ren't already checked, fade our checkmark in.
+ if (!action.isChecked()) {
+ action.setChecked(true);
+ mStylist.onAnimateItemChecked(avh.mStylistViewHolder, true);
+ } else {
+ if (actionCheckSetId == GuidedAction.CHECKBOX_CHECK_SET_ID) {
+ action.setChecked(false);
+ mStylist.onAnimateItemChecked(avh.mStylistViewHolder, false);
+ }
+ }
}
}
+ public void performOnActionClick(ActionViewHolder avh) {
+ if (mClickListener != null) {
+ mClickListener.onGuidedActionClicked(avh.getAction());
+ }
+ }
+
private class ActionOnKeyListener implements View.OnKeyListener {
- private final List<GuidedAction> mActions;
private boolean mKeyPressed = false;
- private ClickListener mClickListener;
-
- public ActionOnKeyListener(ClickListener listener,
- List<GuidedAction> actions) {
- mClickListener = listener;
- mActions = actions;
- }
-
- public void setListener(ClickListener listener) {
- mClickListener = listener;
- }
private void playSound(View v, int soundEffect) {
if (v.isSoundEffectsEnabled()) {
@@ -314,7 +425,7 @@
*/
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (v == null || event == null) {
+ if (v == null || event == null || getRecyclerView() == null) {
return false;
}
boolean handled = false;
@@ -325,7 +436,8 @@
case KeyEvent.KEYCODE_BUTTON_Y:
case KeyEvent.KEYCODE_ENTER:
- ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
+ ActionViewHolder avh = (ActionViewHolder) getRecyclerView()
+ .getChildViewHolder(v);
GuidedAction action = avh.getAction();
if (!action.isEnabled() || action.infoOnly()) {
@@ -338,33 +450,25 @@
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
+ if (DEBUG) {
+ Log.d(TAG, "Enter Key down");
+ }
if (!mKeyPressed) {
mKeyPressed = true;
-
playSound(v, AudioManager.FX_KEY_CLICK);
-
- if (DEBUG) {
- Log.d(TAG, "Enter Key down");
- }
-
mStylist.onAnimateItemPressed(avh.mStylistViewHolder,
mKeyPressed);
- handled = true;
}
break;
case KeyEvent.ACTION_UP:
+ if (DEBUG) {
+ Log.d(TAG, "Enter Key up");
+ }
+ // Sometimes we are losing ACTION_DOWN for the first ENTER after pressed
+ // Escape in IME.
if (mKeyPressed) {
mKeyPressed = false;
-
- if (DEBUG) {
- Log.d(TAG, "Enter Key up");
- }
-
- mStylist.onAnimateItemPressed(avh.mStylistViewHolder,
- mKeyPressed);
- handleCheckedActions(avh, action);
- mClickListener.onGuidedActionClicked(action);
- handled = true;
+ mStylist.onAnimateItemPressed(avh.mStylistViewHolder, mKeyPressed);
}
break;
default:
@@ -377,30 +481,40 @@
return handled;
}
- private void handleCheckedActions(ActionViewHolder avh, GuidedAction action) {
- int actionCheckSetId = action.getCheckSetId();
- if (actionCheckSetId != GuidedAction.NO_CHECK_SET) {
- // Find any actions that are checked and are in the same group
- // as the selected action. Fade their checkmarks out.
- for (int i = 0, size = mActions.size(); i < size; i++) {
- GuidedAction a = mActions.get(i);
- if (a != action && a.getCheckSetId() == actionCheckSetId && a.isChecked()) {
- a.setChecked(false);
- ViewHolder vh = mRecyclerView.findViewHolderForPosition(i);
- if (vh != null) {
- GuidedActionsStylist.ViewHolder subViewHolder =
- ((ActionViewHolder)vh).mStylistViewHolder;
- mStylist.onAnimateItemChecked(subViewHolder, false);
- }
- }
- }
-
- // If we we'ren't already checked, fade our checkmark in.
- if (!action.isChecked()) {
- action.setChecked(true);
- mStylist.onAnimateItemChecked(avh.mStylistViewHolder, true);
- }
- }
- }
}
+
+ private class ActionEditListener implements OnEditorActionListener,
+ ImeKeyMonitor.ImeKeyListener {
+
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "IME action: " + actionId);
+ boolean handled = false;
+ if (actionId == EditorInfo.IME_ACTION_NEXT ||
+ actionId == EditorInfo.IME_ACTION_DONE) {
+ mGroup.fillAndGoNext(GuidedActionAdapter.this, v);
+ handled = true;
+ } else if (actionId == EditorInfo.IME_ACTION_NONE) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme escape north");
+ // Escape north handling: stay on current item, but close editor
+ handled = true;
+ mGroup.fillAndStay(GuidedActionAdapter.this, v);
+ }
+ return handled;
+ }
+
+ @Override
+ public boolean onKeyPreIme(EditText editText, int keyCode, KeyEvent event) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "IME key: " + keyCode);
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
+ mGroup.fillAndStay(GuidedActionAdapter.this, editText);
+ } else if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() ==
+ KeyEvent.ACTION_UP) {
+ mGroup.fillAndGoNext(GuidedActionAdapter.this, editText);
+ }
+ return false;
+ }
+
+ }
+
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java
new file mode 100644
index 0000000..8f8951c
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.content.Context;
+import android.support.v17.leanback.app.GuidedActionAdapter.ActionViewHolder;
+import android.support.v17.leanback.app.GuidedActionAdapter.ClickListener;
+import android.support.v17.leanback.app.GuidedActionAdapter.EditListener;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.ImeKeyMonitor;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import java.util.ArrayList;
+
+/**
+ * Internal implementation manages a group of GuidedActionAdapters, control the next action after
+ * editing finished, maintain the Ime open/close status.
+ */
+class GuidedActionAdapterGroup {
+
+ private static final String TAG_EDIT = "EditableAction";
+ private static final boolean DEBUG_EDIT = false;
+
+ ArrayList<GuidedActionAdapter> mAdapters = new ArrayList<GuidedActionAdapter>();
+ private boolean mImeOpened;
+ private EditListener mEditListener;
+
+ GuidedActionAdapterGroup() {
+ }
+
+ public void addAdpter(GuidedActionAdapter adapter) {
+ mAdapters.add(adapter);
+ adapter.mGroup = this;
+ }
+
+ public void setEditListener(EditListener listener) {
+ mEditListener = listener;
+ }
+
+ boolean focusToNextAction(GuidedActionAdapter adapter, GuidedAction action, long nextActionId) {
+ // for ACTION_ID_NEXT, we first find out the matching index in Actions list.
+ int index = 0;
+ if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
+ index = adapter.indexOf(action);
+ if (index < 0) {
+ return false;
+ }
+ // start from next, if reach end, will go next Adapter below
+ index++;
+ }
+
+ int adapterIndex = mAdapters.indexOf(adapter);
+ do {
+ int size = adapter.getCount();
+ if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
+ while (index < size && !adapter.getItem(index).isFocusable()) {
+ index++;
+ }
+ } else {
+ while (index < size && adapter.getItem(index).getId() != nextActionId) {
+ index++;
+ }
+ }
+ if (index < size) {
+ ActionViewHolder vh = (ActionViewHolder) adapter.getGuidedActionsStylist()
+ .getActionsGridView().findViewHolderForPosition(index);
+ if (vh != null) {
+ if (vh.getAction().isEditable() || vh.getAction().isDescriptionEditable()) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme of next Action");
+ // open Ime on next action.
+ openIme(adapter, vh);
+ } else {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme and focus to next Action");
+ // close IME and focus to next (not editable) action
+ closeIme(vh.mStylistViewHolder.view);
+ vh.mStylistViewHolder.view.requestFocus();
+ }
+ return true;
+ }
+ return false;
+ }
+ // search from index 0 of next Adapter
+ adapterIndex++;
+ if (adapterIndex >= mAdapters.size()) {
+ break;
+ }
+ adapter = mAdapters.get(adapterIndex);
+ index = 0;
+ } while (true);
+ return false;
+ }
+
+ public void openIme(GuidedActionAdapter adapter, ActionViewHolder avh) {
+ adapter.getGuidedActionsStylist().setEditingMode(avh.mStylistViewHolder, avh.getAction(),
+ true);
+ View v = avh.mStylistViewHolder.getEditingView();
+ if (v == null) {
+ return;
+ }
+ InputMethodManager mgr = (InputMethodManager)
+ v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ v.requestFocus();
+ mgr.showSoftInput(v, 0);
+ if (!mImeOpened) {
+ mImeOpened = true;
+ mEditListener.onImeOpen();
+ }
+ }
+
+ public void closeIme(View v) {
+ if (mImeOpened) {
+ mImeOpened = false;
+ InputMethodManager mgr = (InputMethodManager)
+ v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ mgr.hideSoftInputFromWindow(v.getWindowToken(), 0);
+ mEditListener.onImeClose();
+ }
+ }
+
+ private long finishEditing(GuidedActionAdapter adapter, ActionViewHolder avh) {
+ long nextActionId = mEditListener.onGuidedActionEdited(avh.getAction());
+ adapter.getGuidedActionsStylist().setEditingMode(avh.mStylistViewHolder, avh.getAction(),
+ false);
+ return nextActionId;
+ }
+
+ public void fillAndStay(GuidedActionAdapter adapter, TextView v) {
+ ActionViewHolder avh = adapter.findSubChildViewHolder(v);
+ updateTextIntoAction(avh, v);
+ finishEditing(adapter, avh);
+ closeIme(v);
+ avh.mStylistViewHolder.view.requestFocus();
+ }
+
+ public void fillAndGoNext(GuidedActionAdapter adapter, TextView v) {
+ boolean handled = false;
+ ActionViewHolder avh = adapter.findSubChildViewHolder(v);
+ updateTextIntoAction(avh, v);
+ adapter.performOnActionClick(avh);
+ long nextActionId = finishEditing(adapter, avh);
+ if (nextActionId != GuidedAction.ACTION_ID_CURRENT
+ && nextActionId != avh.getAction().getId()) {
+ handled = focusToNextAction(adapter, avh.getAction(), nextActionId);
+ }
+ if (!handled) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme no next action");
+ handled = true;
+ closeIme(v);
+ avh.mStylistViewHolder.view.requestFocus();
+ }
+ }
+
+ private void updateTextIntoAction(ActionViewHolder avh, TextView v) {
+ GuidedAction action = avh.getAction();
+ if (v == avh.mStylistViewHolder.getDescriptionView()) {
+ if (action.getEditDescription() != null) {
+ action.setEditDescription(v.getText());
+ } else {
+ action.setDescription(v.getText());
+ }
+ } else if (v == avh.mStylistViewHolder.getTitleView()) {
+ if (action.getEditTitle() != null) {
+ action.setEditTitle(v.getText());
+ } else {
+ action.setTitle(v.getText());
+ }
+ }
+ }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
index b1e87a1..8be8f24 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
@@ -18,28 +18,34 @@
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
+import android.app.FragmentManager.BackStackEntry;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v17.leanback.animation.UntargetableAnimatorSet;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.R;
import android.support.v17.leanback.widget.GuidanceStylist;
import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
import android.support.v17.leanback.widget.GuidedAction;
import android.support.v17.leanback.widget.GuidedActionsStylist;
import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
@@ -52,7 +58,7 @@
* <p>
* <h3>Basic Usage</h3>
* <p>
- * Clients of GuidedStepFragment typically create a custom subclass to attach to their Activities.
+ * Clients of GuidedStepFragment must create a custom subclass to attach to their Activities.
* This custom subclass provides the information necessary to construct the user interface and
* respond to user actions. At a minimum, subclasses should override:
* <ul>
@@ -61,6 +67,19 @@
* <li>{@link #onGuidedActionClicked}, to respond to those actions</li>
* </ul>
* <p>
+ * Clients use following helper functions to add GuidedStepFragment to Activity or FragmentManager:
+ * <ul>
+ * <li>{@link #addAsRoot(Activity, GuidedStepFragment, int)}, to be called during Activity onCreate,
+ * adds GuidedStepFragment as the first Fragment in activity.</li>
+ * <li>{@link #add(FragmentManager, GuidedStepFragment)} or {@link #add(FragmentManager,
+ * GuidedStepFragment, int)}, to add GuidedStepFragment on top of existing Fragments or
+ * replacing existing GuidedStepFragment when moving forward to next step.</li>
+ * <li>{@link #finishGuidedStepFragments()} can either finish the activity or pop all
+ * GuidedStepFragment from stack.
+ * <li>If app chooses not to use the helper function, it is the app's responsibility to call
+ * {@link #setUiStyle(int)} to select fragment transition and remember the stack entry where it
+ * need pops to.
+ * </ul>
* <h3>Theming and Stylists</h3>
* <p>
* GuidedStepFragment delegates its visual styling to classes called stylists. The {@link
@@ -106,8 +125,14 @@
* <p>
* <i>Note: Currently GuidedStepFragments grouped in this way must all be defined programmatically,
* rather than in XML. This restriction may be removed in the future.</i>
- * <p>
+ *
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepBackground
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeight
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeightTwoPanels
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackground
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackgroundDark
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsElevation
* @see GuidanceStylist
* @see GuidanceStylist.Guidance
* @see GuidedAction
@@ -118,24 +143,81 @@
private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepFragment";
private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
- private static final String EXTRA_ACTION_ENTRY_TRANSITION_ENABLED = "entryTransitionEnabled";
- private static final String EXTRA_ENTRY_TRANSITION_PERFORMED = "entryTransitionPerformed";
+
+ private static final String ENTRY_NAME_REPLACE = "GuidedStepDefault";
+
+ private static final String ENTRY_NAME_ENTRANCE = "GuidedStepEntrance";
+
+ /**
+ * Fragment argument name for UI style. The argument value is persisted in fragment state.
+ * The value is initially {@link #UI_STYLE_ENTRANCE} and might be changed in one of the three
+ * helper functions:
+ * <ul>
+ * <li>{@link #addAsRoot(Activity, GuidedStepFragment, int)}</li>
+ * <li>{@link #add(FragmentManager, GuidedStepFragment)} or {@link #add(FragmentManager,
+ * GuidedStepFragment, int)}</li>
+ * </ul>
+ * <p>
+ * Argument value can be either:
+ * <ul>
+ * <li>{@link #UI_STYLE_REPLACE}</li>
+ * <li>{@link #UI_STYLE_ENTRANCE}</li>
+ * <li>{@link #UI_STYLE_ACTIVITY_ROOT}</li>
+ * </ul>
+ */
+ public static final String EXTRA_UI_STYLE = "uiStyle";
+
+ /**
+ * This is the case that we use GuidedStepFragment to replace another existing
+ * GuidedStepFragment when moving forward to next step. Default behavior of this style is:
+ * <ul>
+ * <li>Enter transition slides in from END(right), exit transition same as
+ * {@link #UI_STYLE_ENTRANCE}.
+ * </li>
+ * </ul>
+ */
+ public static final int UI_STYLE_REPLACE = 0;
+
+ /**
+ * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned in
+ * GuidedStepFragment constructor. This is the case that we show GuidedStepFragment on top of
+ * other content. The default behavior of this style:
+ * <ul>
+ * <li>Enter transition slides in from two sides, exit transition slide out to START(left).
+ * Background will be faded in. Note: Changing exit transition by UI style is not working
+ * because fragment transition asks for exit transition before UI style is restored in Fragment
+ * .onCreate().</li>
+ * </ul>
+ */
+ public static final int UI_STYLE_ENTRANCE = 1;
+
+ /**
+ * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
+ * GuidedStepFragment in a separate activity. The default behavior of this style:
+ * <ul>
+ * <li>Enter transition is assigned null (will rely on activity transition), exit transition is
+ * same as {@link #UI_STYLE_ENTRANCE}. Note: Changing exit transition by UI style is not working
+ * because fragment transition asks for exit transition before UI style is restored in
+ * Fragment.onCreate().</li>
+ * </ul>
+ */
+ public static final int UI_STYLE_ACTIVITY_ROOT = 2;
+
private static final String TAG = "GuidedStepFragment";
- private static final boolean DEBUG = true;
- private static final int ANIMATION_FRAGMENT_ENTER = 1;
- private static final int ANIMATION_FRAGMENT_EXIT = 2;
- private static final int ANIMATION_FRAGMENT_ENTER_POP = 3;
- private static final int ANIMATION_FRAGMENT_EXIT_POP = 4;
+ private static final boolean DEBUG = false;
private int mTheme;
+ private ContextThemeWrapper mThemeWrapper;
private GuidanceStylist mGuidanceStylist;
private GuidedActionsStylist mActionsStylist;
+ private GuidedActionsStylist mButtonActionsStylist;
private GuidedActionAdapter mAdapter;
- private VerticalGridView mListView;
+ private GuidedActionAdapter mButtonAdapter;
+ private GuidedActionAdapterGroup mAdapterGroup;
private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
+ private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
private int mSelectedIndex = -1;
- private boolean mEntryTransitionPerformed;
- private boolean mEntryTransitionEnabled = true;
+ private int mButtonSelectedIndex = -1;
public GuidedStepFragment() {
// We need to supply the theme before any potential call to onInflate in order
@@ -143,6 +225,8 @@
mTheme = onProvideTheme();
mGuidanceStylist = onCreateGuidanceStylist();
mActionsStylist = onCreateActionsStylist();
+ mButtonActionsStylist = onCreateButtonActionsStylist();
+ onProvideFragmentTransitions();
}
/**
@@ -164,6 +248,15 @@
}
/**
+ * Creates the presenter used to style a sided actions panel for button only.
+ * The default implementation returns a basic GuidedActionsStylist.
+ * @return The GuidedActionsStylist used in this fragment.
+ */
+ public GuidedActionsStylist onCreateButtonActionsStylist() {
+ return new GuidedActionsStylist();
+ }
+
+ /**
* Returns the theme used for styling the fragment. The default returns -1, indicating that the
* host Activity's theme should be used.
* @return The theme resource ID of the theme to use in this fragment, or -1 to use the
@@ -195,6 +288,16 @@
}
/**
+ * Fills out the set of actions shown at right available to the user. This hook is called during
+ * {@link #onCreate}. The default leaves the list of actions empty; subclasses may override.
+ * @param actions A non-null, empty list ready to be populated.
+ * @param savedInstanceState The saved instance state from onCreate.
+ */
+ public void onCreateButtonActions(@NonNull List<GuidedAction> actions,
+ Bundle savedInstanceState) {
+ }
+
+ /**
* Callback invoked when an action is taken by the user. Subclasses should override in
* order to act on the user's decisions.
* @param action The chosen action.
@@ -211,8 +314,34 @@
}
/**
+ * Callback invoked when an action's title or description has been edited.
+ * Override {@link #onGuidedActionEditedAndProceed(GuidedAction)} instead of app wants to
+ * control the next action to focus on.
+ */
+ public void onGuidedActionEdited(GuidedAction action) {
+ }
+
+ /**
+ * Callback invoked when an action's title or description has been edited. Default
+ * implementation calls {@link #onGuidedActionEdited(GuidedAction)} and returns
+ * {@link GuidedAction#ACTION_ID_NEXT}.
+ *
+ * @param action The action that has been edited.
+ * @return ID of the action will be focused or {@link GuidedAction#ACTION_ID_NEXT},
+ * {@link GuidedAction#ACTION_ID_CURRENT}.
+ */
+ public long onGuidedActionEditedAndProceed(GuidedAction action) {
+ onGuidedActionEdited(action);
+ return GuidedAction.ACTION_ID_NEXT;
+ }
+
+ /**
* Adds the specified GuidedStepFragment to the fragment stack, replacing any existing
- * GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom animations.
+ * GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom
+ * transitions. A backstack entry is added, so the fragment will be dismissed when BACK key
+ * is pressed.
+ * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_REPLACE}
+ * <li>If current fragment on stack is not GuidedStepFragment: assign {@link #UI_STYLE_ENTRANCE}
* <p>
* Note: currently fragments added using this method must be created programmatically rather
* than via XML.
@@ -224,19 +353,165 @@
return add(fragmentManager, fragment, android.R.id.content);
}
- // Note, this method used to be public, but I haven't found a good way for a client
- // to specify an id.
- private static int add(FragmentManager fm, GuidedStepFragment f, int id) {
- boolean inGuidedStep = getCurrentGuidedStepFragment(fm) != null;
- FragmentTransaction ft = fm.beginTransaction();
+ /**
+ * Adds the specified GuidedStepFragment to the fragment stack, replacing any existing
+ * GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom
+ * transitions. A backstack entry is added, so the fragment will be dismissed when BACK key
+ * is pressed.
+ * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_REPLACE} and
+ * {@link #onAddSharedElementTransition(FragmentTransaction, GuidedStepFragment)} will be called
+ * to perform shared element transition between GuidedStepFragments.
+ * <li>If current fragment on stack is not GuidedStepFragment: assign {@link #UI_STYLE_ENTRANCE}
+ * <p>
+ * Note: currently fragments added using this method must be created programmatically rather
+ * than via XML.
+ * @param fragmentManager The FragmentManager to be used in the transaction.
+ * @param fragment The GuidedStepFragment to be inserted into the fragment stack.
+ * @param id The id of container to add GuidedStepFragment, can be android.R.id.content.
+ * @return The ID returned by the call FragmentTransaction.replace.
+ */
+ public static int add(FragmentManager fragmentManager, GuidedStepFragment fragment, int id) {
+ GuidedStepFragment current = getCurrentGuidedStepFragment(fragmentManager);
+ boolean inGuidedStep = current != null;
+ FragmentTransaction ft = fragmentManager.beginTransaction();
- if (inGuidedStep) {
- ft.setCustomAnimations(ANIMATION_FRAGMENT_ENTER,
- ANIMATION_FRAGMENT_EXIT, ANIMATION_FRAGMENT_ENTER_POP,
- ANIMATION_FRAGMENT_EXIT_POP);
- ft.addToBackStack(null);
+ fragment.setUiStyle(inGuidedStep ? UI_STYLE_REPLACE : UI_STYLE_ENTRANCE);
+ ft.addToBackStack(fragment.generateStackEntryName());
+ if (current != null) {
+ fragment.onAddSharedElementTransition(ft, current);
}
- return ft.replace(id, f, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
+ return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
+ }
+
+ /**
+ * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_REPLACE} (aka
+ * when the GuidedStepFragment replacing an existing GuidedStepFragment). Default implementation
+ * establishes connections between action background views to morph action background bounds
+ * change from disappearing GuidedStepFragment into this GuidedStepFragment. The default
+ * implementation heavily relies on {@link GuidedActionsStylist}'s layout, app may override this
+ * method when modifying the default layout of {@link GuidedActionsStylist}.
+ *
+ * @see GuidedActionsStylist
+ * @see #onProvideFragmentTransitions()
+ * @param ft The FragmentTransaction to add shared element.
+ * @param disappearing The disappearing fragment.
+ */
+ protected void onAddSharedElementTransition(FragmentTransaction ft, GuidedStepFragment
+ disappearing) {
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.action_fragment_root), "action_fragment_root");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.action_fragment_background), "action_fragment_background");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.action_fragment), "action_fragment");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_root), "guidedactions_root");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_selector), "guidedactions_selector");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_content), "guidedactions_content");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_list_background), "guidedactions_list_background");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_root2), "guidedactions_root2");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_selector2), "guidedactions_selector2");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_content2), "guidedactions_content2");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_list_background2), "guidedactions_list_background2");
+ }
+
+ /**
+ * Returns BackStackEntry name for the GuidedStepFragment or empty String if no entry is
+ * associated. Note {@link #UI_STYLE_ACTIVITY_ROOT} will return empty String. The method
+ * returns undefined value if the fragment is not in FragmentManager.
+ * @return BackStackEntry name for the GuidedStepFragment or empty String if no entry is
+ * associated.
+ */
+ public String generateStackEntryName() {
+ return generateStackEntryName(getUiStyle(), getClass());
+ }
+
+ /**
+ * Generates BackStackEntry name for GuidedStepFragment class or empty String if no entry is
+ * associated. Note {@link #UI_STYLE_ACTIVITY_ROOT} is not allowed and returns empty String.
+ * @param uiStyle {@link #UI_STYLE_REPLACE} or {@link #UI_STYLE_ENTRANCE}
+ * @return BackStackEntry name for the GuidedStepFragment or empty String if no entry is
+ * associated.
+ */
+ public static String generateStackEntryName(int uiStyle, Class guidedStepFragmentClass) {
+ if (!GuidedStepFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
+ return "";
+ }
+ switch (uiStyle) {
+ case UI_STYLE_REPLACE:
+ return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
+ case UI_STYLE_ENTRANCE:
+ return ENTRY_NAME_ENTRANCE + guidedStepFragmentClass.getName();
+ case UI_STYLE_ACTIVITY_ROOT:
+ default:
+ return "";
+ }
+ }
+
+ /**
+ * Returns true if the backstack represents GuidedStepFragment with {@link #UI_STYLE_ENTRANCE};
+ * false otherwise.
+ * @param backStackEntryName Name of BackStackEntry.
+ * @return True if the backstack represents GuidedStepFragment with {@link #UI_STYLE_ENTRANCE};
+ * false otherwise.
+ */
+ public static boolean isUiStyleEntrance(String backStackEntryName) {
+ return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE);
+ }
+
+ /**
+ * Returns true if the backstack represents GuidedStepFragment with {@link #UI_STYLE_REPLACE};
+ * false otherwise.
+ * @param backStackEntryName Name of BackStackEntry.
+ * @return True if the backstack represents GuidedStepFragment with {@link #UI_STYLE_REPLACE};
+ * false otherwise.
+ */
+ public static boolean isUiStyleDefault(String backStackEntryName) {
+ return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_REPLACE);
+ }
+
+ /**
+ * Extract Class name from BackStackEntry name.
+ * @param backStackEntryName Name of BackStackEntry.
+ * @return Class name of GuidedStepFragment.
+ */
+ public static String getGuidedStepFragmentClassName(String backStackEntryName) {
+ if (backStackEntryName.startsWith(ENTRY_NAME_REPLACE)) {
+ return backStackEntryName.substring(ENTRY_NAME_REPLACE.length());
+ } else if (backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE)) {
+ return backStackEntryName.substring(ENTRY_NAME_ENTRANCE.length());
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Adds the specified GuidedStepFragment as content of Activity; no backstack entry is added so
+ * the activity will be dismissed when BACK key is pressed.
+ * {@link #UI_STYLE_ACTIVITY_ROOT} is assigned.
+ *
+ * Note: currently fragments added using this method must be created programmatically rather
+ * than via XML.
+ * @param activity The Activity to be used to insert GuidedstepFragment.
+ * @param fragment The GuidedStepFragment to be inserted into the fragment stack.
+ * @param id The id of container to add GuidedStepFragment, can be android.R.id.content.
+ * @return The ID returned by the call FragmentTransaction.replace.
+ */
+ public static int addAsRoot(Activity activity, GuidedStepFragment fragment, int id) {
+ // Workaround b/23764120: call getDecorView() to force requestFeature of ActivityTransition.
+ activity.getWindow().getDecorView();
+
+ FragmentManager fragmentManager = activity.getFragmentManager();
+ FragmentTransaction ft = fragmentManager.beginTransaction();
+ fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
+ return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
}
/**
@@ -268,6 +543,99 @@
}
/**
+ * Returns the list of button GuidedActions that the user may take in this fragment.
+ * @return The list of button GuidedActions for this fragment.
+ */
+ public List<GuidedAction> getButtonActions() {
+ return mButtonActions;
+ }
+
+ /**
+ * Find button GuidedAction by Id.
+ * @param id Id of the button action to search.
+ * @return GuidedAction object or null if not found.
+ */
+ public GuidedAction findButtonActionById(long id) {
+ int index = findButtonActionPositionById(id);
+ return index >= 0 ? mButtonActions.get(index) : null;
+ }
+
+ /**
+ * Find button GuidedAction position in array by Id.
+ * @param id Id of the button action to search.
+ * @return position of GuidedAction object in array or -1 if not found.
+ */
+ public int findButtonActionPositionById(long id) {
+ if (mButtonActions != null) {
+ for (int i = 0; i < mButtonActions.size(); i++) {
+ GuidedAction action = mButtonActions.get(i);
+ if (mButtonActions.get(i).getId() == id) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the GuidedActionsStylist that displays the button actions the user may take.
+ * @return The GuidedActionsStylist for this fragment.
+ */
+ public GuidedActionsStylist getGuidedButtonActionsStylist() {
+ return mButtonActionsStylist;
+ }
+
+ /**
+ * Sets the list of button GuidedActions that the user may take in this fragment.
+ * @param actions The list of button GuidedActions for this fragment.
+ */
+ public void setButtonActions(List<GuidedAction> actions) {
+ mButtonActions = actions;
+ if (mButtonAdapter != null) {
+ mButtonAdapter.setActions(mButtonActions);
+ }
+ }
+
+ /**
+ * Notify an button action has changed and update its UI.
+ * @param position Position of the button GuidedAction in array.
+ */
+ public void notifyButtonActionChanged(int position) {
+ if (mButtonAdapter != null) {
+ mButtonAdapter.notifyItemChanged(position);
+ }
+ }
+
+ /**
+ * Returns the view corresponding to the button action at the indicated position in the list of
+ * actions for this fragment.
+ * @param position The integer position of the button action of interest.
+ * @return The View corresponding to the button action at the indicated position, or null if
+ * that action is not currently onscreen.
+ */
+ public View getButtonActionItemView(int position) {
+ final RecyclerView.ViewHolder holder = mButtonActionsStylist.getActionsGridView()
+ .findViewHolderForPosition(position);
+ return holder == null ? null : holder.itemView;
+ }
+
+ /**
+ * Scrolls the action list to the position indicated, selecting that button action's view.
+ * @param position The integer position of the button action of interest.
+ */
+ public void setSelectedButtonActionPosition(int position) {
+ mButtonActionsStylist.getActionsGridView().setSelectedPosition(position);
+ }
+
+ /**
+ * Returns the position if the currently selected button GuidedAction.
+ * @return position The integer position of the currently selected button action.
+ */
+ public int getSelectedButtonActionPosition() {
+ return mButtonActionsStylist.getActionsGridView().getSelectedPosition();
+ }
+
+ /**
* Returns the list of GuidedActions that the user may take in this fragment.
* @return The list of GuidedActions for this fragment.
*/
@@ -276,6 +644,33 @@
}
/**
+ * Find GuidedAction by Id.
+ * @param id Id of the action to search.
+ * @return GuidedAction object or null if not found.
+ */
+ public GuidedAction findActionById(long id) {
+ int index = findActionPositionById(id);
+ return index >= 0 ? mActions.get(index) : null;
+ }
+
+ /**
+ * Find GuidedAction position in array by Id.
+ * @param id Id of the action to search.
+ * @return position of GuidedAction object in array or -1 if not found.
+ */
+ public int findActionPositionById(long id) {
+ if (mActions != null) {
+ for (int i = 0; i < mActions.size(); i++) {
+ GuidedAction action = mActions.get(i);
+ if (mActions.get(i).getId() == id) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
* Sets the list of GuidedActions that the user may take in this fragment.
* @param actions The list of GuidedActions for this fragment.
*/
@@ -287,6 +682,16 @@
}
/**
+ * Notify an action has changed and update its UI.
+ * @param position Position of the GuidedAction in array.
+ */
+ public void notifyActionChanged(int position) {
+ if (mAdapter != null) {
+ mAdapter.notifyItemChanged(position);
+ }
+ }
+
+ /**
* Returns the view corresponding to the action at the indicated position in the list of
* actions for this fragment.
* @param position The integer position of the action of interest.
@@ -294,7 +699,9 @@
* action is not currently onscreen.
*/
public View getActionItemView(int position) {
- return mListView.findViewHolderForPosition(position).itemView;
+ final RecyclerView.ViewHolder holder = mActionsStylist.getActionsGridView()
+ .findViewHolderForPosition(position);
+ return holder == null ? null : holder.itemView;
}
/**
@@ -302,7 +709,7 @@
* @param position The integer position of the action of interest.
*/
public void setSelectedActionPosition(int position) {
- mListView.setSelectedPosition(position);
+ mActionsStylist.getActionsGridView().setSelectedPosition(position);
}
/**
@@ -310,7 +717,126 @@
* @return position The integer position of the currently selected action.
*/
public int getSelectedActionPosition() {
- return mListView.getSelectedPosition();
+ return mActionsStylist.getActionsGridView().getSelectedPosition();
+ }
+
+ /**
+ * Called by Constructor to provide fragment transitions. The default implementation assigns
+ * transitions based on {@link #getUiStyle()}:
+ * <ul>
+ * <li> {@link #UI_STYLE_REPLACE} Slide from/to end(right) for enter transition, slide from/to
+ * start(left) for exit transition, shared element enter transition is set to ChangeBounds.
+ * <li> {@link #UI_STYLE_ENTRANCE} Enter transition is set to slide from both sides, exit
+ * transition is same as {@link #UI_STYLE_REPLACE}, no shared element enter transition.
+ * <li> {@link #UI_STYLE_ACTIVITY_ROOT} Enter transition is set to null and app should rely on
+ * activity transition, exit transition is same as {@link #UI_STYLE_REPLACE}, no shared element
+ * enter transition.
+ * </ul>
+ * <p>
+ * The default implementation heavily relies on {@link GuidedActionsStylist} and
+ * {@link GuidanceStylist} layout, app may override this method when modifying the default
+ * layout of {@link GuidedActionsStylist} or {@link GuidanceStylist}.
+ * <p>
+ * TIP: because the fragment view is removed during fragment transition, in general app cannot
+ * use two Visibility transition together. Workaround is to create your own Visibility
+ * transition that controls multiple animators (e.g. slide and fade animation in one Transition
+ * class).
+ */
+ protected void onProvideFragmentTransitions() {
+ if (Build.VERSION.SDK_INT >= 21) {
+ final int uiStyle = getUiStyle();
+ if (uiStyle == UI_STYLE_REPLACE) {
+ Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END);
+ TransitionHelper.exclude(enterTransition, R.id.guidedstep_background, true);
+ TransitionHelper.setEnterTransition(this, enterTransition);
+
+ Object changeBounds = TransitionHelper.createChangeBounds(false);
+ TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
+ } else if (uiStyle == UI_STYLE_ENTRANCE) {
+ Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
+ TransitionHelper.FADE_OUT);
+ TransitionHelper.include(fade, R.id.guidedstep_background);
+ Object slide = TransitionHelper.createFadeAndShortSlide(Gravity.END |
+ Gravity.START);
+ TransitionHelper.include(slide, R.id.content_fragment);
+ TransitionHelper.include(slide, R.id.action_fragment_root);
+ Object enterTransition = TransitionHelper.createTransitionSet(false);
+ TransitionHelper.addTransition(enterTransition, fade);
+ TransitionHelper.addTransition(enterTransition, slide);
+ TransitionHelper.setEnterTransition(this, enterTransition);
+
+ // No shared element transition
+ TransitionHelper.setSharedElementEnterTransition(this, null);
+ } else if (uiStyle == UI_STYLE_ACTIVITY_ROOT) {
+ // for Activity root, we dont need enter transition, use activity transition
+ TransitionHelper.setEnterTransition(this, null);
+ // No shared element transition
+ TransitionHelper.setSharedElementEnterTransition(this, null);
+ }
+ // exitTransition is same for all style
+ Object exitTransition = TransitionHelper.createFadeAndShortSlide(Gravity.START);
+ TransitionHelper.exclude(exitTransition, R.id.guidedstep_background, true);
+ TransitionHelper.setExitTransition(this, exitTransition);
+ }
+ }
+
+ /**
+ * Called by onCreateView to inflate background view. Default implementation loads view
+ * from {@link R.layout#lb_guidedstep_background} which holds a reference to
+ * guidedStepBackground.
+ * @param inflater LayoutInflater to load background view.
+ * @param container Parent view of background view.
+ * @param savedInstanceState
+ * @return Created background view or null if no background.
+ */
+ public View onCreateBackgroundView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
+ }
+
+ /**
+ * Set UI style to fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when fragment
+ * is first initialized. UI style is used to choose different fragment transition animations and
+ * determine if this is the first GuidedStepFragment on backstack. In most cases app does not
+ * directly call this method, app calls helper function
+ * {@link #add(FragmentManager, GuidedStepFragment, int)}. However if the app creates Fragment
+ * transaction and controls backstack by itself, it would need call setUiStyle() to select the
+ * fragment transition to use.
+ *
+ * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+ * {@link #UI_STYLE_ENTRANCE}.
+ */
+ public void setUiStyle(int style) {
+ int oldStyle = getUiStyle();
+ Bundle arguments = getArguments();
+ boolean isNew = false;
+ if (arguments == null) {
+ arguments = new Bundle();
+ isNew = true;
+ }
+ arguments.putInt(EXTRA_UI_STYLE, style);
+ // call setArgument() will validate if the fragment is already added.
+ if (isNew) {
+ setArguments(arguments);
+ }
+ if (style != oldStyle) {
+ onProvideFragmentTransitions();
+ }
+ }
+
+ /**
+ * Read UI style from fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when
+ * fragment is first initialized. UI style is used to choose different fragment transition
+ * animations and determine if this is the first GuidedStepFragment on backstack.
+ *
+ * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+ * {@link #UI_STYLE_ENTRANCE}.
+ * @see #onProvideFragmentTransitions()
+ */
+ public int getUiStyle() {
+ Bundle b = getArguments();
+ if (b == null) return UI_STYLE_ENTRANCE;
+ return b.getInt(EXTRA_UI_STYLE, UI_STYLE_ENTRANCE);
}
/**
@@ -320,16 +846,34 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (DEBUG) Log.v(TAG, "onCreate");
+ // Set correct transition from saved arguments.
+ onProvideFragmentTransitions();
Bundle state = (savedInstanceState != null) ? savedInstanceState : getArguments();
if (state != null) {
if (mSelectedIndex == -1) {
mSelectedIndex = state.getInt(EXTRA_ACTION_SELECTED_INDEX, -1);
}
- mEntryTransitionEnabled = state.getBoolean(EXTRA_ACTION_ENTRY_TRANSITION_ENABLED, true);
- mEntryTransitionPerformed = state.getBoolean(EXTRA_ENTRY_TRANSITION_PERFORMED, false);
}
- mActions.clear();
- onCreateActions(mActions, savedInstanceState);
+ ArrayList<GuidedAction> actions = new ArrayList<GuidedAction>();
+ onCreateActions(actions, savedInstanceState);
+ setActions(actions);
+ ArrayList<GuidedAction> buttonActions = new ArrayList<GuidedAction>();
+ onCreateButtonActions(buttonActions, savedInstanceState);
+ setButtonActions(buttonActions);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDestroyView() {
+ mGuidanceStylist.onDestroyView();
+ mActionsStylist.onDestroyView();
+ mButtonActionsStylist.onDestroyView();
+ mAdapter = null;
+ mButtonAdapter = null;
+ mAdapterGroup = null;
+ super.onDestroyView();
}
/**
@@ -343,9 +887,10 @@
resolveTheme();
inflater = getThemeInflater(inflater);
- View v = inflater.inflate(R.layout.lb_guidedstep_fragment, container, false);
- ViewGroup guidanceContainer = (ViewGroup) v.findViewById(R.id.content_fragment);
- ViewGroup actionContainer = (ViewGroup) v.findViewById(R.id.action_fragment);
+ ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_guidedstep_fragment,
+ container, false);
+ ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
+ ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
Guidance guidance = onCreateGuidance(savedInstanceState);
View guidanceView = mGuidanceStylist.onCreateView(inflater, guidanceContainer, guidance);
@@ -354,15 +899,77 @@
View actionsView = mActionsStylist.onCreateView(inflater, actionContainer);
actionContainer.addView(actionsView);
- mAdapter = new GuidedActionAdapter(mActions, this, this, mActionsStylist);
+ View buttonActionsView = mButtonActionsStylist.onCreateView(inflater, actionContainer);
+ mButtonActionsStylist.setAsButtonActions();
+ actionContainer.addView(buttonActionsView);
- mListView = mActionsStylist.getActionsGridView();
- mListView.setAdapter(mAdapter);
+ GuidedActionAdapter.EditListener editListener = new GuidedActionAdapter.EditListener() {
+
+ @Override
+ public void onImeOpen() {
+ runImeAnimations(true);
+ }
+
+ @Override
+ public void onImeClose() {
+ runImeAnimations(false);
+ }
+
+ @Override
+ public long onGuidedActionEdited(GuidedAction action) {
+ return GuidedStepFragment.this.onGuidedActionEditedAndProceed(action);
+ }
+ };
+
+ mAdapter = new GuidedActionAdapter(mActions, this, this, mActionsStylist);
+ mButtonAdapter = new GuidedActionAdapter(mButtonActions, this, this, mButtonActionsStylist);
+ mAdapterGroup = new GuidedActionAdapterGroup();
+ mAdapterGroup.addAdpter(mAdapter);
+ mAdapterGroup.addAdpter(mButtonAdapter);
+ mAdapterGroup.setEditListener(editListener);
+
+ mActionsStylist.getActionsGridView().setAdapter(mAdapter);
+ mButtonActionsStylist.getActionsGridView().setAdapter(mButtonAdapter);
+ if (mButtonActions.size() == 0) {
+ // when there is no button actions, we dont need show the second panel, but keep
+ // the width zero to run ChangeBounds transition.
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ buttonActionsView.getLayoutParams();
+ lp.weight = 0;
+ buttonActionsView.setLayoutParams(lp);
+ } else {
+ // when there are two actions panel, we need adjust the weight of action to
+ // guidedActionContentWidthWeightTwoPanels.
+ Context ctx = mThemeWrapper != null ? mThemeWrapper : getActivity();
+ TypedValue typedValue = new TypedValue();
+ if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
+ typedValue, true)) {
+ View actionsRoot = root.findViewById(R.id.action_fragment_root);
+ float weight = typedValue.getFloat();
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) actionsRoot
+ .getLayoutParams();
+ lp.weight = weight;
+ actionsRoot.setLayoutParams(lp);
+ }
+ }
+
int pos = (mSelectedIndex >= 0 && mSelectedIndex < mActions.size()) ?
mSelectedIndex : getFirstCheckedAction();
- mListView.setSelectedPosition(pos);
+ setSelectedActionPosition(pos);
- return v;
+ setSelectedButtonActionPosition(0);
+
+ View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
+ if (backgroundView != null) {
+ root.addView(backgroundView, 0);
+ }
+ return root;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mActionsStylist.getActionsGridView().requestFocus();
}
/**
@@ -372,75 +979,11 @@
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(EXTRA_ACTION_SELECTED_INDEX,
- (mListView != null) ? getSelectedActionPosition() : mSelectedIndex);
- outState.putBoolean(EXTRA_ACTION_ENTRY_TRANSITION_ENABLED, mEntryTransitionEnabled);
- outState.putBoolean(EXTRA_ENTRY_TRANSITION_PERFORMED, mEntryTransitionPerformed);
+ (mActionsStylist.getActionsGridView() != null) ?
+ getSelectedActionPosition() : mSelectedIndex);
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void onStart() {
- if (DEBUG) Log.v(TAG, "onStart");
- super.onStart();
- if (isEntryTransitionEnabled() && !mEntryTransitionPerformed) {
- mEntryTransitionPerformed = true;
- performEntryTransition();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
- if (DEBUG) Log.v(TAG, "onCreateAnimator: " + transit + " " + enter + " " + nextAnim);
- View mainView = getView();
-
- ArrayList<Animator> animators = new ArrayList<Animator>();
- switch (nextAnim) {
- case ANIMATION_FRAGMENT_ENTER:
- mGuidanceStylist.onFragmentEnter(animators);
- mActionsStylist.onFragmentEnter(animators);
- break;
- case ANIMATION_FRAGMENT_EXIT:
- mGuidanceStylist.onFragmentExit(animators);
- mActionsStylist.onFragmentExit(animators);
- break;
- case ANIMATION_FRAGMENT_ENTER_POP:
- mGuidanceStylist.onFragmentReenter(animators);
- mActionsStylist.onFragmentReenter(animators);
- break;
- case ANIMATION_FRAGMENT_EXIT_POP:
- mGuidanceStylist.onFragmentReturn(animators);
- mActionsStylist.onFragmentReturn(animators);
- break;
- default:
- return super.onCreateAnimator(transit, enter, nextAnim);
- }
-
- mEntryTransitionPerformed = true;
- return createDummyAnimator(mainView, animators);
- }
-
- /**
- * Returns whether entry transitions are enabled for this fragment.
- * @return Whether entry transitions are enabled for this fragment.
- */
- protected boolean isEntryTransitionEnabled() {
- return mEntryTransitionEnabled;
- }
-
- /**
- * Sets whether entry transitions are enabled for this fragment.
- * @param enabled Whether to enable entry transitions for this fragment.
- */
- protected void setEntryTransitionEnabled(boolean enabled) {
- mEntryTransitionEnabled = enabled;
- }
-
- private boolean isGuidedStepTheme(Context context) {
+ private static boolean isGuidedStepTheme(Context context) {
int resId = R.attr.guidedStepThemeFlag;
TypedValue typedValue = new TypedValue();
boolean found = context.getTheme().resolveAttribute(resId, typedValue, true);
@@ -448,8 +991,58 @@
return found && typedValue.type == TypedValue.TYPE_INT_BOOLEAN && typedValue.data != 0;
}
+ /**
+ * Convenient method to close GuidedStepFragments on top of other content or finish Activity if
+ * GuidedStepFragments were started in a separate activity. Pops all stack entries including
+ * {@link #UI_STYLE_ENTRANCE}; if {@link #UI_STYLE_ENTRANCE} is not found, finish the activity.
+ * Note that this method must be paired with {@link #add(FragmentManager, GuidedStepFragment,
+ * int)} which sets up the stack entry name for finding which fragment we need to pop back to.
+ */
+ public void finishGuidedStepFragments() {
+ final FragmentManager fragmentManager = getFragmentManager();
+ final int entryCount = fragmentManager.getBackStackEntryCount();
+ if (entryCount > 0) {
+ for (int i = entryCount - 1; i >= 0; i--) {
+ BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
+ if (isUiStyleEntrance(entry.getName())) {
+ GuidedStepFragment top = getCurrentGuidedStepFragment(fragmentManager);
+ if (top != null) {
+ top.setUiStyle(UI_STYLE_ENTRANCE);
+ }
+ fragmentManager.popBackStack(entry.getId(),
+ FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ return;
+ }
+ }
+ }
+ ActivityCompat.finishAfterTransition(getActivity());
+ }
+
+ /**
+ * Convenient method to pop to fragment with Given class.
+ * @param guidedStepFragmentClass Name of the Class of GuidedStepFragment to pop to.
+ * @param flags Either 0 or {@link FragmentManager#POP_BACK_STACK_INCLUSIVE}.
+ */
+ public void popBackStackToGuidedStepFragment(Class guidedStepFragmentClass, int flags) {
+ if (!GuidedStepFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
+ return;
+ }
+ final FragmentManager fragmentManager = getFragmentManager();
+ final int entryCount = fragmentManager.getBackStackEntryCount();
+ String className = guidedStepFragmentClass.getName();
+ if (entryCount > 0) {
+ for (int i = entryCount - 1; i >= 0; i--) {
+ BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
+ String entryClassName = getGuidedStepFragmentClassName(entry.getName());
+ if (className.equals(entryClassName)) {
+ fragmentManager.popBackStack(entry.getId(), flags);
+ return;
+ }
+ }
+ }
+ }
+
private void resolveTheme() {
- boolean hasThemeReference = true;
// Look up the guidedStepTheme in the currently specified theme. If it exists,
// replace the theme with its value.
Activity activity = getActivity();
@@ -461,15 +1054,21 @@
boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
if (DEBUG) Log.v(TAG, "Found guided step theme reference? " + found);
if (found) {
- if (isGuidedStepTheme(new ContextThemeWrapper(activity, typedValue.resourceId))) {
+ ContextThemeWrapper themeWrapper =
+ new ContextThemeWrapper(activity, typedValue.resourceId);
+ if (isGuidedStepTheme(themeWrapper)) {
mTheme = typedValue.resourceId;
+ mThemeWrapper = themeWrapper;
} else {
found = false;
+ mThemeWrapper = null;
}
}
if (!found) {
Log.e(TAG, "GuidedStepFragment does not have an appropriate theme set.");
}
+ } else if (mTheme != -1) {
+ mThemeWrapper = new ContextThemeWrapper(activity, mTheme);
}
}
@@ -477,8 +1076,7 @@
if (mTheme == -1) {
return inflater;
} else {
- Context ctw = new ContextThemeWrapper(getActivity(), mTheme);
- return inflater.cloneInContext(ctw);
+ return inflater.cloneInContext(mThemeWrapper);
}
}
@@ -491,41 +1089,20 @@
return 0;
}
- private void performEntryTransition() {
- if (DEBUG) Log.v(TAG, "performEntryTransition");
- final View mainView = getView();
-
- mainView.setVisibility(View.INVISIBLE);
-
+ private void runImeAnimations(boolean entering) {
ArrayList<Animator> animators = new ArrayList<Animator>();
- mGuidanceStylist.onActivityEnter(animators);
- mActionsStylist.onActivityEnter(animators);
-
- final Animator animator = createDummyAnimator(mainView, animators);
-
- // We need to defer the animation until the first layout has occurred, as we don't yet
- // know the final locations of views.
- mainView.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- mainView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- if (!isAdded()) {
- // We have been detached before this could run,
- // so just bail
- return;
- }
-
- mainView.setVisibility(View.VISIBLE);
- animator.start();
- }
- });
- }
-
- private Animator createDummyAnimator(final View v, ArrayList<Animator> animators) {
- final AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playTogether(animators);
- return new UntargetableAnimatorSet(animatorSet);
+ if (entering) {
+ mGuidanceStylist.onImeAppearing(animators);
+ mActionsStylist.onImeAppearing(animators);
+ mButtonActionsStylist.onImeAppearing(animators);
+ } else {
+ mGuidanceStylist.onImeDisappearing(animators);
+ mActionsStylist.onImeDisappearing(animators);
+ mButtonActionsStylist.onImeDisappearing(animators);
+ }
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(animators);
+ set.start();
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
new file mode 100644
index 0000000..ad186ff
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
@@ -0,0 +1,1110 @@
+/* This file is auto-generated from GuidedStepFragment.java. DO NOT MODIFY. */
+
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentManager.BackStackEntry;
+import android.support.v4.app.FragmentTransaction;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.GuidanceStylist;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A GuidedStepSupportFragment is used to guide the user through a decision or series of decisions.
+ * It is composed of a guidance view on the left and a view on the right containing a list of
+ * possible actions.
+ * <p>
+ * <h3>Basic Usage</h3>
+ * <p>
+ * Clients of GuidedStepSupportFragment must create a custom subclass to attach to their Activities.
+ * This custom subclass provides the information necessary to construct the user interface and
+ * respond to user actions. At a minimum, subclasses should override:
+ * <ul>
+ * <li>{@link #onCreateGuidance}, to provide instructions to the user</li>
+ * <li>{@link #onCreateActions}, to provide a set of {@link GuidedAction}s the user can take</li>
+ * <li>{@link #onGuidedActionClicked}, to respond to those actions</li>
+ * </ul>
+ * <p>
+ * Clients use following helper functions to add GuidedStepSupportFragment to Activity or FragmentManager:
+ * <ul>
+ * <li>{@link #addAsRoot(FragmentActivity, GuidedStepSupportFragment, int)}, to be called during Activity onCreate,
+ * adds GuidedStepSupportFragment as the first Fragment in activity.</li>
+ * <li>{@link #add(FragmentManager, GuidedStepSupportFragment)} or {@link #add(FragmentManager,
+ * GuidedStepSupportFragment, int)}, to add GuidedStepSupportFragment on top of existing Fragments or
+ * replacing existing GuidedStepSupportFragment when moving forward to next step.</li>
+ * <li>{@link #finishGuidedStepSupportFragments()} can either finish the activity or pop all
+ * GuidedStepSupportFragment from stack.
+ * <li>If app chooses not to use the helper function, it is the app's responsibility to call
+ * {@link #setUiStyle(int)} to select fragment transition and remember the stack entry where it
+ * need pops to.
+ * </ul>
+ * <h3>Theming and Stylists</h3>
+ * <p>
+ * GuidedStepSupportFragment delegates its visual styling to classes called stylists. The {@link
+ * GuidanceStylist} is responsible for the left guidance view, while the {@link
+ * GuidedActionsStylist} is responsible for the right actions view. The stylists use theme
+ * attributes to derive values associated with the presentation, such as colors, animations, etc.
+ * Most simple visual aspects of GuidanceStylist and GuidedActionsStylist can be customized
+ * via theming; see their documentation for more information.
+ * <p>
+ * GuidedStepSupportFragments must have access to an appropriate theme in order for the stylists to
+ * function properly. Specifically, the fragment must receive {@link
+ * android.support.v17.leanback.R.style#Theme_Leanback_GuidedStep}, or a theme whose parent is
+ * is set to that theme. Themes can be provided in one of three ways:
+ * <ul>
+ * <li>The simplest way is to set the theme for the host Activity to the GuidedStep theme or a
+ * theme that derives from it.</li>
+ * <li>If the Activity already has a theme and setting its parent theme is inconvenient, the
+ * existing Activity theme can have an entry added for the attribute {@link
+ * android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme}. If present,
+ * this theme will be used by GuidedStepSupportFragment as an overlay to the Activity's theme.</li>
+ * <li>Finally, custom subclasses of GuidedStepSupportFragment may provide a theme through the {@link
+ * #onProvideTheme} method. This can be useful if a subclass is used across multiple
+ * Activities.</li>
+ * </ul>
+ * <p>
+ * If the theme is provided in multiple ways, the onProvideTheme override has priority, followed by
+ * the Activty's theme. (Themes whose parent theme is already set to the guided step theme do not
+ * need to set the guidedStepTheme attribute; if set, it will be ignored.)
+ * <p>
+ * If themes do not provide enough customizability, the stylists themselves may be subclassed and
+ * provided to the GuidedStepSupportFragment through the {@link #onCreateGuidanceStylist} and {@link
+ * #onCreateActionsStylist} methods. The stylists have simple hooks so that subclasses
+ * may override layout files; subclasses may also have more complex logic to determine styling.
+ * <p>
+ * <h3>Guided sequences</h3>
+ * <p>
+ * GuidedStepSupportFragments can be grouped together to provide a guided sequence. GuidedStepSupportFragments
+ * grouped as a sequence use custom animations provided by {@link GuidanceStylist} and
+ * {@link GuidedActionsStylist} (or subclasses) during transitions between steps. Clients
+ * should use {@link #add} to place subsequent GuidedFragments onto the fragment stack so that
+ * custom animations are properly configured. (Custom animations are triggered automatically when
+ * the fragment stack is subsequently popped by any normal mechanism.)
+ * <p>
+ * <i>Note: Currently GuidedStepSupportFragments grouped in this way must all be defined programmatically,
+ * rather than in XML. This restriction may be removed in the future.</i>
+ *
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepBackground
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeight
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthWeightTwoPanels
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackground
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsBackgroundDark
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsElevation
+ * @see GuidanceStylist
+ * @see GuidanceStylist.Guidance
+ * @see GuidedAction
+ * @see GuidedActionsStylist
+ */
+public class GuidedStepSupportFragment extends Fragment implements GuidedActionAdapter.ClickListener,
+ GuidedActionAdapter.FocusListener {
+
+ private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepSupportFragment";
+ private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
+
+ private static final String ENTRY_NAME_REPLACE = "GuidedStepDefault";
+
+ private static final String ENTRY_NAME_ENTRANCE = "GuidedStepEntrance";
+
+ /**
+ * Fragment argument name for UI style. The argument value is persisted in fragment state.
+ * The value is initially {@link #UI_STYLE_ENTRANCE} and might be changed in one of the three
+ * helper functions:
+ * <ul>
+ * <li>{@link #addAsRoot(FragmentActivity, GuidedStepSupportFragment, int)}</li>
+ * <li>{@link #add(FragmentManager, GuidedStepSupportFragment)} or {@link #add(FragmentManager,
+ * GuidedStepSupportFragment, int)}</li>
+ * </ul>
+ * <p>
+ * Argument value can be either:
+ * <ul>
+ * <li>{@link #UI_STYLE_REPLACE}</li>
+ * <li>{@link #UI_STYLE_ENTRANCE}</li>
+ * <li>{@link #UI_STYLE_ACTIVITY_ROOT}</li>
+ * </ul>
+ */
+ public static final String EXTRA_UI_STYLE = "uiStyle";
+
+ /**
+ * This is the case that we use GuidedStepSupportFragment to replace another existing
+ * GuidedStepSupportFragment when moving forward to next step. Default behavior of this style is:
+ * <ul>
+ * <li>Enter transition slides in from END(right), exit transition same as
+ * {@link #UI_STYLE_ENTRANCE}.
+ * </li>
+ * </ul>
+ */
+ public static final int UI_STYLE_REPLACE = 0;
+
+ /**
+ * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned in
+ * GuidedStepSupportFragment constructor. This is the case that we show GuidedStepSupportFragment on top of
+ * other content. The default behavior of this style:
+ * <ul>
+ * <li>Enter transition slides in from two sides, exit transition slide out to START(left).
+ * Background will be faded in. Note: Changing exit transition by UI style is not working
+ * because fragment transition asks for exit transition before UI style is restored in Fragment
+ * .onCreate().</li>
+ * </ul>
+ */
+ public static final int UI_STYLE_ENTRANCE = 1;
+
+ /**
+ * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
+ * GuidedStepSupportFragment in a separate activity. The default behavior of this style:
+ * <ul>
+ * <li>Enter transition is assigned null (will rely on activity transition), exit transition is
+ * same as {@link #UI_STYLE_ENTRANCE}. Note: Changing exit transition by UI style is not working
+ * because fragment transition asks for exit transition before UI style is restored in
+ * Fragment.onCreate().</li>
+ * </ul>
+ */
+ public static final int UI_STYLE_ACTIVITY_ROOT = 2;
+
+ private static final String TAG = "GuidedStepSupportFragment";
+ private static final boolean DEBUG = false;
+
+ private int mTheme;
+ private ContextThemeWrapper mThemeWrapper;
+ private GuidanceStylist mGuidanceStylist;
+ private GuidedActionsStylist mActionsStylist;
+ private GuidedActionsStylist mButtonActionsStylist;
+ private GuidedActionAdapter mAdapter;
+ private GuidedActionAdapter mButtonAdapter;
+ private GuidedActionAdapterGroup mAdapterGroup;
+ private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
+ private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
+ private int mSelectedIndex = -1;
+ private int mButtonSelectedIndex = -1;
+
+ public GuidedStepSupportFragment() {
+ // We need to supply the theme before any potential call to onInflate in order
+ // for the defaulting to work properly.
+ mTheme = onProvideTheme();
+ mGuidanceStylist = onCreateGuidanceStylist();
+ mActionsStylist = onCreateActionsStylist();
+ mButtonActionsStylist = onCreateButtonActionsStylist();
+ onProvideFragmentTransitions();
+ }
+
+ /**
+ * Creates the presenter used to style the guidance panel. The default implementation returns
+ * a basic GuidanceStylist.
+ * @return The GuidanceStylist used in this fragment.
+ */
+ public GuidanceStylist onCreateGuidanceStylist() {
+ return new GuidanceStylist();
+ }
+
+ /**
+ * Creates the presenter used to style the guided actions panel. The default implementation
+ * returns a basic GuidedActionsStylist.
+ * @return The GuidedActionsStylist used in this fragment.
+ */
+ public GuidedActionsStylist onCreateActionsStylist() {
+ return new GuidedActionsStylist();
+ }
+
+ /**
+ * Creates the presenter used to style a sided actions panel for button only.
+ * The default implementation returns a basic GuidedActionsStylist.
+ * @return The GuidedActionsStylist used in this fragment.
+ */
+ public GuidedActionsStylist onCreateButtonActionsStylist() {
+ return new GuidedActionsStylist();
+ }
+
+ /**
+ * Returns the theme used for styling the fragment. The default returns -1, indicating that the
+ * host Activity's theme should be used.
+ * @return The theme resource ID of the theme to use in this fragment, or -1 to use the
+ * host Activity's theme.
+ */
+ public int onProvideTheme() {
+ return -1;
+ }
+
+ /**
+ * Returns the information required to provide guidance to the user. This hook is called during
+ * {@link #onCreateView}. May be overridden to return a custom subclass of {@link
+ * GuidanceStylist.Guidance} for use in a subclass of {@link GuidanceStylist}. The default
+ * returns a Guidance object with empty fields; subclasses should override.
+ * @param savedInstanceState The saved instance state from onCreateView.
+ * @return The Guidance object representing the information used to guide the user.
+ */
+ public @NonNull Guidance onCreateGuidance(Bundle savedInstanceState) {
+ return new Guidance("", "", "", null);
+ }
+
+ /**
+ * Fills out the set of actions available to the user. This hook is called during {@link
+ * #onCreate}. The default leaves the list of actions empty; subclasses should override.
+ * @param actions A non-null, empty list ready to be populated.
+ * @param savedInstanceState The saved instance state from onCreate.
+ */
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ }
+
+ /**
+ * Fills out the set of actions shown at right available to the user. This hook is called during
+ * {@link #onCreate}. The default leaves the list of actions empty; subclasses may override.
+ * @param actions A non-null, empty list ready to be populated.
+ * @param savedInstanceState The saved instance state from onCreate.
+ */
+ public void onCreateButtonActions(@NonNull List<GuidedAction> actions,
+ Bundle savedInstanceState) {
+ }
+
+ /**
+ * Callback invoked when an action is taken by the user. Subclasses should override in
+ * order to act on the user's decisions.
+ * @param action The chosen action.
+ */
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ }
+
+ /**
+ * Callback invoked when an action is focused (made to be the current selection) by the user.
+ */
+ @Override
+ public void onGuidedActionFocused(GuidedAction action) {
+ }
+
+ /**
+ * Callback invoked when an action's title or description has been edited.
+ * Override {@link #onGuidedActionEditedAndProceed(GuidedAction)} instead of app wants to
+ * control the next action to focus on.
+ */
+ public void onGuidedActionEdited(GuidedAction action) {
+ }
+
+ /**
+ * Callback invoked when an action's title or description has been edited. Default
+ * implementation calls {@link #onGuidedActionEdited(GuidedAction)} and returns
+ * {@link GuidedAction#ACTION_ID_NEXT}.
+ *
+ * @param action The action that has been edited.
+ * @return ID of the action will be focused or {@link GuidedAction#ACTION_ID_NEXT},
+ * {@link GuidedAction#ACTION_ID_CURRENT}.
+ */
+ public long onGuidedActionEditedAndProceed(GuidedAction action) {
+ onGuidedActionEdited(action);
+ return GuidedAction.ACTION_ID_NEXT;
+ }
+
+ /**
+ * Adds the specified GuidedStepSupportFragment to the fragment stack, replacing any existing
+ * GuidedStepSupportFragments in the stack, and configuring the fragment-to-fragment custom
+ * transitions. A backstack entry is added, so the fragment will be dismissed when BACK key
+ * is pressed.
+ * <li>If current fragment on stack is GuidedStepSupportFragment: assign {@link #UI_STYLE_REPLACE}
+ * <li>If current fragment on stack is not GuidedStepSupportFragment: assign {@link #UI_STYLE_ENTRANCE}
+ * <p>
+ * Note: currently fragments added using this method must be created programmatically rather
+ * than via XML.
+ * @param fragmentManager The FragmentManager to be used in the transaction.
+ * @param fragment The GuidedStepSupportFragment to be inserted into the fragment stack.
+ * @return The ID returned by the call FragmentTransaction.replace.
+ */
+ public static int add(FragmentManager fragmentManager, GuidedStepSupportFragment fragment) {
+ return add(fragmentManager, fragment, android.R.id.content);
+ }
+
+ /**
+ * Adds the specified GuidedStepSupportFragment to the fragment stack, replacing any existing
+ * GuidedStepSupportFragments in the stack, and configuring the fragment-to-fragment custom
+ * transitions. A backstack entry is added, so the fragment will be dismissed when BACK key
+ * is pressed.
+ * <li>If current fragment on stack is GuidedStepSupportFragment: assign {@link #UI_STYLE_REPLACE} and
+ * {@link #onAddSharedElementTransition(FragmentTransaction, GuidedStepSupportFragment)} will be called
+ * to perform shared element transition between GuidedStepSupportFragments.
+ * <li>If current fragment on stack is not GuidedStepSupportFragment: assign {@link #UI_STYLE_ENTRANCE}
+ * <p>
+ * Note: currently fragments added using this method must be created programmatically rather
+ * than via XML.
+ * @param fragmentManager The FragmentManager to be used in the transaction.
+ * @param fragment The GuidedStepSupportFragment to be inserted into the fragment stack.
+ * @param id The id of container to add GuidedStepSupportFragment, can be android.R.id.content.
+ * @return The ID returned by the call FragmentTransaction.replace.
+ */
+ public static int add(FragmentManager fragmentManager, GuidedStepSupportFragment fragment, int id) {
+ GuidedStepSupportFragment current = getCurrentGuidedStepSupportFragment(fragmentManager);
+ boolean inGuidedStep = current != null;
+ FragmentTransaction ft = fragmentManager.beginTransaction();
+
+ fragment.setUiStyle(inGuidedStep ? UI_STYLE_REPLACE : UI_STYLE_ENTRANCE);
+ ft.addToBackStack(fragment.generateStackEntryName());
+ if (current != null) {
+ fragment.onAddSharedElementTransition(ft, current);
+ }
+ return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
+ }
+
+ /**
+ * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_REPLACE} (aka
+ * when the GuidedStepSupportFragment replacing an existing GuidedStepSupportFragment). Default implementation
+ * establishes connections between action background views to morph action background bounds
+ * change from disappearing GuidedStepSupportFragment into this GuidedStepSupportFragment. The default
+ * implementation heavily relies on {@link GuidedActionsStylist}'s layout, app may override this
+ * method when modifying the default layout of {@link GuidedActionsStylist}.
+ *
+ * @see GuidedActionsStylist
+ * @see #onProvideFragmentTransitions()
+ * @param ft The FragmentTransaction to add shared element.
+ * @param disappearing The disappearing fragment.
+ */
+ protected void onAddSharedElementTransition(FragmentTransaction ft, GuidedStepSupportFragment
+ disappearing) {
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.action_fragment_root), "action_fragment_root");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.action_fragment_background), "action_fragment_background");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.action_fragment), "action_fragment");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_root), "guidedactions_root");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_selector), "guidedactions_selector");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_content), "guidedactions_content");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_list_background), "guidedactions_list_background");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_root2), "guidedactions_root2");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_selector2), "guidedactions_selector2");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_content2), "guidedactions_content2");
+ TransitionHelper.addSharedElement(ft, disappearing.getView().findViewById(
+ R.id.guidedactions_list_background2), "guidedactions_list_background2");
+ }
+
+ /**
+ * Returns BackStackEntry name for the GuidedStepSupportFragment or empty String if no entry is
+ * associated. Note {@link #UI_STYLE_ACTIVITY_ROOT} will return empty String. The method
+ * returns undefined value if the fragment is not in FragmentManager.
+ * @return BackStackEntry name for the GuidedStepSupportFragment or empty String if no entry is
+ * associated.
+ */
+ public String generateStackEntryName() {
+ return generateStackEntryName(getUiStyle(), getClass());
+ }
+
+ /**
+ * Generates BackStackEntry name for GuidedStepSupportFragment class or empty String if no entry is
+ * associated. Note {@link #UI_STYLE_ACTIVITY_ROOT} is not allowed and returns empty String.
+ * @param uiStyle {@link #UI_STYLE_REPLACE} or {@link #UI_STYLE_ENTRANCE}
+ * @return BackStackEntry name for the GuidedStepSupportFragment or empty String if no entry is
+ * associated.
+ */
+ public static String generateStackEntryName(int uiStyle, Class guidedStepFragmentClass) {
+ if (!GuidedStepSupportFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
+ return "";
+ }
+ switch (uiStyle) {
+ case UI_STYLE_REPLACE:
+ return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
+ case UI_STYLE_ENTRANCE:
+ return ENTRY_NAME_ENTRANCE + guidedStepFragmentClass.getName();
+ case UI_STYLE_ACTIVITY_ROOT:
+ default:
+ return "";
+ }
+ }
+
+ /**
+ * Returns true if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_ENTRANCE};
+ * false otherwise.
+ * @param backStackEntryName Name of BackStackEntry.
+ * @return True if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_ENTRANCE};
+ * false otherwise.
+ */
+ public static boolean isUiStyleEntrance(String backStackEntryName) {
+ return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE);
+ }
+
+ /**
+ * Returns true if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_REPLACE};
+ * false otherwise.
+ * @param backStackEntryName Name of BackStackEntry.
+ * @return True if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_REPLACE};
+ * false otherwise.
+ */
+ public static boolean isUiStyleDefault(String backStackEntryName) {
+ return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_REPLACE);
+ }
+
+ /**
+ * Extract Class name from BackStackEntry name.
+ * @param backStackEntryName Name of BackStackEntry.
+ * @return Class name of GuidedStepSupportFragment.
+ */
+ public static String getGuidedStepSupportFragmentClassName(String backStackEntryName) {
+ if (backStackEntryName.startsWith(ENTRY_NAME_REPLACE)) {
+ return backStackEntryName.substring(ENTRY_NAME_REPLACE.length());
+ } else if (backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE)) {
+ return backStackEntryName.substring(ENTRY_NAME_ENTRANCE.length());
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Adds the specified GuidedStepSupportFragment as content of Activity; no backstack entry is added so
+ * the activity will be dismissed when BACK key is pressed.
+ * {@link #UI_STYLE_ACTIVITY_ROOT} is assigned.
+ *
+ * Note: currently fragments added using this method must be created programmatically rather
+ * than via XML.
+ * @param activity The Activity to be used to insert GuidedstepFragment.
+ * @param fragment The GuidedStepSupportFragment to be inserted into the fragment stack.
+ * @param id The id of container to add GuidedStepSupportFragment, can be android.R.id.content.
+ * @return The ID returned by the call FragmentTransaction.replace.
+ */
+ public static int addAsRoot(FragmentActivity activity, GuidedStepSupportFragment fragment, int id) {
+ // Workaround b/23764120: call getDecorView() to force requestFeature of ActivityTransition.
+ activity.getWindow().getDecorView();
+
+ FragmentManager fragmentManager = activity.getSupportFragmentManager();
+ FragmentTransaction ft = fragmentManager.beginTransaction();
+ fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
+ return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
+ }
+
+ /**
+ * Returns the current GuidedStepSupportFragment on the fragment transaction stack.
+ * @return The current GuidedStepSupportFragment, if any, on the fragment transaction stack.
+ */
+ public static GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(FragmentManager fm) {
+ Fragment f = fm.findFragmentByTag(TAG_LEAN_BACK_ACTIONS_FRAGMENT);
+ if (f instanceof GuidedStepSupportFragment) {
+ return (GuidedStepSupportFragment) f;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the GuidanceStylist that displays guidance information for the user.
+ * @return The GuidanceStylist for this fragment.
+ */
+ public GuidanceStylist getGuidanceStylist() {
+ return mGuidanceStylist;
+ }
+
+ /**
+ * Returns the GuidedActionsStylist that displays the actions the user may take.
+ * @return The GuidedActionsStylist for this fragment.
+ */
+ public GuidedActionsStylist getGuidedActionsStylist() {
+ return mActionsStylist;
+ }
+
+ /**
+ * Returns the list of button GuidedActions that the user may take in this fragment.
+ * @return The list of button GuidedActions for this fragment.
+ */
+ public List<GuidedAction> getButtonActions() {
+ return mButtonActions;
+ }
+
+ /**
+ * Find button GuidedAction by Id.
+ * @param id Id of the button action to search.
+ * @return GuidedAction object or null if not found.
+ */
+ public GuidedAction findButtonActionById(long id) {
+ int index = findButtonActionPositionById(id);
+ return index >= 0 ? mButtonActions.get(index) : null;
+ }
+
+ /**
+ * Find button GuidedAction position in array by Id.
+ * @param id Id of the button action to search.
+ * @return position of GuidedAction object in array or -1 if not found.
+ */
+ public int findButtonActionPositionById(long id) {
+ if (mButtonActions != null) {
+ for (int i = 0; i < mButtonActions.size(); i++) {
+ GuidedAction action = mButtonActions.get(i);
+ if (mButtonActions.get(i).getId() == id) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the GuidedActionsStylist that displays the button actions the user may take.
+ * @return The GuidedActionsStylist for this fragment.
+ */
+ public GuidedActionsStylist getGuidedButtonActionsStylist() {
+ return mButtonActionsStylist;
+ }
+
+ /**
+ * Sets the list of button GuidedActions that the user may take in this fragment.
+ * @param actions The list of button GuidedActions for this fragment.
+ */
+ public void setButtonActions(List<GuidedAction> actions) {
+ mButtonActions = actions;
+ if (mButtonAdapter != null) {
+ mButtonAdapter.setActions(mButtonActions);
+ }
+ }
+
+ /**
+ * Notify an button action has changed and update its UI.
+ * @param position Position of the button GuidedAction in array.
+ */
+ public void notifyButtonActionChanged(int position) {
+ if (mButtonAdapter != null) {
+ mButtonAdapter.notifyItemChanged(position);
+ }
+ }
+
+ /**
+ * Returns the view corresponding to the button action at the indicated position in the list of
+ * actions for this fragment.
+ * @param position The integer position of the button action of interest.
+ * @return The View corresponding to the button action at the indicated position, or null if
+ * that action is not currently onscreen.
+ */
+ public View getButtonActionItemView(int position) {
+ final RecyclerView.ViewHolder holder = mButtonActionsStylist.getActionsGridView()
+ .findViewHolderForPosition(position);
+ return holder == null ? null : holder.itemView;
+ }
+
+ /**
+ * Scrolls the action list to the position indicated, selecting that button action's view.
+ * @param position The integer position of the button action of interest.
+ */
+ public void setSelectedButtonActionPosition(int position) {
+ mButtonActionsStylist.getActionsGridView().setSelectedPosition(position);
+ }
+
+ /**
+ * Returns the position if the currently selected button GuidedAction.
+ * @return position The integer position of the currently selected button action.
+ */
+ public int getSelectedButtonActionPosition() {
+ return mButtonActionsStylist.getActionsGridView().getSelectedPosition();
+ }
+
+ /**
+ * Returns the list of GuidedActions that the user may take in this fragment.
+ * @return The list of GuidedActions for this fragment.
+ */
+ public List<GuidedAction> getActions() {
+ return mActions;
+ }
+
+ /**
+ * Find GuidedAction by Id.
+ * @param id Id of the action to search.
+ * @return GuidedAction object or null if not found.
+ */
+ public GuidedAction findActionById(long id) {
+ int index = findActionPositionById(id);
+ return index >= 0 ? mActions.get(index) : null;
+ }
+
+ /**
+ * Find GuidedAction position in array by Id.
+ * @param id Id of the action to search.
+ * @return position of GuidedAction object in array or -1 if not found.
+ */
+ public int findActionPositionById(long id) {
+ if (mActions != null) {
+ for (int i = 0; i < mActions.size(); i++) {
+ GuidedAction action = mActions.get(i);
+ if (mActions.get(i).getId() == id) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Sets the list of GuidedActions that the user may take in this fragment.
+ * @param actions The list of GuidedActions for this fragment.
+ */
+ public void setActions(List<GuidedAction> actions) {
+ mActions = actions;
+ if (mAdapter != null) {
+ mAdapter.setActions(mActions);
+ }
+ }
+
+ /**
+ * Notify an action has changed and update its UI.
+ * @param position Position of the GuidedAction in array.
+ */
+ public void notifyActionChanged(int position) {
+ if (mAdapter != null) {
+ mAdapter.notifyItemChanged(position);
+ }
+ }
+
+ /**
+ * Returns the view corresponding to the action at the indicated position in the list of
+ * actions for this fragment.
+ * @param position The integer position of the action of interest.
+ * @return The View corresponding to the action at the indicated position, or null if that
+ * action is not currently onscreen.
+ */
+ public View getActionItemView(int position) {
+ final RecyclerView.ViewHolder holder = mActionsStylist.getActionsGridView()
+ .findViewHolderForPosition(position);
+ return holder == null ? null : holder.itemView;
+ }
+
+ /**
+ * Scrolls the action list to the position indicated, selecting that action's view.
+ * @param position The integer position of the action of interest.
+ */
+ public void setSelectedActionPosition(int position) {
+ mActionsStylist.getActionsGridView().setSelectedPosition(position);
+ }
+
+ /**
+ * Returns the position if the currently selected GuidedAction.
+ * @return position The integer position of the currently selected action.
+ */
+ public int getSelectedActionPosition() {
+ return mActionsStylist.getActionsGridView().getSelectedPosition();
+ }
+
+ /**
+ * Called by Constructor to provide fragment transitions. The default implementation assigns
+ * transitions based on {@link #getUiStyle()}:
+ * <ul>
+ * <li> {@link #UI_STYLE_REPLACE} Slide from/to end(right) for enter transition, slide from/to
+ * start(left) for exit transition, shared element enter transition is set to ChangeBounds.
+ * <li> {@link #UI_STYLE_ENTRANCE} Enter transition is set to slide from both sides, exit
+ * transition is same as {@link #UI_STYLE_REPLACE}, no shared element enter transition.
+ * <li> {@link #UI_STYLE_ACTIVITY_ROOT} Enter transition is set to null and app should rely on
+ * activity transition, exit transition is same as {@link #UI_STYLE_REPLACE}, no shared element
+ * enter transition.
+ * </ul>
+ * <p>
+ * The default implementation heavily relies on {@link GuidedActionsStylist} and
+ * {@link GuidanceStylist} layout, app may override this method when modifying the default
+ * layout of {@link GuidedActionsStylist} or {@link GuidanceStylist}.
+ * <p>
+ * TIP: because the fragment view is removed during fragment transition, in general app cannot
+ * use two Visibility transition together. Workaround is to create your own Visibility
+ * transition that controls multiple animators (e.g. slide and fade animation in one Transition
+ * class).
+ */
+ protected void onProvideFragmentTransitions() {
+ if (Build.VERSION.SDK_INT >= 21) {
+ final int uiStyle = getUiStyle();
+ if (uiStyle == UI_STYLE_REPLACE) {
+ Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END);
+ TransitionHelper.exclude(enterTransition, R.id.guidedstep_background, true);
+ TransitionHelper.setEnterTransition(this, enterTransition);
+
+ Object changeBounds = TransitionHelper.createChangeBounds(false);
+ TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
+ } else if (uiStyle == UI_STYLE_ENTRANCE) {
+ Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
+ TransitionHelper.FADE_OUT);
+ TransitionHelper.include(fade, R.id.guidedstep_background);
+ Object slide = TransitionHelper.createFadeAndShortSlide(Gravity.END |
+ Gravity.START);
+ TransitionHelper.include(slide, R.id.content_fragment);
+ TransitionHelper.include(slide, R.id.action_fragment_root);
+ Object enterTransition = TransitionHelper.createTransitionSet(false);
+ TransitionHelper.addTransition(enterTransition, fade);
+ TransitionHelper.addTransition(enterTransition, slide);
+ TransitionHelper.setEnterTransition(this, enterTransition);
+
+ // No shared element transition
+ TransitionHelper.setSharedElementEnterTransition(this, null);
+ } else if (uiStyle == UI_STYLE_ACTIVITY_ROOT) {
+ // for Activity root, we dont need enter transition, use activity transition
+ TransitionHelper.setEnterTransition(this, null);
+ // No shared element transition
+ TransitionHelper.setSharedElementEnterTransition(this, null);
+ }
+ // exitTransition is same for all style
+ Object exitTransition = TransitionHelper.createFadeAndShortSlide(Gravity.START);
+ TransitionHelper.exclude(exitTransition, R.id.guidedstep_background, true);
+ TransitionHelper.setExitTransition(this, exitTransition);
+ }
+ }
+
+ /**
+ * Called by onCreateView to inflate background view. Default implementation loads view
+ * from {@link R.layout#lb_guidedstep_background} which holds a reference to
+ * guidedStepBackground.
+ * @param inflater LayoutInflater to load background view.
+ * @param container Parent view of background view.
+ * @param savedInstanceState
+ * @return Created background view or null if no background.
+ */
+ public View onCreateBackgroundView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
+ }
+
+ /**
+ * Set UI style to fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when fragment
+ * is first initialized. UI style is used to choose different fragment transition animations and
+ * determine if this is the first GuidedStepSupportFragment on backstack. In most cases app does not
+ * directly call this method, app calls helper function
+ * {@link #add(FragmentManager, GuidedStepSupportFragment, int)}. However if the app creates Fragment
+ * transaction and controls backstack by itself, it would need call setUiStyle() to select the
+ * fragment transition to use.
+ *
+ * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+ * {@link #UI_STYLE_ENTRANCE}.
+ */
+ public void setUiStyle(int style) {
+ int oldStyle = getUiStyle();
+ Bundle arguments = getArguments();
+ boolean isNew = false;
+ if (arguments == null) {
+ arguments = new Bundle();
+ isNew = true;
+ }
+ arguments.putInt(EXTRA_UI_STYLE, style);
+ // call setArgument() will validate if the fragment is already added.
+ if (isNew) {
+ setArguments(arguments);
+ }
+ if (style != oldStyle) {
+ onProvideFragmentTransitions();
+ }
+ }
+
+ /**
+ * Read UI style from fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when
+ * fragment is first initialized. UI style is used to choose different fragment transition
+ * animations and determine if this is the first GuidedStepSupportFragment on backstack.
+ *
+ * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+ * {@link #UI_STYLE_ENTRANCE}.
+ * @see #onProvideFragmentTransitions()
+ */
+ public int getUiStyle() {
+ Bundle b = getArguments();
+ if (b == null) return UI_STYLE_ENTRANCE;
+ return b.getInt(EXTRA_UI_STYLE, UI_STYLE_ENTRANCE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (DEBUG) Log.v(TAG, "onCreate");
+ // Set correct transition from saved arguments.
+ onProvideFragmentTransitions();
+ Bundle state = (savedInstanceState != null) ? savedInstanceState : getArguments();
+ if (state != null) {
+ if (mSelectedIndex == -1) {
+ mSelectedIndex = state.getInt(EXTRA_ACTION_SELECTED_INDEX, -1);
+ }
+ }
+ ArrayList<GuidedAction> actions = new ArrayList<GuidedAction>();
+ onCreateActions(actions, savedInstanceState);
+ setActions(actions);
+ ArrayList<GuidedAction> buttonActions = new ArrayList<GuidedAction>();
+ onCreateButtonActions(buttonActions, savedInstanceState);
+ setButtonActions(buttonActions);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDestroyView() {
+ mGuidanceStylist.onDestroyView();
+ mActionsStylist.onDestroyView();
+ mButtonActionsStylist.onDestroyView();
+ mAdapter = null;
+ mButtonAdapter = null;
+ mAdapterGroup = null;
+ super.onDestroyView();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ if (DEBUG) Log.v(TAG, "onCreateView");
+
+ resolveTheme();
+ inflater = getThemeInflater(inflater);
+
+ ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_guidedstep_fragment,
+ container, false);
+ ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
+ ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
+
+ Guidance guidance = onCreateGuidance(savedInstanceState);
+ View guidanceView = mGuidanceStylist.onCreateView(inflater, guidanceContainer, guidance);
+ guidanceContainer.addView(guidanceView);
+
+ View actionsView = mActionsStylist.onCreateView(inflater, actionContainer);
+ actionContainer.addView(actionsView);
+
+ View buttonActionsView = mButtonActionsStylist.onCreateView(inflater, actionContainer);
+ mButtonActionsStylist.setAsButtonActions();
+ actionContainer.addView(buttonActionsView);
+
+ GuidedActionAdapter.EditListener editListener = new GuidedActionAdapter.EditListener() {
+
+ @Override
+ public void onImeOpen() {
+ runImeAnimations(true);
+ }
+
+ @Override
+ public void onImeClose() {
+ runImeAnimations(false);
+ }
+
+ @Override
+ public long onGuidedActionEdited(GuidedAction action) {
+ return GuidedStepSupportFragment.this.onGuidedActionEditedAndProceed(action);
+ }
+ };
+
+ mAdapter = new GuidedActionAdapter(mActions, this, this, mActionsStylist);
+ mButtonAdapter = new GuidedActionAdapter(mButtonActions, this, this, mButtonActionsStylist);
+ mAdapterGroup = new GuidedActionAdapterGroup();
+ mAdapterGroup.addAdpter(mAdapter);
+ mAdapterGroup.addAdpter(mButtonAdapter);
+ mAdapterGroup.setEditListener(editListener);
+
+ mActionsStylist.getActionsGridView().setAdapter(mAdapter);
+ mButtonActionsStylist.getActionsGridView().setAdapter(mButtonAdapter);
+ if (mButtonActions.size() == 0) {
+ // when there is no button actions, we dont need show the second panel, but keep
+ // the width zero to run ChangeBounds transition.
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ buttonActionsView.getLayoutParams();
+ lp.weight = 0;
+ buttonActionsView.setLayoutParams(lp);
+ } else {
+ // when there are two actions panel, we need adjust the weight of action to
+ // guidedActionContentWidthWeightTwoPanels.
+ Context ctx = mThemeWrapper != null ? mThemeWrapper : getActivity();
+ TypedValue typedValue = new TypedValue();
+ if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
+ typedValue, true)) {
+ View actionsRoot = root.findViewById(R.id.action_fragment_root);
+ float weight = typedValue.getFloat();
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) actionsRoot
+ .getLayoutParams();
+ lp.weight = weight;
+ actionsRoot.setLayoutParams(lp);
+ }
+ }
+
+ int pos = (mSelectedIndex >= 0 && mSelectedIndex < mActions.size()) ?
+ mSelectedIndex : getFirstCheckedAction();
+ setSelectedActionPosition(pos);
+
+ setSelectedButtonActionPosition(0);
+
+ View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
+ if (backgroundView != null) {
+ root.addView(backgroundView, 0);
+ }
+ return root;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mActionsStylist.getActionsGridView().requestFocus();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(EXTRA_ACTION_SELECTED_INDEX,
+ (mActionsStylist.getActionsGridView() != null) ?
+ getSelectedActionPosition() : mSelectedIndex);
+ }
+
+ private static boolean isGuidedStepTheme(Context context) {
+ int resId = R.attr.guidedStepThemeFlag;
+ TypedValue typedValue = new TypedValue();
+ boolean found = context.getTheme().resolveAttribute(resId, typedValue, true);
+ if (DEBUG) Log.v(TAG, "Found guided step theme flag? " + found);
+ return found && typedValue.type == TypedValue.TYPE_INT_BOOLEAN && typedValue.data != 0;
+ }
+
+ /**
+ * Convenient method to close GuidedStepSupportFragments on top of other content or finish Activity if
+ * GuidedStepSupportFragments were started in a separate activity. Pops all stack entries including
+ * {@link #UI_STYLE_ENTRANCE}; if {@link #UI_STYLE_ENTRANCE} is not found, finish the activity.
+ * Note that this method must be paired with {@link #add(FragmentManager, GuidedStepSupportFragment,
+ * int)} which sets up the stack entry name for finding which fragment we need to pop back to.
+ */
+ public void finishGuidedStepSupportFragments() {
+ final FragmentManager fragmentManager = getFragmentManager();
+ final int entryCount = fragmentManager.getBackStackEntryCount();
+ if (entryCount > 0) {
+ for (int i = entryCount - 1; i >= 0; i--) {
+ BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
+ if (isUiStyleEntrance(entry.getName())) {
+ GuidedStepSupportFragment top = getCurrentGuidedStepSupportFragment(fragmentManager);
+ if (top != null) {
+ top.setUiStyle(UI_STYLE_ENTRANCE);
+ }
+ fragmentManager.popBackStack(entry.getId(),
+ FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ return;
+ }
+ }
+ }
+ ActivityCompat.finishAfterTransition(getActivity());
+ }
+
+ /**
+ * Convenient method to pop to fragment with Given class.
+ * @param guidedStepFragmentClass Name of the Class of GuidedStepSupportFragment to pop to.
+ * @param flags Either 0 or {@link FragmentManager#POP_BACK_STACK_INCLUSIVE}.
+ */
+ public void popBackStackToGuidedStepSupportFragment(Class guidedStepFragmentClass, int flags) {
+ if (!GuidedStepSupportFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
+ return;
+ }
+ final FragmentManager fragmentManager = getFragmentManager();
+ final int entryCount = fragmentManager.getBackStackEntryCount();
+ String className = guidedStepFragmentClass.getName();
+ if (entryCount > 0) {
+ for (int i = entryCount - 1; i >= 0; i--) {
+ BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
+ String entryClassName = getGuidedStepSupportFragmentClassName(entry.getName());
+ if (className.equals(entryClassName)) {
+ fragmentManager.popBackStack(entry.getId(), flags);
+ return;
+ }
+ }
+ }
+ }
+
+ private void resolveTheme() {
+ // Look up the guidedStepTheme in the currently specified theme. If it exists,
+ // replace the theme with its value.
+ FragmentActivity activity = getActivity();
+ if (mTheme == -1 && !isGuidedStepTheme(activity)) {
+ // Look up the guidedStepTheme in the activity's currently specified theme. If it
+ // exists, replace the theme with its value.
+ int resId = R.attr.guidedStepTheme;
+ TypedValue typedValue = new TypedValue();
+ boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
+ if (DEBUG) Log.v(TAG, "Found guided step theme reference? " + found);
+ if (found) {
+ ContextThemeWrapper themeWrapper =
+ new ContextThemeWrapper(activity, typedValue.resourceId);
+ if (isGuidedStepTheme(themeWrapper)) {
+ mTheme = typedValue.resourceId;
+ mThemeWrapper = themeWrapper;
+ } else {
+ found = false;
+ mThemeWrapper = null;
+ }
+ }
+ if (!found) {
+ Log.e(TAG, "GuidedStepSupportFragment does not have an appropriate theme set.");
+ }
+ } else if (mTheme != -1) {
+ mThemeWrapper = new ContextThemeWrapper(activity, mTheme);
+ }
+ }
+
+ private LayoutInflater getThemeInflater(LayoutInflater inflater) {
+ if (mTheme == -1) {
+ return inflater;
+ } else {
+ return inflater.cloneInContext(mThemeWrapper);
+ }
+ }
+
+ private int getFirstCheckedAction() {
+ for (int i = 0, size = mActions.size(); i < size; i++) {
+ if (mActions.get(i).isChecked()) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ private void runImeAnimations(boolean entering) {
+ ArrayList<Animator> animators = new ArrayList<Animator>();
+ if (entering) {
+ mGuidanceStylist.onImeAppearing(animators);
+ mActionsStylist.onImeAppearing(animators);
+ mButtonActionsStylist.onImeAppearing(animators);
+ } else {
+ mGuidanceStylist.onImeDisappearing(animators);
+ mActionsStylist.onImeDisappearing(animators);
+ mButtonActionsStylist.onImeDisappearing(animators);
+ }
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(animators);
+ set.start();
+ }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
index b2c9b1c..219bb98 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
@@ -138,8 +138,10 @@
if (getBridgeAdapter() != null) {
FocusHighlightHelper.setupHeaderItemFocusHighlight(listView);
}
- view.setBackgroundColor(getBackgroundColor());
- updateFadingEdgeToBrandColor(getBackgroundColor());
+ if (mBackgroundColorSet) {
+ view.setBackgroundColor(mBackgroundColor);
+ updateFadingEdgeToBrandColor(mBackgroundColor);
+ }
updateListViewVisibility();
}
@@ -228,22 +230,6 @@
}
}
- int getBackgroundColor() {
- if (getActivity() == null) {
- throw new IllegalStateException("Activity must be attached");
- }
-
- if (mBackgroundColorSet) {
- return mBackgroundColor;
- }
-
- TypedValue outValue = new TypedValue();
- if (getActivity().getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
- return getResources().getColor(outValue.resourceId);
- }
- return getResources().getColor(R.color.lb_default_brand_color);
- }
-
@Override
void onTransitionStart() {
super.onTransitionStart();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java
index 9c66714..ecf04d8 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java
@@ -140,8 +140,10 @@
if (getBridgeAdapter() != null) {
FocusHighlightHelper.setupHeaderItemFocusHighlight(listView);
}
- view.setBackgroundColor(getBackgroundColor());
- updateFadingEdgeToBrandColor(getBackgroundColor());
+ if (mBackgroundColorSet) {
+ view.setBackgroundColor(mBackgroundColor);
+ updateFadingEdgeToBrandColor(mBackgroundColor);
+ }
updateListViewVisibility();
}
@@ -230,22 +232,6 @@
}
}
- int getBackgroundColor() {
- if (getActivity() == null) {
- throw new IllegalStateException("Activity must be attached");
- }
-
- if (mBackgroundColorSet) {
- return mBackgroundColor;
- }
-
- TypedValue outValue = new TypedValue();
- if (getActivity().getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
- return getResources().getColor(outValue.resourceId);
- }
- return getResources().getColor(R.color.lb_default_brand_color);
- }
-
@Override
void onTransitionStart() {
super.onTransitionStart();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
index 8c56925..e3af403 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
@@ -74,7 +74,7 @@
*/
public abstract class PlaybackControlGlue implements OnActionClickedListener, View.OnKeyListener {
/**
- * The adapter key for the first custom control on the right side
+ * The adapter key for the first custom control on the left side
* of the predefined primary controls.
*/
public static final int ACTION_CUSTOM_LEFT_FIRST = 0x1;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
new file mode 100644
index 0000000..5857e65
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
@@ -0,0 +1,858 @@
+/* This file is auto-generated from PlaybackControlGlue.java. DO NOT MODIFY. */
+
+package android.support.v17.leanback.app;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
+import android.support.v17.leanback.widget.OnActionClickedListener;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.View;
+
+
+/**
+ * A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow} and
+ * {@link PlaybackOverlaySupportFragment} that implements a recommended approach to handling standard
+ * playback control actions such as play/pause, fast forward/rewind at progressive speed levels,
+ * and skip to next/previous. This helper class is a glue layer in that it manages the
+ * configuration of and interaction between the leanback UI components by defining a functional
+ * interface to the media player.
+ *
+ * <p>You can instantiate a concrete subclass such as {@link MediaControllerGlue} or you must
+ * subclass this abstract helper. To create a subclass you must implement all of the
+ * abstract methods and the subclass must invoke {@link #onMetadataChanged()} and
+ * {@link #onStateChanged()} appropriately.
+ * </p>
+ *
+ * <p>To use an instance of the glue layer, first construct an instance. Constructor parameters
+ * inform the glue what speed levels are supported for fast forward/rewind. Providing a
+ * {@link android.support.v17.leanback.app.PlaybackOverlaySupportFragment} is optional.
+ * </p>
+ *
+ * <p>If you have your own controls row you must pass it to {@link #setControlsRow}.
+ * The row will be updated by the glue layer based on the media metadata and playback state.
+ * Alternatively, you may call {@link #createControlsRowAndPresenter()} which will set a controls
+ * row and return a row presenter you can use to present the row.
+ * </p>
+ *
+ * <p>The helper sets a {@link android.support.v17.leanback.widget.SparseArrayObjectAdapter}
+ * on the controls row as the primary actions adapter, and adds actions to it. You can provide
+ * additional actions by overriding {@link #createPrimaryActionsAdapter}. This helper does not
+ * deal in secondary actions so those you may add separately.
+ * </p>
+ *
+ * <p>Provide a click listener on your fragment and if an action is clicked, call
+ * {@link #onActionClicked}. There is no need to call {@link #setOnItemViewClickedListener}
+ * but if you do a click listener will be installed on the fragment and recognized action clicks
+ * will be handled. Your listener will be called only for unhandled actions.
+ * </p>
+ *
+ * <p>The helper implements a key event handler. If you pass a
+ * {@link android.support.v17.leanback.app.PlaybackOverlaySupportFragment} the fragment's input event
+ * handler will be set. Otherwise, you should set the glue object as key event handler to the
+ * ViewHolder when bound by your row presenter; see
+ * {@link RowPresenter.ViewHolder#setOnKeyListener(android.view.View.OnKeyListener)}.
+ * </p>
+ *
+ * <p>To update the controls row progress during playback, override {@link #enableProgressUpdating}
+ * to manage the lifecycle of a periodic callback to {@link #updateProgress()}.
+ * {@link #getUpdatePeriod()} provides a recommended update period.
+ * </p>
+ *
+ */
+public abstract class PlaybackControlSupportGlue implements OnActionClickedListener, View.OnKeyListener {
+ /**
+ * The adapter key for the first custom control on the left side
+ * of the predefined primary controls.
+ */
+ public static final int ACTION_CUSTOM_LEFT_FIRST = 0x1;
+
+ /**
+ * The adapter key for the skip to previous control.
+ */
+ public static final int ACTION_SKIP_TO_PREVIOUS = 0x10;
+
+ /**
+ * The adapter key for the rewind control.
+ */
+ public static final int ACTION_REWIND = 0x20;
+
+ /**
+ * The adapter key for the play/pause control.
+ */
+ public static final int ACTION_PLAY_PAUSE = 0x40;
+
+ /**
+ * The adapter key for the fast forward control.
+ */
+ public static final int ACTION_FAST_FORWARD = 0x80;
+
+ /**
+ * The adapter key for the skip to next control.
+ */
+ public static final int ACTION_SKIP_TO_NEXT = 0x100;
+
+ /**
+ * The adapter key for the first custom control on the right side
+ * of the predefined primary controls.
+ */
+ public static final int ACTION_CUSTOM_RIGHT_FIRST = 0x1000;
+
+ /**
+ * Invalid playback speed.
+ */
+ public static final int PLAYBACK_SPEED_INVALID = -1;
+
+ /**
+ * Speed representing playback state that is paused.
+ */
+ public static final int PLAYBACK_SPEED_PAUSED = 0;
+
+ /**
+ * Speed representing playback state that is playing normally.
+ */
+ public static final int PLAYBACK_SPEED_NORMAL = 1;
+
+ /**
+ * The initial (level 0) fast forward playback speed.
+ * The negative of this value is for rewind at the same speed.
+ */
+ public static final int PLAYBACK_SPEED_FAST_L0 = 10;
+
+ /**
+ * The level 1 fast forward playback speed.
+ * The negative of this value is for rewind at the same speed.
+ */
+ public static final int PLAYBACK_SPEED_FAST_L1 = 11;
+
+ /**
+ * The level 2 fast forward playback speed.
+ * The negative of this value is for rewind at the same speed.
+ */
+ public static final int PLAYBACK_SPEED_FAST_L2 = 12;
+
+ /**
+ * The level 3 fast forward playback speed.
+ * The negative of this value is for rewind at the same speed.
+ */
+ public static final int PLAYBACK_SPEED_FAST_L3 = 13;
+
+ /**
+ * The level 4 fast forward playback speed.
+ * The negative of this value is for rewind at the same speed.
+ */
+ public static final int PLAYBACK_SPEED_FAST_L4 = 14;
+
+ private static final String TAG = "PlaybackControlSupportGlue";
+ private static final boolean DEBUG = false;
+
+ private static final int MSG_UPDATE_PLAYBACK_STATE = 100;
+ private static final int UPDATE_PLAYBACK_STATE_DELAY_MS = 2000;
+ private static final int NUMBER_OF_SEEK_SPEEDS = PLAYBACK_SPEED_FAST_L4 -
+ PLAYBACK_SPEED_FAST_L0 + 1;
+
+ private final PlaybackOverlaySupportFragment mFragment;
+ private final Context mContext;
+ private final int[] mFastForwardSpeeds;
+ private final int[] mRewindSpeeds;
+ private PlaybackControlsRow mControlsRow;
+ private SparseArrayObjectAdapter mPrimaryActionsAdapter;
+ private PlaybackControlsRow.PlayPauseAction mPlayPauseAction;
+ private PlaybackControlsRow.SkipNextAction mSkipNextAction;
+ private PlaybackControlsRow.SkipPreviousAction mSkipPreviousAction;
+ private PlaybackControlsRow.FastForwardAction mFastForwardAction;
+ private PlaybackControlsRow.RewindAction mRewindAction;
+ private OnItemViewClickedListener mExternalOnItemViewClickedListener;
+ private int mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
+ private boolean mFadeWhenPlaying = true;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_UPDATE_PLAYBACK_STATE) {
+ updatePlaybackState();
+ }
+ }
+ };
+
+ private final OnItemViewClickedListener mOnItemViewClickedListener =
+ new OnItemViewClickedListener() {
+ @Override
+ public void onItemClicked(Presenter.ViewHolder viewHolder, Object object,
+ RowPresenter.ViewHolder viewHolder2, Row row) {
+ if (DEBUG) Log.v(TAG, "onItemClicked " + object);
+ boolean handled = false;
+ if (object instanceof Action) {
+ handled = dispatchAction((Action) object, null);
+ }
+ if (!handled && mExternalOnItemViewClickedListener != null) {
+ mExternalOnItemViewClickedListener.onItemClicked(viewHolder, object,
+ viewHolder2, row);
+ }
+ }
+ };
+
+ /**
+ * Constructor for the glue.
+ *
+ * @param context
+ * @param seekSpeeds Array of seek speeds for fast forward and rewind.
+ */
+ public PlaybackControlSupportGlue(Context context, int[] seekSpeeds) {
+ this(context, null, seekSpeeds, seekSpeeds);
+ }
+
+ /**
+ * Constructor for the glue.
+ *
+ * @param context
+ * @param fastForwardSpeeds Array of seek speeds for fast forward.
+ * @param rewindSpeeds Array of seek speeds for rewind.
+ */
+ public PlaybackControlSupportGlue(Context context,
+ int[] fastForwardSpeeds,
+ int[] rewindSpeeds) {
+ this(context, null, fastForwardSpeeds, rewindSpeeds);
+ }
+
+ /**
+ * Constructor for the glue.
+ *
+ * @param context
+ * @param fragment Optional; if using a {@link PlaybackOverlaySupportFragment}, pass it in.
+ * @param seekSpeeds Array of seek speeds for fast forward and rewind.
+ */
+ public PlaybackControlSupportGlue(Context context,
+ PlaybackOverlaySupportFragment fragment,
+ int[] seekSpeeds) {
+ this(context, fragment, seekSpeeds, seekSpeeds);
+ }
+
+ /**
+ * Constructor for the glue.
+ *
+ * @param context
+ * @param fragment Optional; if using a {@link PlaybackOverlaySupportFragment}, pass it in.
+ * @param fastForwardSpeeds Array of seek speeds for fast forward.
+ * @param rewindSpeeds Array of seek speeds for rewind.
+ */
+ public PlaybackControlSupportGlue(Context context,
+ PlaybackOverlaySupportFragment fragment,
+ int[] fastForwardSpeeds,
+ int[] rewindSpeeds) {
+ mContext = context;
+ mFragment = fragment;
+ if (fragment != null) {
+ attachToFragment();
+ }
+ if (fastForwardSpeeds.length == 0 || fastForwardSpeeds.length > NUMBER_OF_SEEK_SPEEDS) {
+ throw new IllegalStateException("invalid fastForwardSpeeds array size");
+ }
+ mFastForwardSpeeds = fastForwardSpeeds;
+ if (rewindSpeeds.length == 0 || rewindSpeeds.length > NUMBER_OF_SEEK_SPEEDS) {
+ throw new IllegalStateException("invalid rewindSpeeds array size");
+ }
+ mRewindSpeeds = rewindSpeeds;
+ }
+
+ private final PlaybackOverlaySupportFragment.InputEventHandler mOnInputEventHandler =
+ new PlaybackOverlaySupportFragment.InputEventHandler() {
+ @Override
+ public boolean handleInputEvent(InputEvent event) {
+ if (event instanceof KeyEvent) {
+ KeyEvent keyEvent = (KeyEvent) event;
+ return onKey(null, keyEvent.getKeyCode(), keyEvent);
+ }
+ return false;
+ }
+ };
+
+ private void attachToFragment() {
+ mFragment.setInputEventHandler(mOnInputEventHandler);
+ }
+
+ /**
+ * Helper method for instantiating a
+ * {@link android.support.v17.leanback.widget.PlaybackControlsRow} and corresponding
+ * {@link android.support.v17.leanback.widget.PlaybackControlsRowPresenter}.
+ */
+ public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
+ PlaybackControlsRow controlsRow = new PlaybackControlsRow(this);
+ setControlsRow(controlsRow);
+
+ AbstractDetailsDescriptionPresenter detailsPresenter =
+ new AbstractDetailsDescriptionPresenter() {
+ @Override
+ protected void onBindDescription(AbstractDetailsDescriptionPresenter.ViewHolder
+ viewHolder, Object object) {
+ PlaybackControlSupportGlue glue = (PlaybackControlSupportGlue) object;
+ if (glue.hasValidMedia()) {
+ viewHolder.getTitle().setText(glue.getMediaTitle());
+ viewHolder.getSubtitle().setText(glue.getMediaSubtitle());
+ } else {
+ viewHolder.getTitle().setText("");
+ viewHolder.getSubtitle().setText("");
+ }
+ }
+ };
+ return new PlaybackControlsRowPresenter(detailsPresenter) {
+ @Override
+ protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
+ super.onBindRowViewHolder(vh, item);
+ vh.setOnKeyListener(PlaybackControlSupportGlue.this);
+ }
+ @Override
+ protected void onUnbindRowViewHolder(RowPresenter.ViewHolder vh) {
+ super.onUnbindRowViewHolder(vh);
+ vh.setOnKeyListener(null);
+ }
+ };
+ }
+
+ /**
+ * Returns the fragment.
+ */
+ public PlaybackOverlaySupportFragment getFragment() {
+ return mFragment;
+ }
+
+ /**
+ * Returns the context.
+ */
+ public Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Returns the fast forward speeds.
+ */
+ public int[] getFastForwardSpeeds() {
+ return mFastForwardSpeeds;
+ }
+
+ /**
+ * Returns the rewind speeds.
+ */
+ public int[] getRewindSpeeds() {
+ return mRewindSpeeds;
+ }
+
+ /**
+ * Sets the controls to fade after a timeout when media is playing.
+ */
+ public void setFadingEnabled(boolean enable) {
+ mFadeWhenPlaying = enable;
+ if (!mFadeWhenPlaying && mFragment != null) {
+ mFragment.setFadingEnabled(false);
+ }
+ }
+
+ /**
+ * Returns true if controls are set to fade when media is playing.
+ */
+ public boolean isFadingEnabled() {
+ return mFadeWhenPlaying;
+ }
+
+ /**
+ * Set the {@link OnItemViewClickedListener} to be called if the click event
+ * is not handled internally.
+ * @param listener
+ * @deprecated Don't call this. Instead set the listener on the fragment yourself,
+ * and call {@link #onActionClicked} to handle clicks.
+ */
+ public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+ mExternalOnItemViewClickedListener = listener;
+ if (mFragment != null) {
+ mFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
+ }
+ }
+
+ /**
+ * Returns the {@link OnItemViewClickedListener}.
+ */
+ public OnItemViewClickedListener getOnItemViewClickedListener() {
+ return mExternalOnItemViewClickedListener;
+ }
+
+ /**
+ * Sets the controls row to be managed by the glue layer.
+ * The primary actions and playback state related aspects of the row
+ * are updated by the glue.
+ */
+ public void setControlsRow(PlaybackControlsRow controlsRow) {
+ mControlsRow = controlsRow;
+ mPrimaryActionsAdapter = createPrimaryActionsAdapter(
+ new ControlButtonPresenterSelector());
+ mControlsRow.setPrimaryActionsAdapter(mPrimaryActionsAdapter);
+ updateControlsRow();
+ }
+
+ /**
+ * Returns the playback controls row managed by the glue layer.
+ */
+ public PlaybackControlsRow getControlsRow() {
+ return mControlsRow;
+ }
+
+ /**
+ * Override this to start/stop a runnable to call {@link #updateProgress} at
+ * an interval such as {@link #getUpdatePeriod}.
+ */
+ public void enableProgressUpdating(boolean enable) {
+ }
+
+ /**
+ * Returns the time period in milliseconds that should be used
+ * to update the progress. See {@link #updateProgress()}.
+ */
+ public int getUpdatePeriod() {
+ // TODO: calculate a better update period based on total duration and screen size
+ return 500;
+ }
+
+ /**
+ * Updates the progress bar based on the current media playback position.
+ */
+ public void updateProgress() {
+ int position = getCurrentPosition();
+ if (DEBUG) Log.v(TAG, "updateProgress " + position);
+ mControlsRow.setCurrentTime(position);
+ }
+
+ /**
+ * Handles action clicks. A subclass may override this add support for additional actions.
+ */
+ @Override
+ public void onActionClicked(Action action) {
+ dispatchAction(action, null);
+ }
+
+ /**
+ * Handles key events and returns true if handled. A subclass may override this to provide
+ * additional support.
+ */
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_BACK:
+ case KeyEvent.KEYCODE_ESCAPE:
+ boolean abortSeek = mPlaybackSpeed >= PLAYBACK_SPEED_FAST_L0 ||
+ mPlaybackSpeed <= -PLAYBACK_SPEED_FAST_L0;
+ if (abortSeek) {
+ mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
+ startPlayback(mPlaybackSpeed);
+ updatePlaybackStatusAfterUserAction();
+ return keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE;
+ }
+ return false;
+ }
+ Action action = mControlsRow.getActionForKeyCode(mPrimaryActionsAdapter, keyCode);
+ if (action != null) {
+ if (action == mPrimaryActionsAdapter.lookup(ACTION_PLAY_PAUSE) ||
+ action == mPrimaryActionsAdapter.lookup(ACTION_REWIND) ||
+ action == mPrimaryActionsAdapter.lookup(ACTION_FAST_FORWARD) ||
+ action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_PREVIOUS) ||
+ action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_NEXT)) {
+ if (((KeyEvent) event).getAction() == KeyEvent.ACTION_DOWN) {
+ dispatchAction(action, (KeyEvent) event);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Called when the given action is invoked, either by click or keyevent.
+ */
+ private boolean dispatchAction(Action action, KeyEvent keyEvent) {
+ boolean handled = false;
+ if (action == mPlayPauseAction) {
+ boolean canPlay = keyEvent == null ||
+ keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
+ keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY;
+ boolean canPause = keyEvent == null ||
+ keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
+ keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE;
+ if (mPlaybackSpeed != PLAYBACK_SPEED_NORMAL) {
+ if (canPlay) {
+ mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
+ startPlayback(mPlaybackSpeed);
+ }
+ } else if (canPause) {
+ mPlaybackSpeed = PLAYBACK_SPEED_PAUSED;
+ pausePlayback();
+ }
+ updatePlaybackStatusAfterUserAction();
+ handled = true;
+ } else if (action == mSkipNextAction) {
+ skipToNext();
+ handled = true;
+ } else if (action == mSkipPreviousAction) {
+ skipToPrevious();
+ handled = true;
+ } else if (action == mFastForwardAction) {
+ if (mPlaybackSpeed < getMaxForwardSpeedId()) {
+ switch (mPlaybackSpeed) {
+ case PLAYBACK_SPEED_FAST_L0:
+ case PLAYBACK_SPEED_FAST_L1:
+ case PLAYBACK_SPEED_FAST_L2:
+ case PLAYBACK_SPEED_FAST_L3:
+ mPlaybackSpeed++;
+ break;
+ default:
+ mPlaybackSpeed = PLAYBACK_SPEED_FAST_L0;
+ break;
+ }
+ startPlayback(mPlaybackSpeed);
+ updatePlaybackStatusAfterUserAction();
+ }
+ handled = true;
+ } else if (action == mRewindAction) {
+ if (mPlaybackSpeed > -getMaxRewindSpeedId()) {
+ switch (mPlaybackSpeed) {
+ case -PLAYBACK_SPEED_FAST_L0:
+ case -PLAYBACK_SPEED_FAST_L1:
+ case -PLAYBACK_SPEED_FAST_L2:
+ case -PLAYBACK_SPEED_FAST_L3:
+ mPlaybackSpeed--;
+ break;
+ default:
+ mPlaybackSpeed = -PLAYBACK_SPEED_FAST_L0;
+ break;
+ }
+ startPlayback(mPlaybackSpeed);
+ updatePlaybackStatusAfterUserAction();
+ }
+ handled = true;
+ }
+ return handled;
+ }
+
+ private int getMaxForwardSpeedId() {
+ return PLAYBACK_SPEED_FAST_L0 + (mFastForwardSpeeds.length - 1);
+ }
+
+ private int getMaxRewindSpeedId() {
+ return PLAYBACK_SPEED_FAST_L0 + (mRewindSpeeds.length - 1);
+ }
+
+ private void updateControlsRow() {
+ updateRowMetadata();
+ mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+ updatePlaybackState();
+ }
+
+ private void updatePlaybackStatusAfterUserAction() {
+ updatePlaybackState(mPlaybackSpeed);
+ // Sync playback state after a delay
+ mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
+ UPDATE_PLAYBACK_STATE_DELAY_MS);
+ }
+
+ private void updateRowMetadata() {
+ if (mControlsRow == null) {
+ return;
+ }
+
+ if (DEBUG) Log.v(TAG, "updateRowMetadata hasValidMedia " + hasValidMedia());
+
+ if (!hasValidMedia()) {
+ mControlsRow.setImageDrawable(null);
+ mControlsRow.setTotalTime(0);
+ mControlsRow.setCurrentTime(0);
+ } else {
+ mControlsRow.setImageDrawable(getMediaArt());
+ mControlsRow.setTotalTime(getMediaDuration());
+ mControlsRow.setCurrentTime(getCurrentPosition());
+ }
+
+ onRowChanged(mControlsRow);
+ }
+
+ private void updatePlaybackState() {
+ if (hasValidMedia()) {
+ mPlaybackSpeed = getCurrentSpeedId();
+ updatePlaybackState(mPlaybackSpeed);
+ }
+ }
+
+ private void updatePlaybackState(int playbackSpeed) {
+ if (mControlsRow == null) {
+ return;
+ }
+
+ final long actions = getSupportedActions();
+ if ((actions & ACTION_SKIP_TO_PREVIOUS) != 0) {
+ if (mSkipPreviousAction == null) {
+ mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(mContext);
+ }
+ mPrimaryActionsAdapter.set(ACTION_SKIP_TO_PREVIOUS, mSkipPreviousAction);
+ } else {
+ mPrimaryActionsAdapter.clear(ACTION_SKIP_TO_PREVIOUS);
+ mSkipPreviousAction = null;
+ }
+ if ((actions & ACTION_REWIND) != 0) {
+ if (mRewindAction == null) {
+ mRewindAction = new PlaybackControlsRow.RewindAction(mContext,
+ mRewindSpeeds.length);
+ }
+ mPrimaryActionsAdapter.set(ACTION_REWIND, mRewindAction);
+ } else {
+ mPrimaryActionsAdapter.clear(ACTION_REWIND);
+ mRewindAction = null;
+ }
+ if ((actions & ACTION_PLAY_PAUSE) != 0) {
+ if (mPlayPauseAction == null) {
+ mPlayPauseAction = new PlaybackControlsRow.PlayPauseAction(mContext);
+ }
+ mPrimaryActionsAdapter.set(ACTION_PLAY_PAUSE, mPlayPauseAction);
+ } else {
+ mPrimaryActionsAdapter.clear(ACTION_PLAY_PAUSE);
+ mPlayPauseAction = null;
+ }
+ if ((actions & ACTION_FAST_FORWARD) != 0) {
+ if (mFastForwardAction == null) {
+ mFastForwardAction = new PlaybackControlsRow.FastForwardAction(mContext,
+ mFastForwardSpeeds.length);
+ }
+ mPrimaryActionsAdapter.set(ACTION_FAST_FORWARD, mFastForwardAction);
+ } else {
+ mPrimaryActionsAdapter.clear(ACTION_FAST_FORWARD);
+ mFastForwardAction = null;
+ }
+ if ((actions & ACTION_SKIP_TO_NEXT) != 0) {
+ if (mSkipNextAction == null) {
+ mSkipNextAction = new PlaybackControlsRow.SkipNextAction(mContext);
+ }
+ mPrimaryActionsAdapter.set(ACTION_SKIP_TO_NEXT, mSkipNextAction);
+ } else {
+ mPrimaryActionsAdapter.clear(ACTION_SKIP_TO_NEXT);
+ mSkipNextAction = null;
+ }
+
+ if (mFastForwardAction != null) {
+ int index = 0;
+ if (playbackSpeed >= PLAYBACK_SPEED_FAST_L0) {
+ index = playbackSpeed - PLAYBACK_SPEED_FAST_L0;
+ if (playbackSpeed < getMaxForwardSpeedId()) {
+ index++;
+ }
+ }
+ if (mFastForwardAction.getIndex() != index) {
+ mFastForwardAction.setIndex(index);
+ notifyItemChanged(mPrimaryActionsAdapter, mFastForwardAction);
+ }
+ }
+ if (mRewindAction != null) {
+ int index = 0;
+ if (playbackSpeed <= -PLAYBACK_SPEED_FAST_L0) {
+ index = -playbackSpeed - PLAYBACK_SPEED_FAST_L0;
+ if (-playbackSpeed < getMaxRewindSpeedId()) {
+ index++;
+ }
+ }
+ if (mRewindAction.getIndex() != index) {
+ mRewindAction.setIndex(index);
+ notifyItemChanged(mPrimaryActionsAdapter, mRewindAction);
+ }
+ }
+
+ if (playbackSpeed == PLAYBACK_SPEED_PAUSED) {
+ updateProgress();
+ enableProgressUpdating(false);
+ } else {
+ enableProgressUpdating(true);
+ }
+
+ if (mFadeWhenPlaying && mFragment != null) {
+ mFragment.setFadingEnabled(playbackSpeed == PLAYBACK_SPEED_NORMAL);
+ }
+
+ if (mPlayPauseAction != null) {
+ int index = playbackSpeed == PLAYBACK_SPEED_PAUSED ?
+ PlaybackControlsRow.PlayPauseAction.PLAY :
+ PlaybackControlsRow.PlayPauseAction.PAUSE;
+ if (mPlayPauseAction.getIndex() != index) {
+ mPlayPauseAction.setIndex(index);
+ notifyItemChanged(mPrimaryActionsAdapter, mPlayPauseAction);
+ }
+ }
+ }
+
+ private static void notifyItemChanged(SparseArrayObjectAdapter adapter, Object object) {
+ int index = adapter.indexOf(object);
+ if (index >= 0) {
+ adapter.notifyArrayItemRangeChanged(index, 1);
+ }
+ }
+
+ private static String getSpeedString(int speed) {
+ switch (speed) {
+ case PLAYBACK_SPEED_INVALID:
+ return "PLAYBACK_SPEED_INVALID";
+ case PLAYBACK_SPEED_PAUSED:
+ return "PLAYBACK_SPEED_PAUSED";
+ case PLAYBACK_SPEED_NORMAL:
+ return "PLAYBACK_SPEED_NORMAL";
+ case PLAYBACK_SPEED_FAST_L0:
+ return "PLAYBACK_SPEED_FAST_L0";
+ case PLAYBACK_SPEED_FAST_L1:
+ return "PLAYBACK_SPEED_FAST_L1";
+ case PLAYBACK_SPEED_FAST_L2:
+ return "PLAYBACK_SPEED_FAST_L2";
+ case PLAYBACK_SPEED_FAST_L3:
+ return "PLAYBACK_SPEED_FAST_L3";
+ case PLAYBACK_SPEED_FAST_L4:
+ return "PLAYBACK_SPEED_FAST_L4";
+ case -PLAYBACK_SPEED_FAST_L0:
+ return "-PLAYBACK_SPEED_FAST_L0";
+ case -PLAYBACK_SPEED_FAST_L1:
+ return "-PLAYBACK_SPEED_FAST_L1";
+ case -PLAYBACK_SPEED_FAST_L2:
+ return "-PLAYBACK_SPEED_FAST_L2";
+ case -PLAYBACK_SPEED_FAST_L3:
+ return "-PLAYBACK_SPEED_FAST_L3";
+ case -PLAYBACK_SPEED_FAST_L4:
+ return "-PLAYBACK_SPEED_FAST_L4";
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if there is a valid media item.
+ */
+ public abstract boolean hasValidMedia();
+
+ /**
+ * Returns true if media is currently playing.
+ */
+ public abstract boolean isMediaPlaying();
+
+ /**
+ * Returns the title of the media item.
+ */
+ public abstract CharSequence getMediaTitle();
+
+ /**
+ * Returns the subtitle of the media item.
+ */
+ public abstract CharSequence getMediaSubtitle();
+
+ /**
+ * Returns the duration of the media item in milliseconds.
+ */
+ public abstract int getMediaDuration();
+
+ /**
+ * Returns a bitmap of the art for the media item.
+ */
+ public abstract Drawable getMediaArt();
+
+ /**
+ * Returns a bitmask of actions supported by the media player.
+ */
+ public abstract long getSupportedActions();
+
+ /**
+ * Returns the current playback speed. When playing normally,
+ * {@link #PLAYBACK_SPEED_NORMAL} should be returned.
+ */
+ public abstract int getCurrentSpeedId();
+
+ /**
+ * Returns the current position of the media item in milliseconds.
+ */
+ public abstract int getCurrentPosition();
+
+ /**
+ * Start playback at the given speed.
+ * @param speed The desired playback speed. For normal playback this will be
+ * {@link #PLAYBACK_SPEED_NORMAL}; higher positive values for fast forward,
+ * and negative values for rewind.
+ */
+ protected abstract void startPlayback(int speed);
+
+ /**
+ * Pause playback.
+ */
+ protected abstract void pausePlayback();
+
+ /**
+ * Skip to the next track.
+ */
+ protected abstract void skipToNext();
+
+ /**
+ * Skip to the previous track.
+ */
+ protected abstract void skipToPrevious();
+
+ /**
+ * Invoked when the playback controls row has changed. The adapter containing this row
+ * should be notified.
+ */
+ protected abstract void onRowChanged(PlaybackControlsRow row);
+
+ /**
+ * Creates the primary action adapter. May be overridden to add additional primary
+ * actions to the adapter.
+ */
+ protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
+ PresenterSelector presenterSelector) {
+ return new SparseArrayObjectAdapter(presenterSelector);
+ }
+
+ /**
+ * Must be called appropriately by a subclass when the playback state has changed.
+ */
+ protected void onStateChanged() {
+ if (DEBUG) Log.v(TAG, "onStateChanged");
+ // If a pending control button update is present, delay
+ // the update until the state settles.
+ if (!hasValidMedia()) {
+ return;
+ }
+ if (mHandler.hasMessages(MSG_UPDATE_PLAYBACK_STATE)) {
+ mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+ if (getCurrentSpeedId() != mPlaybackSpeed) {
+ if (DEBUG) Log.v(TAG, "Status expectation mismatch, delaying update");
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
+ UPDATE_PLAYBACK_STATE_DELAY_MS);
+ } else {
+ if (DEBUG) Log.v(TAG, "Update state matches expectation");
+ updatePlaybackState();
+ }
+ } else {
+ updatePlaybackState();
+ }
+ }
+
+ /**
+ * Must be called appropriately by a subclass when the metadata state has changed.
+ */
+ protected void onMetadataChanged() {
+ if (DEBUG) Log.v(TAG, "onMetadataChanged");
+ updateRowMetadata();
+ }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
index 71a95e8..a5a7ccd 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
@@ -448,6 +448,10 @@
@Override
public boolean onPreDraw() {
+ if (getView() == null || getActivity() == null) {
+ mVerticalView.getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
if (mState == STATE_INIT) {
setExpand(true);
mState = STATE_FIRST_DRAW;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
index 7f12aac..7390acf 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
@@ -450,6 +450,10 @@
@Override
public boolean onPreDraw() {
+ if (getView() == null || getActivity() == null) {
+ mVerticalView.getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
if (mState == STATE_INIT) {
setExpand(true);
mState = STATE_FIRST_DRAW;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
index fc93625..d828963 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
@@ -34,6 +34,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.CompletionInfo;
import android.widget.FrameLayout;
import android.support.v17.leanback.R;
@@ -478,6 +479,17 @@
}
/**
+ * Displays the completions shown by the IME. An application may provide
+ * a list of query completions that the system will show in the IME.
+ *
+ * @param completions A list of completions to show in the IME. Setting to
+ * null or empty will clear the list.
+ */
+ public void displayCompletions(CompletionInfo[] completions) {
+ mSearchBar.displayCompletions(completions);
+ }
+
+ /**
* Sets this callback to have the fragment pass speech recognition requests
* to the activity rather than using an internal recognizer.
*/
diff --git a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
index e06f7e8..7ff364e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
@@ -36,6 +36,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.CompletionInfo;
import android.widget.FrameLayout;
import android.support.v17.leanback.R;
@@ -480,6 +481,17 @@
}
/**
+ * Displays the completions shown by the IME. An application may provide
+ * a list of query completions that the system will show in the IME.
+ *
+ * @param completions A list of completions to show in the IME. Setting to
+ * null or empty will clear the list.
+ */
+ public void displayCompletions(CompletionInfo[] completions) {
+ mSearchBar.displayCompletions(completions);
+ }
+
+ /**
* Sets this callback to have the fragment pass speech recognition requests
* to the activity rather than using an internal recognizer.
*/
diff --git a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
index 6b6cc2e..3e51989 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
@@ -15,6 +15,7 @@
import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.widget.BrowseFrameLayout;
import android.support.v17.leanback.widget.OnChildLaidOutListener;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
@@ -38,7 +39,7 @@
* <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
* an {@link ObjectAdapter}.
*/
-public class VerticalGridFragment extends BrandedFragment {
+public class VerticalGridFragment extends BaseFragment {
private static final String TAG = "VerticalGridFragment";
private static boolean DEBUG = false;
@@ -47,6 +48,7 @@
private VerticalGridPresenter.ViewHolder mGridViewHolder;
private OnItemViewSelectedListener mOnItemViewSelectedListener;
private OnItemViewClickedListener mOnItemViewClickedListener;
+ private Object mSceneAfterEntranceTransition;
private int mSelectedPosition = -1;
/**
@@ -170,6 +172,13 @@
gridDock.addView(mGridViewHolder.view);
mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
+ mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() {
+ @Override
+ public void run() {
+ setEntranceTransitionState(true);
+ }
+ });
+
updateAdapter();
}
@@ -183,7 +192,9 @@
public void onStart() {
super.onStart();
setupFocusSearchListener();
- mGridViewHolder.getGridView().requestFocus();
+ if (isEntranceTransitionEnabled()) {
+ setEntranceTransitionState(false);
+ }
}
@Override
@@ -210,4 +221,19 @@
}
}
}
+
+ @Override
+ protected Object createEntranceTransition() {
+ return TransitionHelper.loadTransition(getActivity(),
+ R.transition.lb_vertical_grid_entrance_transition);
+ }
+
+ @Override
+ protected void runEntranceTransition(Object entranceTransition) {
+ TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+ }
+
+ void setEntranceTransitionState(boolean afterTransition) {
+ mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition);
+ }
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
index 0770761..eb0b337 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
@@ -17,6 +17,7 @@
import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.widget.BrowseFrameLayout;
import android.support.v17.leanback.widget.OnChildLaidOutListener;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
@@ -40,7 +41,7 @@
* <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
* an {@link ObjectAdapter}.
*/
-public class VerticalGridSupportFragment extends BrandedSupportFragment {
+public class VerticalGridSupportFragment extends BaseSupportFragment {
private static final String TAG = "VerticalGridSupportFragment";
private static boolean DEBUG = false;
@@ -49,6 +50,7 @@
private VerticalGridPresenter.ViewHolder mGridViewHolder;
private OnItemViewSelectedListener mOnItemViewSelectedListener;
private OnItemViewClickedListener mOnItemViewClickedListener;
+ private Object mSceneAfterEntranceTransition;
private int mSelectedPosition = -1;
/**
@@ -172,6 +174,13 @@
gridDock.addView(mGridViewHolder.view);
mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
+ mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() {
+ @Override
+ public void run() {
+ setEntranceTransitionState(true);
+ }
+ });
+
updateAdapter();
}
@@ -185,7 +194,9 @@
public void onStart() {
super.onStart();
setupFocusSearchListener();
- mGridViewHolder.getGridView().requestFocus();
+ if (isEntranceTransitionEnabled()) {
+ setEntranceTransitionState(false);
+ }
}
@Override
@@ -212,4 +223,19 @@
}
}
}
+
+ @Override
+ protected Object createEntranceTransition() {
+ return TransitionHelper.loadTransition(getActivity(),
+ R.transition.lb_vertical_grid_entrance_transition);
+ }
+
+ @Override
+ protected void runEntranceTransition(Object entranceTransition) {
+ TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+ }
+
+ void setEntranceTransitionState(boolean afterTransition) {
+ mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition);
+ }
}
diff --git a/v17/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java b/v17/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
index f7451d4..47495cb 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
@@ -30,9 +30,9 @@
static interface LeanbackTransitionHelperVersion {
- public Object loadTitleInTransition(Context context, TransitionHelper helper);
+ public Object loadTitleInTransition(Context context);
- public Object loadTitleOutTransition(Context context, TransitionHelper helper);
+ public Object loadTitleOutTransition(Context context);
}
/*
@@ -42,12 +42,12 @@
static class LeanbackTransitionHelperKitKatImpl implements LeanbackTransitionHelperVersion {
@Override
- public Object loadTitleInTransition(Context context, TransitionHelper helper) {
+ public Object loadTitleInTransition(Context context) {
return LeanbackTransitionHelperKitKat.loadTitleInTransition(context);
}
@Override
- public Object loadTitleOutTransition(Context context, TransitionHelper helper) {
+ public Object loadTitleOutTransition(Context context) {
return LeanbackTransitionHelperKitKat.loadTitleOutTransition(context);
}
}
@@ -58,13 +58,13 @@
static class LeanbackTransitionHelperDefault implements LeanbackTransitionHelperVersion {
@Override
- public Object loadTitleInTransition(Context context, TransitionHelper helper) {
- return helper.loadTransition(context, R.transition.lb_title_in);
+ public Object loadTitleInTransition(Context context) {
+ return TransitionHelper.loadTransition(context, R.transition.lb_title_in);
}
@Override
- public Object loadTitleOutTransition(Context context, TransitionHelper helper) {
- return helper.loadTransition(context, R.transition.lb_title_out);
+ public Object loadTitleOutTransition(Context context) {
+ return TransitionHelper.loadTransition(context, R.transition.lb_title_out);
}
}
@@ -81,11 +81,11 @@
}
}
- static public Object loadTitleInTransition(Context context, TransitionHelper helper) {
- return sImpl.loadTitleInTransition(context, helper);
+ static public Object loadTitleInTransition(Context context) {
+ return sImpl.loadTitleInTransition(context);
}
- static public Object loadTitleOutTransition(Context context, TransitionHelper helper) {
- return sImpl.loadTitleOutTransition(context, helper);
+ static public Object loadTitleOutTransition(Context context) {
+ return sImpl.loadTitleOutTransition(context);
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
index 1c66d03..9420154 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
@@ -20,6 +20,8 @@
import android.view.ViewGroup;
import android.view.Window;
+import java.util.ArrayList;
+
/**
* Helper for view transitions.
* @hide
@@ -34,8 +36,7 @@
public static final int SLIDE_RIGHT = Gravity.RIGHT;
public static final int SLIDE_BOTTOM = Gravity.BOTTOM;
- private final static TransitionHelper sHelper = new TransitionHelper();
- TransitionHelperVersionImpl mImpl;
+ private static TransitionHelperVersionImpl sImpl;
/**
* Gets whether the system supports Transition animations.
@@ -62,6 +63,16 @@
*/
static interface TransitionHelperVersionImpl {
+ public void setEnterTransition(android.app.Fragment fragment, Object transition);
+
+ public void setExitTransition(android.app.Fragment fragment, Object transition);
+
+ public void setSharedElementEnterTransition(android.app.Fragment fragment,
+ Object transition);
+
+ public void addSharedElement(android.app.FragmentTransaction ft,
+ View view, String transitionName);
+
public Object getSharedElementEnterTransition(Window window);
public Object getSharedElementReturnTransition(Window window);
@@ -90,6 +101,8 @@
public Object createChangeBounds(boolean reparent);
+ public Object createFadeAndShortSlide(int edge);
+
public void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay);
public void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay);
@@ -103,7 +116,9 @@
public void addTransition(Object transitionSet, Object transition);
- public void setTransitionListener(Object transition, TransitionListener listener);
+ public void addTransitionListener(Object transition, TransitionListener listener);
+
+ public void removeTransitionListener(Object transition, TransitionListener listener);
public void runTransition(Object scene, Object transition);
@@ -130,15 +145,31 @@
public Object createDefaultInterpolator(Context context);
public Object loadTransition(Context context, int resId);
+
+ public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup);
}
/**
* Interface used when we do not support Transition animations.
*/
- private static final class TransitionHelperStubImpl implements TransitionHelperVersionImpl {
+ static class TransitionHelperStubImpl implements TransitionHelperVersionImpl {
private static class TransitionStub {
- TransitionListener mTransitionListener;
+ ArrayList<TransitionListener> mTransitionListeners;
+ }
+
+ public void setEnterTransition(android.app.Fragment fragment, Object transition) {
+ }
+
+ public void setExitTransition(android.app.Fragment fragment, Object transition) {
+ }
+
+ public void setSharedElementEnterTransition(android.app.Fragment fragment,
+ Object transition) {
+ }
+
+ public void addSharedElement(android.app.FragmentTransaction ft,
+ View view, String transitionName) {
}
@Override
@@ -202,6 +233,11 @@
}
@Override
+ public Object createFadeAndShortSlide(int edge) {
+ return new TransitionStub();
+ }
+
+ @Override
public Object createSlide(int slideEdge) {
return new TransitionStub();
}
@@ -270,22 +306,38 @@
}
@Override
- public void setTransitionListener(Object transition, TransitionListener listener) {
- ((TransitionStub) transition).mTransitionListener = listener;
+ public void addTransitionListener(Object transition, TransitionListener listener) {
+ TransitionStub stub = (TransitionStub) transition;
+ if (stub.mTransitionListeners == null) {
+ stub.mTransitionListeners = new ArrayList<TransitionListener>();
+ }
+ stub.mTransitionListeners.add(listener);
+ }
+
+ @Override
+ public void removeTransitionListener(Object transition, TransitionListener listener) {
+ TransitionStub stub = (TransitionStub) transition;
+ if (stub.mTransitionListeners != null) {
+ stub.mTransitionListeners.remove(listener);
+ }
}
@Override
public void runTransition(Object scene, Object transition) {
TransitionStub transitionStub = (TransitionStub) transition;
- if (transitionStub != null && transitionStub.mTransitionListener != null) {
- transitionStub.mTransitionListener.onTransitionStart(transition);
+ if (transitionStub != null && transitionStub.mTransitionListeners != null) {
+ for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
+ transitionStub.mTransitionListeners.get(i).onTransitionStart(transition);
+ }
}
Runnable r = ((Runnable) scene);
if (r != null) {
r.run();
}
- if (transitionStub != null && transitionStub.mTransitionListener != null) {
- transitionStub.mTransitionListener.onTransitionEnd(transition);
+ if (transitionStub != null && transitionStub.mTransitionListeners != null) {
+ for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
+ transitionStub.mTransitionListeners.get(i).onTransitionEnd(transition);
+ }
}
}
@@ -306,52 +358,16 @@
public Object loadTransition(Context context, int resId) {
return new TransitionStub();
}
+
+ @Override
+ public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
+ }
}
/**
* Implementation used on KitKat (and above).
*/
- private static class TransitionHelperKitkatImpl implements TransitionHelperVersionImpl {
-
- @Override
- public Object getSharedElementEnterTransition(Window window) {
- return null;
- }
-
- @Override
- public Object getSharedElementReturnTransition(Window window) {
- return null;
- }
-
- @Override
- public Object getSharedElementExitTransition(Window window) {
- return null;
- }
-
- @Override
- public Object getSharedElementReenterTransition(Window window) {
- return null;
- }
-
- @Override
- public Object getEnterTransition(Window window) {
- return null;
- }
-
- @Override
- public Object getReturnTransition(Window window) {
- return null;
- }
-
- @Override
- public Object getExitTransition(Window window) {
- return null;
- }
-
- @Override
- public Object getReenterTransition(Window window) {
- return null;
- }
+ static class TransitionHelperKitkatImpl extends TransitionHelperStubImpl {
@Override
public Object createScene(ViewGroup sceneRoot, Runnable r) {
@@ -455,8 +471,13 @@
}
@Override
- public void setTransitionListener(Object transition, TransitionListener listener) {
- TransitionHelperKitkat.setTransitionListener(transition, listener);
+ public void addTransitionListener(Object transition, TransitionListener listener) {
+ TransitionHelperKitkat.addTransitionListener(transition, listener);
+ }
+
+ @Override
+ public void removeTransitionListener(Object transition, TransitionListener listener) {
+ TransitionHelperKitkat.removeTransitionListener(transition, listener);
}
@Override
@@ -485,7 +506,25 @@
}
}
- private static final class TransitionHelperApi21Impl extends TransitionHelperKitkatImpl {
+ static final class TransitionHelperApi21Impl extends TransitionHelperKitkatImpl {
+
+ public void setEnterTransition(android.app.Fragment fragment, Object transition) {
+ TransitionHelperApi21.setEnterTransition(fragment, transition);
+ }
+
+ public void setExitTransition(android.app.Fragment fragment, Object transition) {
+ TransitionHelperApi21.setExitTransition(fragment, transition);
+ }
+
+ public void setSharedElementEnterTransition(android.app.Fragment fragment,
+ Object transition) {
+ TransitionHelperApi21.setSharedElementEnterTransition(fragment, transition);
+ }
+
+ public void addSharedElement(android.app.FragmentTransaction ft,
+ View view, String transitionName) {
+ TransitionHelperApi21.addSharedElement(ft, view, transitionName);
+ }
@Override
public Object getSharedElementEnterTransition(Window window) {
@@ -508,6 +547,11 @@
}
@Override
+ public Object createFadeAndShortSlide(int edge) {
+ return TransitionHelperApi21.createFadeAndShortSlide(edge);
+ }
+
+ @Override
public Object getEnterTransition(Window window) {
return TransitionHelperApi21.getEnterTransition(window);
}
@@ -536,159 +580,207 @@
public Object createDefaultInterpolator(Context context) {
return TransitionHelperApi21.createDefaultInterpolator(context);
}
- }
- /**
- * Returns the TransitionHelper that can be used to perform Transition
- * animations.
- */
- public static TransitionHelper getInstance() {
- return sHelper;
- }
-
- private TransitionHelper() {
- if (Build.VERSION.SDK_INT >= 21) {
- mImpl = new TransitionHelperApi21Impl();
- } else if (systemSupportsTransitions()) {
- mImpl = new TransitionHelperKitkatImpl();
- } else {
- mImpl = new TransitionHelperStubImpl();
+ @Override
+ public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
+ TransitionHelperApi21.setTransitionGroup(viewGroup, transitionGroup);
}
}
- public Object getSharedElementEnterTransition(Window window) {
- return mImpl.getSharedElementEnterTransition(window);
+ static {
+ if (Build.VERSION.SDK_INT >= 21) {
+ sImpl = new TransitionHelperApi21Impl();
+ } else if (systemSupportsTransitions()) {
+ sImpl = new TransitionHelperKitkatImpl();
+ } else {
+ sImpl = new TransitionHelperStubImpl();
+ }
}
- public Object getSharedElementReturnTransition(Window window) {
- return mImpl.getSharedElementReturnTransition(window);
+ public static Object getSharedElementEnterTransition(Window window) {
+ return sImpl.getSharedElementEnterTransition(window);
}
- public Object getSharedElementExitTransition(Window window) {
- return mImpl.getSharedElementExitTransition(window);
+ public static Object getSharedElementReturnTransition(Window window) {
+ return sImpl.getSharedElementReturnTransition(window);
}
- public Object getSharedElementReenterTransition(Window window) {
- return mImpl.getSharedElementReenterTransition(window);
+ public static Object getSharedElementExitTransition(Window window) {
+ return sImpl.getSharedElementExitTransition(window);
}
- public Object getEnterTransition(Window window) {
- return mImpl.getEnterTransition(window);
+ public static Object getSharedElementReenterTransition(Window window) {
+ return sImpl.getSharedElementReenterTransition(window);
}
- public Object getReturnTransition(Window window) {
- return mImpl.getReturnTransition(window);
+ public static Object getEnterTransition(Window window) {
+ return sImpl.getEnterTransition(window);
}
- public Object getExitTransition(Window window) {
- return mImpl.getExitTransition(window);
+ public static Object getReturnTransition(Window window) {
+ return sImpl.getReturnTransition(window);
}
- public Object getReenterTransition(Window window) {
- return mImpl.getReenterTransition(window);
+ public static Object getExitTransition(Window window) {
+ return sImpl.getExitTransition(window);
}
- public Object createScene(ViewGroup sceneRoot, Runnable r) {
- return mImpl.createScene(sceneRoot, r);
+ public static Object getReenterTransition(Window window) {
+ return sImpl.getReenterTransition(window);
}
- public Object createChangeBounds(boolean reparent) {
- return mImpl.createChangeBounds(reparent);
+ public static Object createScene(ViewGroup sceneRoot, Runnable r) {
+ return sImpl.createScene(sceneRoot, r);
}
- public void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
- mImpl.setChangeBoundsStartDelay(changeBounds, view, startDelay);
+ public static Object createChangeBounds(boolean reparent) {
+ return sImpl.createChangeBounds(reparent);
}
- public void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
- mImpl.setChangeBoundsStartDelay(changeBounds, viewId, startDelay);
+ public static void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
+ sImpl.setChangeBoundsStartDelay(changeBounds, view, startDelay);
}
- public void setChangeBoundsStartDelay(Object changeBounds, String className, int startDelay) {
- mImpl.setChangeBoundsStartDelay(changeBounds, className, startDelay);
+ public static void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
+ sImpl.setChangeBoundsStartDelay(changeBounds, viewId, startDelay);
}
- public void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
- mImpl.setChangeBoundsDefaultStartDelay(changeBounds, startDelay);
+ public static void setChangeBoundsStartDelay(Object changeBounds, String className,
+ int startDelay) {
+ sImpl.setChangeBoundsStartDelay(changeBounds, className, startDelay);
}
- public Object createTransitionSet(boolean sequential) {
- return mImpl.createTransitionSet(sequential);
+ public static void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
+ sImpl.setChangeBoundsDefaultStartDelay(changeBounds, startDelay);
}
- public Object createSlide(int slideEdge) {
- return mImpl.createSlide(slideEdge);
+ public static Object createTransitionSet(boolean sequential) {
+ return sImpl.createTransitionSet(sequential);
}
- public Object createScale() {
- return mImpl.createScale();
+ public static Object createSlide(int slideEdge) {
+ return sImpl.createSlide(slideEdge);
}
- public void addTransition(Object transitionSet, Object transition) {
- mImpl.addTransition(transitionSet, transition);
+ public static Object createScale() {
+ return sImpl.createScale();
}
- public void exclude(Object transition, int targetId, boolean exclude) {
- mImpl.exclude(transition, targetId, exclude);
+ public static void addTransition(Object transitionSet, Object transition) {
+ sImpl.addTransition(transitionSet, transition);
}
- public void exclude(Object transition, View targetView, boolean exclude) {
- mImpl.exclude(transition, targetView, exclude);
+ public static void exclude(Object transition, int targetId, boolean exclude) {
+ sImpl.exclude(transition, targetId, exclude);
}
- public void excludeChildren(Object transition, int targetId, boolean exclude) {
- mImpl.excludeChildren(transition, targetId, exclude);
+ public static void exclude(Object transition, View targetView, boolean exclude) {
+ sImpl.exclude(transition, targetView, exclude);
}
- public void excludeChildren(Object transition, View targetView, boolean exclude) {
- mImpl.excludeChildren(transition, targetView, exclude);
+ public static void excludeChildren(Object transition, int targetId, boolean exclude) {
+ sImpl.excludeChildren(transition, targetId, exclude);
}
- public void include(Object transition, int targetId) {
- mImpl.include(transition, targetId);
+ public static void excludeChildren(Object transition, View targetView, boolean exclude) {
+ sImpl.excludeChildren(transition, targetView, exclude);
}
- public void include(Object transition, View targetView) {
- mImpl.include(transition, targetView);
+ public static void include(Object transition, int targetId) {
+ sImpl.include(transition, targetId);
}
- public void setStartDelay(Object transition, long startDelay) {
- mImpl.setStartDelay(transition, startDelay);
+ public static void include(Object transition, View targetView) {
+ sImpl.include(transition, targetView);
}
- public void setDuration(Object transition, long duration) {
- mImpl.setDuration(transition, duration);
+ public static void setStartDelay(Object transition, long startDelay) {
+ sImpl.setStartDelay(transition, startDelay);
}
- public Object createAutoTransition() {
- return mImpl.createAutoTransition();
+ public static void setDuration(Object transition, long duration) {
+ sImpl.setDuration(transition, duration);
}
- public Object createFadeTransition(int fadeMode) {
- return mImpl.createFadeTransition(fadeMode);
+ public static Object createAutoTransition() {
+ return sImpl.createAutoTransition();
}
- public void setTransitionListener(Object transition, TransitionListener listener) {
- mImpl.setTransitionListener(transition, listener);
+ public static Object createFadeTransition(int fadeMode) {
+ return sImpl.createFadeTransition(fadeMode);
}
- public void runTransition(Object scene, Object transition) {
- mImpl.runTransition(scene, transition);
+ public static void addTransitionListener(Object transition, TransitionListener listener) {
+ sImpl.addTransitionListener(transition, listener);
}
- public void setInterpolator(Object transition, Object timeInterpolator) {
- mImpl.setInterpolator(transition, timeInterpolator);
+ public static void removeTransitionListener(Object transition, TransitionListener listener) {
+ sImpl.removeTransitionListener(transition, listener);
}
- public void addTarget(Object transition, View view) {
- mImpl.addTarget(transition, view);
+ public static void runTransition(Object scene, Object transition) {
+ sImpl.runTransition(scene, transition);
}
- public Object createDefaultInterpolator(Context context) {
- return mImpl.createDefaultInterpolator(context);
+ public static void setInterpolator(Object transition, Object timeInterpolator) {
+ sImpl.setInterpolator(transition, timeInterpolator);
}
- public Object loadTransition(Context context, int resId) {
- return mImpl.loadTransition(context, resId);
+ public static void addTarget(Object transition, View view) {
+ sImpl.addTarget(transition, view);
+ }
+
+ public static Object createDefaultInterpolator(Context context) {
+ return sImpl.createDefaultInterpolator(context);
+ }
+
+ public static Object loadTransition(Context context, int resId) {
+ return sImpl.loadTransition(context, resId);
+ }
+
+ public static void setEnterTransition(android.app.Fragment fragment, Object transition) {
+ sImpl.setEnterTransition(fragment, transition);
+ }
+
+ public static void setExitTransition(android.app.Fragment fragment, Object transition) {
+ sImpl.setExitTransition(fragment, transition);
+ }
+
+ public static void setSharedElementEnterTransition(android.app.Fragment fragment,
+ Object transition) {
+ sImpl.setSharedElementEnterTransition(fragment, transition);
+ }
+
+ public static void addSharedElement(android.app.FragmentTransaction ft,
+ View view, String transitionName) {
+ sImpl.addSharedElement(ft, view, transitionName);
+ }
+
+ public static void setEnterTransition(android.support.v4.app.Fragment fragment,
+ Object transition) {
+ fragment.setEnterTransition(transition);
+ }
+
+ public static void setExitTransition(android.support.v4.app.Fragment fragment,
+ Object transition) {
+ fragment.setExitTransition(transition);
+ }
+
+ public static void setSharedElementEnterTransition(android.support.v4.app.Fragment fragment,
+ Object transition) {
+ fragment.setSharedElementEnterTransition(transition);
+ }
+
+ public static void addSharedElement(android.support.v4.app.FragmentTransaction ft,
+ View view, String transitionName) {
+ ft.addSharedElement(view, transitionName);
+ }
+
+ public static Object createFadeAndShortSlide(int edge) {
+ return sImpl.createFadeAndShortSlide(edge);
+ }
+
+ public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
+ sImpl.setTransitionGroup(viewGroup, transitionGroup);
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java b/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
index 614f12b..085aac3 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.support.v17.leanback.R;
import android.util.AttributeSet;
import android.util.Log;
@@ -154,6 +155,14 @@
try {
mCardType = a.getInteger(R.styleable.lbBaseCardView_cardType, CARD_TYPE_MAIN_ONLY);
+ Drawable cardForeground = a.getDrawable(R.styleable.lbBaseCardView_cardForeground);
+ if (cardForeground != null) {
+ setForeground(cardForeground);
+ }
+ Drawable cardBackground = a.getDrawable(R.styleable.lbBaseCardView_cardBackground);
+ if (cardBackground != null) {
+ setBackground(cardBackground);
+ }
mInfoVisibility = a.getInteger(R.styleable.lbBaseCardView_infoVisibility,
CARD_REGION_VISIBLE_ACTIVATED);
mExtraVisibility = a.getInteger(R.styleable.lbBaseCardView_extraVisibility,
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java b/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
index 93a454e..73e5b40 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
@@ -23,6 +23,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import android.support.v7.widget.SimpleItemAnimator;
/**
* An abstract base class for vertically and horizontally scrolling lists. The items come
@@ -201,7 +202,7 @@
// Disable change animation by default on leanback.
// Change animation will create a new view and cause undesired
// focus animation between the old view and new view.
- getItemAnimator().setSupportsChangeAnimations(false);
+ ((SimpleItemAnimator)getItemAnimator()).setSupportsChangeAnimations(false);
super.setRecyclerListener(new RecyclerView.RecyclerListener() {
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java b/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java
new file mode 100644
index 0000000..627bbd4
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Checkable;
+import android.widget.ImageView;
+
+/**
+ * ImageView that supports Checkable states.
+ */
+class CheckableImageView extends ImageView implements Checkable {
+
+ private boolean mChecked;
+
+ private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
+
+ public CheckableImageView(Context context) {
+ this(context, null);
+ }
+
+ public CheckableImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CheckableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public int[] onCreateDrawableState(final int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ if (isChecked()) {
+ mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+ }
+ return drawableState;
+ }
+
+ @Override
+ public void toggle() {
+ setChecked(!mChecked);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ @Override
+ public void setChecked(final boolean checked) {
+ if (mChecked != checked) {
+ mChecked = checked;
+ refreshDrawableState();
+ }
+ }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
index 410aa28..cac7d9e 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
@@ -232,11 +232,10 @@
Log.d(TAG, "setTransitionName "+mViewHolder.mOverviewFrame);
}
ViewCompat.setTransitionName(mViewHolder.mOverviewFrame, mSharedElementName);
- final TransitionHelper transitionHelper = TransitionHelper.getInstance();
- Object transition = transitionHelper.getSharedElementEnterTransition(
+ Object transition = TransitionHelper.getSharedElementEnterTransition(
mActivityToRunTransition.getWindow());
if (transition != null) {
- transitionHelper.setTransitionListener(transition, new TransitionListener() {
+ TransitionHelper.addTransitionListener(transition, new TransitionListener() {
@Override
public void onTransitionEnd(Object transition) {
if (DEBUG) {
@@ -247,7 +246,7 @@
if (mViewHolder.mActionsRow.isFocused()) {
mViewHolder.mActionsRow.requestFocus();
}
- transitionHelper.setTransitionListener(transition, null);
+ TransitionHelper.removeTransitionListener(transition, this);
}
});
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
index 48829eb..87bbbd4 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
@@ -85,7 +85,7 @@
mWrapper = null;
}
mAnimator.setTimeListener(this);
- if (mWrapper != null && useDimmer) {
+ if (useDimmer) {
mDimmer = ColorOverlayDimmer.createDefault(view.getContext());
} else {
mDimmer = null;
@@ -99,9 +99,16 @@
mView.setScaleY(scale);
if (mWrapper != null) {
mWrapper.setShadowFocusLevel(level);
- if (mDimmer != null) {
- mDimmer.setActiveLevel(level);
- mWrapper.setOverlayColor(mDimmer.getPaint().getColor());
+ } else {
+ ShadowOverlayHelper.setNoneWrapperShadowFocusLevel(mView, level);
+ }
+ if (mDimmer != null) {
+ mDimmer.setActiveLevel(level);
+ int color = mDimmer.getPaint().getColor();
+ if (mWrapper != null) {
+ mWrapper.setOverlayColor(color);
+ } else {
+ ShadowOverlayHelper.setNoneWrapperOverlayColor(mView, color);
}
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
new file mode 100644
index 0000000..c9bed58
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
@@ -0,0 +1,78 @@
+package android.support.v17.leanback.widget;
+
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.view.View;
+import android.view.ViewGroup;
+
+final class ForegroundHelper {
+
+ final static ForegroundHelper sInstance = new ForegroundHelper();
+ ForegroundHelperVersionImpl mImpl;
+
+ /**
+ * Interface implemented by classes that support Shadow.
+ */
+ static interface ForegroundHelperVersionImpl {
+
+ public void setForeground(View view, Drawable drawable);
+
+ public Drawable getForeground(View view);
+ }
+
+ /**
+ * Implementation used on api 23 (and above).
+ */
+ private static final class ForegroundHelperApi23Impl implements ForegroundHelperVersionImpl {
+ @Override
+ public void setForeground(View view, Drawable drawable) {
+ ForegroundHelperApi23.setForeground(view, drawable);
+ }
+
+ @Override
+ public Drawable getForeground(View view) {
+ return ForegroundHelperApi23.getForeground(view);
+ }
+ }
+
+ /**
+ * Stub implementation
+ */
+ private static final class ForegroundHelperStubImpl implements ForegroundHelperVersionImpl {
+ @Override
+ public void setForeground(View view, Drawable drawable) {
+ }
+
+ @Override
+ public Drawable getForeground(View view) {
+ return null;
+ }
+ }
+
+ private ForegroundHelper() {
+ if (supportsForeground()) {
+ mImpl = new ForegroundHelperApi23Impl();
+ } else {
+ mImpl = new ForegroundHelperStubImpl();
+ }
+ }
+
+ public static ForegroundHelper getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * Returns true if view.setForeground() is supported.
+ */
+ public static boolean supportsForeground() {
+ return Build.VERSION.SDK_INT >= 23;
+ }
+
+ public Drawable getForeground(View view) {
+ return mImpl.getForeground(view);
+ }
+
+ public void setForeground(View view, Drawable drawable) {
+ mImpl.setForeground(view, drawable);
+ }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java b/v17/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java
index 8bd0007..1c5dcb5 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java
@@ -26,47 +26,15 @@
public interface FragmentAnimationProvider {
/**
- * Animates the entry of the fragment in the case where the activity is first being presented.
+ * Animates the fragment in response to the IME appearing.
* @param animators A list of animations to which this provider's animations should be added.
*/
- public abstract void onActivityEnter(@NonNull List<Animator> animators);
+ public abstract void onImeAppearing(@NonNull List<Animator> animators);
/**
- * Animates the exit of the fragment in the case where the activity is about to pause.
+ * Animates the fragment in response to the IME disappearing.
* @param animators A list of animations to which this provider's animations should be added.
*/
- public abstract void onActivityExit(@NonNull List<Animator> animators);
-
- /**
- * Animates the entry of the fragment in the case where there is a previous step fragment
- * participating in the animation. Entry occurs when the fragment is preparing to be shown
- * as it is pushed onto the back stack.
- * @param animators A list of animations to which this provider's animations should be added.
- */
- public abstract void onFragmentEnter(@NonNull List<Animator> animators);
-
- /**
- * Animates the exit of the fragment in the case where there is a previous step fragment
- * participating in the animation. Exit occurs when the fragment is preparing to be removed,
- * hidden, or detached due to pushing another fragment onto the back stack.
- * @param animators A list of animations to which this provider's animations should be added.
- */
- public abstract void onFragmentExit(@NonNull List<Animator> animators);
-
- /**
- * Animates the re-entry of the fragment in the case where there is a previous step fragment
- * participating in the animation. Re-entry occurs when the fragment is preparing to be shown
- * due to popping the back stack.
- * @param animators A list of animations to which this provider's animations should be added.
- */
- public abstract void onFragmentReenter(@NonNull List<Animator> animators);
-
- /**
- * Animates the return of the fragment in the case where there is a previous step fragment
- * participating in the animation. Return occurs when the fragment is preparing to be removed,
- * hidden, or detached due to popping the back stack.
- * @param animators A list of animations to which this provider's animations should be added.
- */
- public abstract void onFragmentReturn(@NonNull List<Animator> animators);
+ public abstract void onImeDisappearing(@NonNull List<Animator> animators);
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
index c4418c1..7c9d5db 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
@@ -528,19 +528,6 @@
mListener = listener;
}
- private int getDefaultBackgroundColor(Context context) {
- TypedValue outValue = new TypedValue();
- if (context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
- return context.getResources().getColor(outValue.resourceId);
- }
- return context.getResources().getColor(R.color.lb_default_brand_color);
- }
-
- private int getDefaultActionsBackgroundColor(Context context) {
- int c = getDefaultBackgroundColor(context);
- return Color.argb(Color.alpha(c), Color.red(c) / 2, Color.green(c) / 2, Color.blue(c) / 2);
- }
-
/**
* Get resource id to inflate the layout. The layout must match {@link #STATE_HALF}
*/
@@ -558,13 +545,13 @@
vh.mActionBridgeAdapter = new ActionsItemBridgeAdapter(vh);
final View overview = vh.mOverviewFrame;
- final int bgColor = mBackgroundColorSet ? mBackgroundColor :
- getDefaultBackgroundColor(overview.getContext());
- overview.setBackgroundColor(bgColor);
- final int actionBgColor = mActionsBackgroundColorSet ? mActionsBackgroundColor :
- getDefaultActionsBackgroundColor(overview.getContext());
- overview.findViewById(R.id.details_overview_actions_background)
- .setBackgroundColor(actionBgColor);
+ if (mBackgroundColorSet) {
+ overview.setBackgroundColor(mBackgroundColor);
+ }
+ if (mActionsBackgroundColorSet) {
+ overview.findViewById(R.id.details_overview_actions_background)
+ .setBackgroundColor(mActionsBackgroundColor);
+ }
RoundedRectHelper.getInstance().setClipToRoundedOutline(overview, true);
if (!getSelectEffectEnabled()) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
index 857c4d9..a9fe9ec 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
@@ -76,8 +76,7 @@
if (DEBUG) {
Log.d(TAG, "postponeEnterTransition " + mActivityToRunTransition);
}
- Object transition = TransitionHelper.getInstance()
- .getSharedElementEnterTransition(activity.getWindow());
+ Object transition = TransitionHelper.getSharedElementEnterTransition(activity.getWindow());
setAutoStartSharedElementTransition(transition != null);
ActivityCompat.postponeEnterTransition(mActivityToRunTransition);
if (timeoutMs > 0) {
@@ -140,11 +139,10 @@
}
ViewCompat.setTransitionName(mViewHolder.getLogoViewHolder().view,
mSharedElementName);
- final TransitionHelper transitionHelper = TransitionHelper.getInstance();
- Object transition = transitionHelper.getSharedElementEnterTransition(
+ Object transition = TransitionHelper.getSharedElementEnterTransition(
mActivityToRunTransition.getWindow());
if (transition != null) {
- transitionHelper.setTransitionListener(transition, new TransitionListener() {
+ TransitionHelper.addTransitionListener(transition, new TransitionListener() {
@Override
public void onTransitionEnd(Object transition) {
if (DEBUG) {
@@ -155,7 +153,7 @@
if (mViewHolder.getActionsRow().isFocused()) {
mViewHolder.getActionsRow().requestFocus();
}
- transitionHelper.setTransitionListener(transition, null);
+ TransitionHelper.removeTransitionListener(transition, this);
}
});
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index 10c7e3e..20d54e2 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -58,7 +58,7 @@
* - Saves optical bounds insets.
* - Caches focus align view center.
*/
- static class LayoutParams extends RecyclerView.LayoutParams {
+ final static class LayoutParams extends RecyclerView.LayoutParams {
// For placement
private int mLeftInset;
@@ -128,6 +128,32 @@
return view.getHeight() - mTopInset - mBottomInset;
}
+ int getDecoratedOpticalLeftWithMargin(RecyclerView.LayoutManager lm, View view) {
+ return lm.getDecoratedLeft(view) + mLeftInset - leftMargin;
+ }
+
+ int getDecoratedOpticalTopWithMargin(RecyclerView.LayoutManager lm, View view) {
+ return lm.getDecoratedTop(view) + mTopInset - topMargin;
+ }
+
+ int getDecoratedOpticalRightWithMargin(RecyclerView.LayoutManager lm, View view) {
+ return lm.getDecoratedRight(view) - mRightInset + rightMargin;
+ }
+
+ int getDecoratedOpticalBottomWithMargin(RecyclerView.LayoutManager lm, View view) {
+ return lm.getDecoratedBottom(view) - mBottomInset + bottomMargin;
+ }
+
+ int getDecoratedOpticalWidthWithMargin(RecyclerView.LayoutManager lm, View view) {
+ return lm.getDecoratedRight(view) - lm.getDecoratedLeft(view)
+ - mLeftInset - mRightInset + leftMargin + rightMargin;
+ }
+
+ int getDecoratedOpticalHeightWithMargin(RecyclerView.LayoutManager lm, View view) {
+ return lm.getDecoratedBottom(view) - lm.getDecoratedTop(view)
+ - mTopInset - mBottomInset + topMargin + bottomMargin;
+ }
+
int getOpticalLeftInset() {
return mLeftInset;
}
@@ -199,9 +225,18 @@
@Override
protected void onStop() {
- // onTargetFound() may not be called if we hit the "wall" first.
+ // onTargetFound() may not be called if we hit the "wall" first or get cancelled.
View targetView = findViewByPosition(getTargetPosition());
- if (hasFocus() && targetView != null) {
+ if (targetView == null) {
+ if (getTargetPosition() >= 0) {
+ // if smooth scroller is stopped without target, immediately jumps
+ // to the target position.
+ scrollToSelection(mBaseGridView, getTargetPosition(), 0, false, 0);
+ }
+ super.onStop();
+ return;
+ }
+ if (hasFocus()) {
mInSelection = true;
targetView.requestFocus();
mInSelection = false;
@@ -391,6 +426,8 @@
private RecyclerView.State mState;
private RecyclerView.Recycler mRecycler;
+ private static final Rect sTempRect = new Rect();
+
private boolean mInLayout;
private boolean mInScroll;
private boolean mInFastRelayout;
@@ -913,16 +950,21 @@
}
private int getViewMin(View v) {
- return (mOrientation == HORIZONTAL) ? getOpticalLeft(v) : getOpticalTop(v);
+ LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ return (mOrientation == HORIZONTAL) ? lp.getDecoratedOpticalLeftWithMargin(this, v)
+ : lp.getDecoratedOpticalTopWithMargin(this, v);
}
private int getViewMax(View v) {
- return (mOrientation == HORIZONTAL) ? getOpticalRight(v) : getOpticalBottom(v);
+ LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ return (mOrientation == HORIZONTAL) ? lp.getDecoratedOpticalRightWithMargin(this, v)
+ : lp.getDecoratedOpticalBottomWithMargin(this, v);
}
private int getViewPrimarySize(View view) {
LayoutParams p = (LayoutParams) view.getLayoutParams();
- return mOrientation == HORIZONTAL ? p.getOpticalWidth(view) : p.getOpticalHeight(view);
+ return mOrientation == HORIZONTAL ? p.getDecoratedOpticalWidthWithMargin(this, view)
+ : p.getDecoratedOpticalHeightWithMargin(this, view);
}
private int getViewCenter(View view) {
@@ -1056,18 +1098,33 @@
return getRowStartSecondary(rightmostIndex) + getRowSizeSecondary(rightmostIndex);
}
+ int getDecoratedMeasuredWidthWithMargin(View v) {
+ final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ return getDecoratedMeasuredWidth(v) + lp.leftMargin + lp.rightMargin;
+ }
+
+ int getDecoratedMeasuredHeightWithMargin(View v) {
+ final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ return getDecoratedMeasuredHeight(v) + lp.topMargin + lp.bottomMargin;
+ }
+
private void measureScrapChild(int position, int widthSpec, int heightSpec,
int[] measuredDimension) {
View view = mRecycler.getViewForPosition(position);
if (view != null) {
- LayoutParams p = (LayoutParams) view.getLayoutParams();
+ final LayoutParams p = (LayoutParams) view.getLayoutParams();
+ calculateItemDecorationsForChild(view, sTempRect);
+ int widthUsed = p.leftMargin + p.rightMargin + sTempRect.left + sTempRect.right;
+ int heightUsed = p.topMargin + p.bottomMargin + sTempRect.top + sTempRect.bottom;
+
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
- getPaddingLeft() + getPaddingRight(), p.width);
+ getPaddingLeft() + getPaddingRight() + widthUsed, p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
- getPaddingTop() + getPaddingBottom(), p.height);
+ getPaddingTop() + getPaddingBottom() + heightUsed, p.height);
view.measure(childWidthSpec, childHeightSpec);
- measuredDimension[0] = view.getMeasuredWidth();
- measuredDimension[1] = view.getMeasuredHeight();
+
+ measuredDimension[0] = getDecoratedMeasuredWidthWithMargin(view);
+ measuredDimension[1] = getDecoratedMeasuredHeightWithMargin(view);
mRecycler.recycleView(view);
}
}
@@ -1100,7 +1157,8 @@
measureChild(view);
}
final int secondarySize = mOrientation == HORIZONTAL ?
- view.getMeasuredHeight() : view.getMeasuredWidth();
+ getDecoratedMeasuredHeightWithMargin(view)
+ : getDecoratedMeasuredWidthWithMargin(view);
if (secondarySize > rowSize) {
rowSize = secondarySize;
}
@@ -1229,14 +1287,8 @@
} else {
switch (modeSecondary) {
case MeasureSpec.UNSPECIFIED:
- if (mRowSizeSecondaryRequested == 0) {
- if (mOrientation == HORIZONTAL) {
- throw new IllegalStateException("Must specify rowHeight or view height");
- } else {
- throw new IllegalStateException("Must specify columnWidth or view width");
- }
- }
- mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
+ mFixedRowSizeSecondary = mRowSizeSecondaryRequested == 0 ?
+ sizeSecondary - paddingSecondary: mRowSizeSecondaryRequested;
mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
measuredSizeSecondary = mFixedRowSizeSecondary * mNumRows + mMarginSecondary
* (mNumRows - 1) + paddingSecondary;
@@ -1287,7 +1339,11 @@
private void measureChild(View child) {
if (TRACE) TraceHelper.beginSection("measureChild");
- final ViewGroup.LayoutParams lp = child.getLayoutParams();
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ calculateItemDecorationsForChild(child, sTempRect);
+ int widthUsed = lp.leftMargin + lp.rightMargin + sTempRect.left + sTempRect.right;
+ int heightUsed = lp.topMargin + lp.bottomMargin + sTempRect.top + sTempRect.bottom;
+
final int secondarySpec = (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT) ?
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) :
MeasureSpec.makeMeasureSpec(mFixedRowSizeSecondary, MeasureSpec.EXACTLY);
@@ -1295,14 +1351,12 @@
if (mOrientation == HORIZONTAL) {
widthSpec = ViewGroup.getChildMeasureSpec(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- 0, lp.width);
- heightSpec = ViewGroup.getChildMeasureSpec(secondarySpec, 0, lp.height);
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), widthUsed, lp.width);
+ heightSpec = ViewGroup.getChildMeasureSpec(secondarySpec, heightUsed, lp.height);
} else {
heightSpec = ViewGroup.getChildMeasureSpec(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- 0, lp.height);
- widthSpec = ViewGroup.getChildMeasureSpec(secondarySpec, 0, lp.width);
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightUsed, lp.height);
+ widthSpec = ViewGroup.getChildMeasureSpec(secondarySpec, widthUsed, lp.width);
}
child.measure(widthSpec, heightSpec);
if (DEBUG) Log.v(getTag(), "measureChild secondarySpec " + Integer.toHexString(secondarySpec) +
@@ -1395,7 +1449,8 @@
measureChild(v);
}
item[0] = v;
- return mOrientation == HORIZONTAL ? v.getMeasuredWidth() : v.getMeasuredHeight();
+ return mOrientation == HORIZONTAL ? getDecoratedMeasuredWidthWithMargin(v)
+ : getDecoratedMeasuredHeightWithMargin(v);
}
@Override
@@ -1476,8 +1531,8 @@
private void layoutChild(int rowIndex, View v, int start, int end, int startSecondary) {
if (TRACE) TraceHelper.beginSection("layoutChild");
- int sizeSecondary = mOrientation == HORIZONTAL ? v.getMeasuredHeight()
- : v.getMeasuredWidth();
+ int sizeSecondary = mOrientation == HORIZONTAL ? getDecoratedMeasuredHeightWithMargin(v)
+ : getDecoratedMeasuredWidthWithMargin(v);
if (mFixedRowSizeSecondary > 0) {
sizeSecondary = Math.min(sizeSecondary, mFixedRowSizeSecondary);
}
@@ -1507,7 +1562,9 @@
bottom = end;
right = startSecondary + sizeSecondary;
}
- v.layout(left, top, right, bottom);
+ LayoutParams params = (LayoutParams) v.getLayoutParams();
+ layoutDecorated(v, left + params.leftMargin, top + params.topMargin,
+ right - params.rightMargin, bottom - params.bottomMargin);
updateChildOpticalInsets(v, left, top, right, bottom);
updateChildAlignments(v);
if (TRACE) TraceHelper.endSection();
@@ -1624,10 +1681,10 @@
measureChild(view);
}
if (mOrientation == HORIZONTAL) {
- primarySize = view.getMeasuredWidth();
+ primarySize = getDecoratedMeasuredWidthWithMargin(view);
end = start + primarySize;
} else {
- primarySize = view.getMeasuredHeight();
+ primarySize = getDecoratedMeasuredHeightWithMargin(view);
end = start + primarySize;
}
layoutChild(location.row, view, start, end, startSecondary);
@@ -1716,6 +1773,11 @@
mFocusPositionOffset = 0;
saveContext(recycler, state);
+ View savedFocusView = findViewByPosition(mFocusPosition);
+ int savedFocusPos = mFocusPosition;
+ int savedSubFocusPos = mSubFocusPosition;
+ boolean hadFocus = mBaseGridView.hasFocus();
+
// Track the old focus view so we can adjust our system scroll position
// so that any scroll animations happening now will remain valid.
// We must use same delta in Pre Layout (if prelayout exists) and second layout.
@@ -1724,17 +1786,14 @@
if (mFocusPosition != NO_POSITION && scrollToFocus
&& mBaseGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
// FIXME: we should get the remaining scroll animation offset from RecyclerView
- View focusView = findViewByPosition(mFocusPosition);
- if (focusView != null) {
- if (getScrollPosition(focusView, focusView.findFocus(), sTwoInts)) {
+ if (savedFocusView != null) {
+ if (getScrollPosition(savedFocusView, savedFocusView.findFocus(), sTwoInts)) {
delta = sTwoInts[0];
deltaSecondary = sTwoInts[1];
}
}
}
- boolean hadFocus = mBaseGridView.hasFocus();
- int savedFocusPos = mFocusPosition;
if (mInFastRelayout = layoutInit()) {
fastRelayout();
// appends items till focus position.
@@ -1802,7 +1861,8 @@
}
// For fastRelayout, only dispatch event when focus position changes.
- if (mInFastRelayout && mFocusPosition != savedFocusPos) {
+ if (mInFastRelayout && (mFocusPosition != savedFocusPos || mSubFocusPosition !=
+ savedFocusPos || findViewByPosition(mFocusPosition) != savedFocusView)) {
dispatchChildSelected();
} else if (!mInFastRelayout && mInLayoutSearchFocus) {
// For full layout we dispatchChildSelected() in createItem() unless searched all
@@ -1968,7 +2028,7 @@
int pos = sTwoInts[1];
int savedMaxEdge = mWindowAlignment.mainAxis().getMaxEdge();
mWindowAlignment.mainAxis().setMaxEdge(maxEdge);
- int maxScroll = getPrimarySystemScrollPosition(findViewByPosition(pos));
+ int maxScroll = getPrimarySystemScrollPositionOfChildMax(findViewByPosition(pos));
mWindowAlignment.mainAxis().setMaxEdge(savedMaxEdge);
if (highAvailable) {
@@ -2319,6 +2379,16 @@
return mWindowAlignment.mainAxis().getSystemScrollPos(viewCenterPrimary, isMin, isMax);
}
+ private int getPrimarySystemScrollPositionOfChildMax(View view) {
+ int scrollPosition = getPrimarySystemScrollPosition(view);
+ final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ int[] multipleAligns = lp.getAlignMultiple();
+ if (multipleAligns != null && multipleAligns.length > 0) {
+ scrollPosition += multipleAligns[multipleAligns.length - 1] - multipleAligns[0];
+ }
+ return scrollPosition;
+ }
+
/**
* Get adjusted primary position for a given childView (if there is multiple ItemAlignment defined
* on the view).
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
index 8d12510..3fcdbba 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
@@ -54,11 +54,8 @@
* </ul><p>
* View IDs are allowed to be missing, in which case the corresponding views will be null.
*
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceEntryAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepEntryAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepExitAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepReentryAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepReturnAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceContainerStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceTitleStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidanceDescriptionStyle
@@ -176,6 +173,16 @@
}
/**
+ * Called when destroy the View created by GuidanceStylist.
+ */
+ public void onDestroyView() {
+ mBreadcrumbView = null;
+ mDescriptionView = null;
+ mIconView = null;
+ mTitleView = null;
+ }
+
+ /**
* Provides the resource ID of the layout defining the guidance view. Subclasses may override
* to provide their own customized layouts. The base implementation returns
* {@link android.support.v17.leanback.R.layout#lb_guidance}. If overridden, the substituted
@@ -223,61 +230,22 @@
* {@inheritDoc}
*/
@Override
- public void onActivityEnter(@NonNull List<Animator> animators) {
- addAnimator(animators, mTitleView, R.attr.guidanceEntryAnimation);
- addAnimator(animators, mBreadcrumbView, R.attr.guidanceEntryAnimation);
- addAnimator(animators, mDescriptionView, R.attr.guidanceEntryAnimation);
- addAnimator(animators, mIconView, R.attr.guidanceEntryAnimation);
+ public void onImeAppearing(@NonNull List<Animator> animators) {
+ addAnimator(animators, mTitleView, R.attr.guidedStepImeAppearingAnimation);
+ addAnimator(animators, mBreadcrumbView, R.attr.guidedStepImeAppearingAnimation);
+ addAnimator(animators, mDescriptionView, R.attr.guidedStepImeAppearingAnimation);
+ addAnimator(animators, mIconView, R.attr.guidedStepImeAppearingAnimation);
}
/**
* {@inheritDoc}
*/
@Override
- public void onActivityExit(@NonNull List<Animator> animators) {}
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFragmentEnter(@NonNull List<Animator> animators) {
- addAnimator(animators, mTitleView, R.attr.guidedStepEntryAnimation);
- addAnimator(animators, mBreadcrumbView, R.attr.guidedStepEntryAnimation);
- addAnimator(animators, mDescriptionView, R.attr.guidedStepEntryAnimation);
- addAnimator(animators, mIconView, R.attr.guidedStepEntryAnimation);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFragmentExit(@NonNull List<Animator> animators) {
- addAnimator(animators, mTitleView, R.attr.guidedStepExitAnimation);
- addAnimator(animators, mBreadcrumbView, R.attr.guidedStepExitAnimation);
- addAnimator(animators, mDescriptionView, R.attr.guidedStepExitAnimation);
- addAnimator(animators, mIconView, R.attr.guidedStepExitAnimation);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFragmentReenter(@NonNull List<Animator> animators) {
- addAnimator(animators, mTitleView, R.attr.guidedStepReentryAnimation);
- addAnimator(animators, mBreadcrumbView, R.attr.guidedStepReentryAnimation);
- addAnimator(animators, mDescriptionView, R.attr.guidedStepReentryAnimation);
- addAnimator(animators, mIconView, R.attr.guidedStepReentryAnimation);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFragmentReturn(@NonNull List<Animator> animators) {
- addAnimator(animators, mTitleView, R.attr.guidedStepReturnAnimation);
- addAnimator(animators, mBreadcrumbView, R.attr.guidedStepReturnAnimation);
- addAnimator(animators, mDescriptionView, R.attr.guidedStepReturnAnimation);
- addAnimator(animators, mIconView, R.attr.guidedStepReturnAnimation);
+ public void onImeDisappearing(@NonNull List<Animator> animators) {
+ addAnimator(animators, mTitleView, R.attr.guidedStepImeDisappearingAnimation);
+ addAnimator(animators, mBreadcrumbView, R.attr.guidedStepImeDisappearingAnimation);
+ addAnimator(animators, mDescriptionView, R.attr.guidedStepImeDisappearingAnimation);
+ addAnimator(animators, mIconView, R.attr.guidedStepImeDisappearingAnimation);
}
private void addAnimator(List<Animator> animators, View v, int attrId) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
index e4db2eb..21986d5 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
@@ -13,9 +13,12 @@
*/
package android.support.v17.leanback.widget;
+import android.support.v17.leanback.R;
+
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.text.InputType;
import android.util.Log;
/**
@@ -34,47 +37,189 @@
private static final String TAG = "GuidedAction";
- public static final int NO_DRAWABLE = 0;
+ /**
+ * Special check set Id that is neither checkbox nor radio.
+ */
public static final int NO_CHECK_SET = 0;
+ /**
+ * Default checkset Id for radio.
+ */
public static final int DEFAULT_CHECK_SET_ID = 1;
+ /**
+ * Checkset Id for checkbox.
+ */
+ public static final int CHECKBOX_CHECK_SET_ID = -1;
/**
- * Builds a {@link GuidedAction} object.
+ * When finishing editing, goes to next action.
+ */
+ public static final long ACTION_ID_NEXT = -2;
+ /**
+ * When finishing editing, stay on current action.
+ */
+ public static final long ACTION_ID_CURRENT = -3;
+
+ /**
+ * Id of standard OK action.
+ */
+ public static final long ACTION_ID_OK = -4;
+
+ /**
+ * Id of standard Cancel action.
+ */
+ public static final long ACTION_ID_CANCEL = -5;
+
+ /**
+ * Id of standard Finish action.
+ */
+ public static final long ACTION_ID_FINISH = -6;
+
+ /**
+ * Id of standard Finish action.
+ */
+ public static final long ACTION_ID_CONTINUE = -7;
+
+ /**
+ * Id of standard Yes action.
+ */
+ public static final long ACTION_ID_YES = -8;
+
+ /**
+ * Id of standard No action.
+ */
+ public static final long ACTION_ID_NO = -9;
+
+ /**
+ * Builds a {@link GuidedAction} object. When subclass GuidedAction, you may override this
+ * Builder class and call {@link #applyValues(GuidedAction)}.
*/
public static class Builder {
private long mId;
- private String mTitle;
- private String mDescription;
+ private CharSequence mTitle;
+ private CharSequence mEditTitle;
+ private CharSequence mDescription;
+ private CharSequence mEditDescription;
private Drawable mIcon;
private boolean mChecked;
private boolean mMultilineDescription;
private boolean mHasNext;
private boolean mInfoOnly;
+ private boolean mEditable = false;
+ private boolean mDescriptionEditable = false;
+ private int mInputType = InputType.TYPE_CLASS_TEXT;
+ private int mDescriptionInputType = InputType.TYPE_CLASS_TEXT;
+ private int mEditInputType = InputType.TYPE_CLASS_TEXT;
+ private int mDescriptionEditInputType = InputType.TYPE_CLASS_TEXT;
private int mCheckSetId = NO_CHECK_SET;
private boolean mEnabled = true;
+ private boolean mFocusable = true;
private Intent mIntent;
/**
* Builds the GuidedAction corresponding to this Builder.
* @return the GuidedAction as configured through this Builder.
*/
- public GuidedAction build() {
+ public final GuidedAction build() {
GuidedAction action = new GuidedAction();
+ applyValues(action);
+ return action;
+ }
+
+ /**
+ * Subclass Builder may call this function to apply values.
+ * @param action GuidedAction to apply Builder values.
+ */
+ protected final void applyValues(GuidedAction action) {
// Base Action values
action.setId(mId);
action.setLabel1(mTitle);
+ action.setEditTitle(mEditTitle);
action.setLabel2(mDescription);
+ action.setEditDescription(mEditDescription);
action.setIcon(mIcon);
// Subclass values
action.mIntent = mIntent;
+ action.mEditable = mEditable;
+ action.mDescriptionEditable = mDescriptionEditable;
+ action.mInputType = mInputType;
+ action.mDescriptionInputType = mDescriptionInputType;
+ action.mEditInputType = mEditInputType;
+ action.mDescriptionEditInputType = mDescriptionEditInputType;
action.mChecked = mChecked;
action.mCheckSetId = mCheckSetId;
action.mMultilineDescription = mMultilineDescription;
action.mHasNext = mHasNext;
action.mInfoOnly = mInfoOnly;
action.mEnabled = mEnabled;
- return action;
+ action.mFocusable = mFocusable;
+ }
+
+ /**
+ * Construct a standard "OK" action with {@link GuidedAction#ACTION_ID_OK}.
+ * @param context Context for loading action title.
+ * @return The same Builder object.
+ */
+ public Builder constructOK(Context context) {
+ mId = ACTION_ID_OK;
+ mTitle = context.getString(android.R.string.ok);
+ return this;
+ }
+
+ /**
+ * Construct a standard "Cancel" action with {@link GuidedAction#ACTION_ID_CANCEL}.
+ * @param context Context for loading action title.
+ * @return The same Builder object.
+ */
+ public Builder constructCancel(Context context) {
+ mId = ACTION_ID_CANCEL;
+ mTitle = context.getString(android.R.string.cancel);
+ return this;
+ }
+
+ /**
+ * Construct a standard "Finish" action with {@link GuidedAction#ACTION_ID_FINISH}.
+ * @param context Context for loading action title.
+ * @return The same Builder object.
+ */
+ public Builder constructFinish(Context context) {
+ mId = ACTION_ID_FINISH;
+ mTitle = context.getString(R.string.lb_guidedaction_finish_title);
+ return this;
+ }
+
+ /**
+ * Construct a standard "Continue" action with {@link GuidedAction#ACTION_ID_CONTINUE}.
+ * @param context Context for loading action title.
+ * @return The same Builder object.
+ */
+ public Builder constructContinue(Context context) {
+ mId = ACTION_ID_CONTINUE;
+ mHasNext = true;
+ mTitle = context.getString(R.string.lb_guidedaction_continue_title);
+ return this;
+ }
+
+ /**
+ * Construct a standard "Yes" action with {@link GuidedAction#ACTION_ID_YES}.
+ * @param context Context for loading action title.
+ * @return The same Builder object.
+ */
+ public Builder constructYes(Context context) {
+ mId = ACTION_ID_YES;
+ mTitle = context.getString(android.R.string.yes);
+ return this;
+ }
+
+ /**
+ * Construct a standard "No" action with {@link GuidedAction#ACTION_ID_NO}.
+ * @param context Context for loading action title.
+ * @return The same Builder object.
+ */
+ public Builder constructNo(Context context) {
+ mId = ACTION_ID_NO;
+ mTitle = context.getString(android.R.string.no);
+ return this;
}
/**
@@ -92,22 +237,41 @@
* action to be taken on click, e.g. "Continue" or "Cancel".
* @param title The title for this action.
*/
- public Builder title(String title) {
+ public Builder title(CharSequence title) {
mTitle = title;
return this;
}
/**
+ * Sets the optional title text to edit. When TextView is activated, the edit title
+ * replaces the string of title.
+ */
+ public Builder editTitle(CharSequence editTitle) {
+ mEditTitle = editTitle;
+ return this;
+ }
+
+ /**
* Sets the description for this action. The description is typically a longer string
* providing extra information on what the action will do.
* @param description The description for this action.
*/
- public Builder description(String description) {
+ public Builder description(CharSequence description) {
mDescription = description;
return this;
}
/**
+ * Sets the optional description text to edit. When TextView is activated, the edit
+ * description replaces the string of description.
+ * @param description The description to edit for this action.
+ */
+ public Builder editDescription(CharSequence description) {
+ mEditDescription = description;
+ return this;
+ }
+
+ /**
* Sets the intent associated with this action. Clients would typically fire this intent
* directly when the action is clicked.
* @param intent The intent associated with this action.
@@ -138,22 +302,96 @@
}
/**
+ * Indicates whether this action title is editable. Note: Editable actions cannot also be
+ * checked, or belong to a check set.
+ * @param editable Whether this action is editable.
+ */
+ public Builder editable(boolean editable) {
+ mEditable = editable;
+ if (mChecked || mCheckSetId != NO_CHECK_SET) {
+ throw new IllegalArgumentException("Editable actions cannot also be checked");
+ }
+ return this;
+ }
+
+ /**
+ * Indicates whether this action's description is editable
+ * @param editable Whether this action description is editable.
+ */
+ public Builder descriptionEditable(boolean editable) {
+ mDescriptionEditable = editable;
+ if (mChecked || mCheckSetId != NO_CHECK_SET) {
+ throw new IllegalArgumentException("Editable actions cannot also be checked");
+ }
+ return this;
+ }
+
+ /**
+ * Sets {@link InputType} of this action title not in editing.
+ *
+ * @param inputType InputType for the action title not in editing.
+ */
+ public Builder inputType(int inputType) {
+ mInputType = inputType;
+ return this;
+ }
+
+ /**
+ * Sets {@link InputType} of this action description not in editing.
+ *
+ * @param inputType InputType for the action description not in editing.
+ */
+ public Builder descriptionInputType(int inputType) {
+ mDescriptionInputType = inputType;
+ return this;
+ }
+
+
+ /**
+ * Sets {@link InputType} of this action title in editing.
+ *
+ * @param inputType InputType for the action title in editing.
+ */
+ public Builder editInputType(int inputType) {
+ mEditInputType = inputType;
+ return this;
+ }
+
+ /**
+ * Sets {@link InputType} of this action description in editing.
+ *
+ * @param inputType InputType for the action description in editing.
+ */
+ public Builder descriptionEditInputType(int inputType) {
+ mDescriptionEditInputType = inputType;
+ return this;
+ }
+
+
+ /**
* Indicates whether this action is initially checked.
* @param checked Whether this action is checked.
*/
public Builder checked(boolean checked) {
mChecked = checked;
+ if (mEditable || mDescriptionEditable) {
+ throw new IllegalArgumentException("Editable actions cannot also be checked");
+ }
return this;
}
/**
- * Indicates whether this action is part of a single-select group similar to radio buttons.
- * When one item in a check set is checked, all others with the same check set ID will be
- * unchecked automatically.
- * @param checkSetId The check set ID, or {@link #NO_CHECK_SET) to indicate no check set.
+ * Indicates whether this action is part of a single-select group similar to radio buttons
+ * or this action is a checkbox. When one item in a check set is checked, all others with
+ * the same check set ID will be nchecked automatically.
+ * @param checkSetId The check set ID, or {@link GuidedAction#NO_CHECK_SET} to indicate not
+ * radio or checkbox, or {@link GuidedAction#CHECKBOX_CHECK_SET_ID} to indicate a checkbox.
*/
public Builder checkSetId(int checkSetId) {
mCheckSetId = checkSetId;
+ if (mEditable || mDescriptionEditable) {
+ throw new IllegalArgumentException("Editable actions cannot also be in check sets");
+ }
return this;
}
@@ -193,18 +431,37 @@
mEnabled = enabled;
return this;
}
+
+ /**
+ * Indicates whether this action can take focus.
+ * @param focusable
+ * @return The same Builder object.
+ */
+ public Builder focusable(boolean focusable) {
+ mFocusable = focusable;
+ return this;
+ }
}
- private boolean mChecked;
+ private CharSequence mEditTitle;
+ private CharSequence mEditDescription;
+ private boolean mEditable;
+ private boolean mDescriptionEditable;
+ private int mInputType;
+ private int mDescriptionInputType;
+ private int mEditInputType;
+ private int mDescriptionEditInputType;
private boolean mMultilineDescription;
private boolean mHasNext;
+ private boolean mChecked;
private boolean mInfoOnly;
private int mCheckSetId;
private boolean mEnabled;
+ private boolean mFocusable;
private Intent mIntent;
- private GuidedAction() {
+ protected GuidedAction() {
super(0);
}
@@ -217,14 +474,74 @@
}
/**
+ * Sets the title of this action.
+ * @param title The title set when this action was built.
+ */
+ public void setTitle(CharSequence title) {
+ setLabel1(title);
+ }
+
+ /**
+ * Returns the optional title text to edit. When not null, it is being edited instead of
+ * {@link #getTitle()}.
+ * @return Optional title text to edit instead of {@link #getTitle()}.
+ */
+ public CharSequence getEditTitle() {
+ return mEditTitle;
+ }
+
+ /**
+ * Sets the optional title text to edit instead of {@link #setTitle(CharSequence)}.
+ * @param editTitle Optional title text to edit instead of {@link #setTitle(CharSequence)}.
+ */
+ public void setEditTitle(CharSequence editTitle) {
+ mEditTitle = editTitle;
+ }
+
+ /**
+ * Returns the optional description text to edit. When not null, it is being edited instead of
+ * {@link #getDescription()}.
+ * @return Optional description text to edit instead of {@link #getDescription()}.
+ */
+ public CharSequence getEditDescription() {
+ return mEditDescription;
+ }
+
+ /**
+ * Sets the optional description text to edit instead of {@link #setDescription(CharSequence)}.
+ * @param editDescription Optional description text to edit instead of
+ * {@link #setDescription(CharSequence)}.
+ */
+ public void setEditDescription(CharSequence editDescription) {
+ mEditDescription = editDescription;
+ }
+
+ /**
+ * Returns true if {@link #getEditTitle()} is not null. When true, the {@link #getEditTitle()}
+ * is being edited instead of {@link #getTitle()}.
+ * @return true if {@link #getEditTitle()} is not null.
+ */
+ public boolean isEditTitleUsed() {
+ return mEditTitle != null;
+ }
+
+ /**
* Returns the description of this action.
- * @return The description set when this action was built.
+ * @return The description of this action.
*/
public CharSequence getDescription() {
return getLabel2();
}
/**
+ * Sets the description of this action.
+ * @param description The description of the action.
+ */
+ public void setDescription(CharSequence description) {
+ setLabel2(description);
+ }
+
+ /**
* Returns the intent associated with this action.
* @return The intent set when this action was built.
*/
@@ -233,6 +550,55 @@
}
/**
+ * Returns whether this action title is editable.
+ * @return true if the action title is editable, false otherwise.
+ */
+ public boolean isEditable() {
+ return mEditable;
+ }
+
+ /**
+ * Returns whether this action description is editable.
+ * @return true if the action description is editable, false otherwise.
+ */
+ public boolean isDescriptionEditable() {
+ return mDescriptionEditable;
+ }
+
+ /**
+ * Returns InputType of action title in editing; only valid when {@link #isEditable()} is true.
+ * @return InputType of action title in editing.
+ */
+ public int getEditInputType() {
+ return mEditInputType;
+ }
+
+ /**
+ * Returns InputType of action description in editing; only valid when
+ * {@link #isDescriptionEditable()} is true.
+ * @return InputType of action description in editing.
+ */
+ public int getDescriptionEditInputType() {
+ return mDescriptionEditInputType;
+ }
+
+ /**
+ * Returns InputType of action title not in editing.
+ * @return InputType of action title not in editing.
+ */
+ public int getInputType() {
+ return mInputType;
+ }
+
+ /**
+ * Returns InputType of action description not in editing.
+ * @return InputType of action description not in editing.
+ */
+ public int getDescriptionInputType() {
+ return mDescriptionInputType;
+ }
+
+ /**
* Returns whether this action is checked.
* @return true if the action is currently checked, false otherwise.
*/
@@ -249,13 +615,13 @@
}
/**
- * Returns the check set id this action is a part of. All actions in the
- * same list with the same check set id are considered linked. When one
- * of the actions within that set is selected, that action becomes
- * checked, while all the other actions become unchecked.
+ * Returns the check set id this action is a part of. All actions in the same list with the same
+ * check set id are considered linked. When one of the actions within that set is selected, that
+ * action becomes checked, while all the other actions become unchecked.
*
* @return an integer representing the check set this action is a part of, or
- * {@link #NO_CHECK_SET} if this action isn't a part of a check set.
+ * {@link #CHECKBOX_CHECK_SET_ID} if this is a checkbox, or {@link #NO_CHECK_SET} if
+ * this action is not a checkbox or radiobutton.
*/
public int getCheckSetId() {
return mCheckSetId;
@@ -287,6 +653,22 @@
}
/**
+ * Returns whether this action is focusable.
+ * @return true if the action is currently focusable, false otherwise.
+ */
+ public boolean isFocusable() {
+ return mFocusable;
+ }
+
+ /**
+ * Sets whether this action is focusable.
+ * @param focusable Whether this action should be focusable.
+ */
+ public void setFocusable(boolean focusable) {
+ mFocusable = focusable;
+ }
+
+ /**
* Returns whether this action will request further user input when selected, such as showing
* another GuidedStepFragment or launching a new activity. Configured during construction.
* @return true if the action will request further user input when selected, false otherwise.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionEditText.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionEditText.java
new file mode 100644
index 0000000..8e052fb
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionEditText.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.support.v17.leanback.widget.ImeKeyMonitor.ImeKeyListener;
+import android.util.AttributeSet;
+import android.widget.EditText;
+import android.view.KeyEvent;
+
+/**
+ * A custom EditText that satisfies the IME key monitoring requirements of GuidedStepFragment.
+ */
+public class GuidedActionEditText extends EditText implements ImeKeyMonitor {
+
+ private ImeKeyListener mKeyListener;
+
+ public GuidedActionEditText(Context ctx) {
+ this(ctx, null);
+ }
+
+ public GuidedActionEditText(Context ctx, AttributeSet attrs) {
+ this(ctx, attrs, android.R.attr.editTextStyle);
+ }
+
+ public GuidedActionEditText(Context ctx, AttributeSet attrs, int defStyleAttr) {
+ super(ctx, attrs, defStyleAttr);
+ }
+
+ @Override
+ public void setImeKeyListener(ImeKeyListener listener) {
+ mKeyListener = listener;
+ }
+
+ @Override
+ public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ boolean result = false;
+ if (mKeyListener != null) {
+ result = mKeyListener.onKeyPreIme(this, keyCode, event);
+ }
+ if (!result) {
+ result = super.onKeyPreIme(keyCode, event);
+ }
+ return result;
+ }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
index 15943b4..6e5d506 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
@@ -22,17 +22,21 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v17.leanback.R;
import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.animation.DecelerateInterpolator;
+import android.view.inputmethod.EditorInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -40,6 +44,8 @@
import android.view.ViewPropertyAnimator;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.widget.Checkable;
+import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
@@ -81,11 +87,15 @@
* </ul><p>
* These view IDs are allowed to be missing, in which case the corresponding views in {@link
* GuidedActionsStylist.ViewHolder} will be null.
+ * <p>
+ * In order to support editable actions, the view associated with guidedactions_item_title should
+ * be a subclass of {@link android.widget.EditText}, and should satisfy the {@link
+ * ImeKeyMonitor} interface.
*
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsEntryAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorShowAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorHideAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsContainerStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsListStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContainerStyle
@@ -95,24 +105,30 @@
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemTitleStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemDescriptionStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemChevronStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionCheckedAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUncheckedAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionPressedAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUnpressedAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionEnabledChevronAlpha
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDisabledChevronAlpha
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidth
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionContentWidthNoIcon
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMinLines
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMaxLines
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDescriptionMinLines
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionVerticalPadding
+ * @see android.R.styleable#Theme_listChoiceIndicatorSingle
+ * @see android.R.styleable#Theme_listChoiceIndicatorMultiple
* @see android.support.v17.leanback.app.GuidedStepFragment
* @see GuidedAction
*/
public class GuidedActionsStylist implements FragmentAnimationProvider {
/**
+ * Default viewType that associated with default layout Id for the action item.
+ * @see #getItemViewType(GuidedAction)
+ * @see #onProvideItemLayoutId(int)
+ * @see #onCreateViewHolder(ViewGroup, int)
+ */
+ public static final int VIEW_TYPE_DEFAULT = 0;
+
+ /**
* ViewHolder caches information about the action item layouts' subviews. Subclasses of {@link
* GuidedActionsStylist} may also wish to subclass this in order to add fields.
* @see GuidedAction
@@ -127,6 +143,8 @@
private ImageView mIconView;
private ImageView mCheckmarkView;
private ImageView mChevronView;
+ private boolean mInEditing;
+ private boolean mInEditingDescription;
/**
* Constructs an ViewHolder and caches the relevant subviews.
@@ -158,6 +176,14 @@
}
/**
+ * Convenience method to return an editable version of the title, if possible,
+ * or null if the title view isn't an EditText.
+ */
+ public EditText getEditableTitleView() {
+ return (mTitleView instanceof EditText) ? (EditText)mTitleView : null;
+ }
+
+ /**
* Returns the description view within this view holder's view.
*/
public TextView getDescriptionView() {
@@ -165,6 +191,14 @@
}
/**
+ * Convenience method to return an editable version of the description, if possible,
+ * or null if the description view isn't an EditText.
+ */
+ public EditText getEditableDescriptionView() {
+ return (mDescriptionView instanceof EditText) ? (EditText)mDescriptionView : null;
+ }
+
+ /**
* Returns the icon view within this view holder's view.
*/
public ImageView getIconView() {
@@ -185,19 +219,47 @@
return mChevronView;
}
+ /**
+ * Returns true if the TextView is in editing title or description, false otherwise.
+ */
+ public boolean isInEditing() {
+ return mInEditing;
+ }
+
+ /**
+ * Returns true if the TextView is in editing description, false otherwise.
+ */
+ public boolean isInEditingDescription() {
+ return mInEditingDescription;
+ }
+
+ public View getEditingView() {
+ if (mInEditing) {
+ return mInEditingDescription ? mDescriptionView : mTitleView;
+ } else {
+ return null;
+ }
+ }
}
private static String TAG = "GuidedActionsStylist";
- protected View mMainView;
- protected VerticalGridView mActionsGridView;
- protected View mSelectorView;
+ private ViewGroup mMainView;
+ private VerticalGridView mActionsGridView;
+ private View mBgView;
+ private View mSelectorView;
+ private View mContentView;
+ private boolean mButtonActions;
+
+ private Animator mSelectorAnimator;
// Cached values from resources
+ private float mEnabledTextAlpha;
+ private float mDisabledTextAlpha;
+ private float mEnabledDescriptionAlpha;
+ private float mDisabledDescriptionAlpha;
private float mEnabledChevronAlpha;
private float mDisabledChevronAlpha;
- private int mContentWidth;
- private int mContentWidthNoIcon;
private int mTitleMinLines;
private int mTitleMaxLines;
private int mDescriptionMinLines;
@@ -216,8 +278,17 @@
* @return The view to be added to the caller's view hierarchy.
*/
public View onCreateView(LayoutInflater inflater, ViewGroup container) {
- mMainView = inflater.inflate(onProvideLayoutId(), container, false);
+ mMainView = (ViewGroup) inflater.inflate(onProvideLayoutId(), container, false);
+ mContentView = mMainView.findViewById(R.id.guidedactions_content);
mSelectorView = mMainView.findViewById(R.id.guidedactions_selector);
+ mSelectorView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ updateSelectorView(false);
+ }
+ });
+ mBgView = mMainView.findViewById(R.id.guidedactions_list_background);
if (mMainView instanceof VerticalGridView) {
mActionsGridView = (VerticalGridView) mMainView;
} else {
@@ -229,32 +300,23 @@
mActionsGridView.setWindowAlignmentOffsetPercent(50f);
mActionsGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
if (mSelectorView != null) {
- mActionsGridView.setOnScrollListener(new
- SelectorAnimator(mSelectorView, mActionsGridView));
+ mActionsGridView.setOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ if (mSelectorView.getAlpha() != 1f) {
+ updateSelectorView(true);
+ }
+ }
+ }
+ });
}
}
- mActionsGridView.requestFocusFromTouch();
-
if (mSelectorView != null) {
// ALlow focus to move to other views
mActionsGridView.getViewTreeObserver().addOnGlobalFocusChangeListener(
- new ViewTreeObserver.OnGlobalFocusChangeListener() {
- private boolean mChildFocused;
-
- @Override
- public void onGlobalFocusChanged(View oldFocus, View newFocus) {
- View focusedChild = mActionsGridView.getFocusedChild();
- if (focusedChild == null) {
- mSelectorView.setVisibility(View.INVISIBLE);
- mChildFocused = false;
- } else if (!mChildFocused) {
- mChildFocused = true;
- mSelectorView.setVisibility(View.VISIBLE);
- updateSelectorView(focusedChild);
- }
- }
- });
+ mGlobalFocusChangeListener);
}
// Cache widths, chevron alpha values, max and min text lines, etc
@@ -262,8 +324,6 @@
TypedValue val = new TypedValue();
mEnabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionEnabledChevronAlpha);
mDisabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionDisabledChevronAlpha);
- mContentWidth = getDimension(ctx, val, R.attr.guidedActionContentWidth);
- mContentWidthNoIcon = getDimension(ctx, val, R.attr.guidedActionContentWidthNoIcon);
mTitleMinLines = getInteger(ctx, val, R.attr.guidedActionTitleMinLines);
mTitleMaxLines = getInteger(ctx, val, R.attr.guidedActionTitleMaxLines);
mDescriptionMinLines = getInteger(ctx, val, R.attr.guidedActionDescriptionMinLines);
@@ -271,10 +331,79 @@
mDisplayHeight = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getHeight();
+ mEnabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string
+ .lb_guidedactions_item_unselected_text_alpha));
+ mDisabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string
+ .lb_guidedactions_item_disabled_text_alpha));
+ mEnabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
+ .lb_guidedactions_item_unselected_description_text_alpha));
+ mDisabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
+ .lb_guidedactions_item_disabled_description_text_alpha));
return mMainView;
}
/**
+ * Default implementation turns on background for actions and applies different Ids to views so
+ * that GuidedStepFragment could run transitions against two action lists. The method is called
+ * by GuidedStepFragment, app may override this function when replacing default layout file
+ * provided by {@link #onProvideLayoutId()}
+ */
+ public void setAsButtonActions() {
+ mButtonActions = true;
+ mMainView.setId(R.id.guidedactions_root2);
+ ViewCompat.setTransitionName(mMainView, "guidedactions_root2");
+ if (mActionsGridView != null) {
+ mActionsGridView.setId(R.id.guidedactions_list2);
+ }
+ if (mSelectorView != null) {
+ mSelectorView.setId(R.id.guidedactions_selector2);
+ ViewCompat.setTransitionName(mSelectorView, "guidedactions_selector2");
+ }
+ if (mContentView != null) {
+ mContentView.setId(R.id.guidedactions_content2);
+ ViewCompat.setTransitionName(mContentView, "guidedactions_content2");
+ }
+ if (mBgView != null) {
+ mBgView.setId(R.id.guidedactions_list_background2);
+ ViewCompat.setTransitionName(mBgView, "guidedactions_list_background2");
+ mBgView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Returns true if {@link #setAsButtonActions()} was called, false otherwise.
+ * @return True if {@link #setAsButtonActions()} was called, false otherwise.
+ */
+ public boolean isButtonActions() {
+ return mButtonActions;
+ }
+
+ final ViewTreeObserver.OnGlobalFocusChangeListener mGlobalFocusChangeListener =
+ new ViewTreeObserver.OnGlobalFocusChangeListener() {
+
+ @Override
+ public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+ updateSelectorView(false);
+ }
+ };
+
+ /**
+ * Called when destroy the View created by GuidedActionsStylist.
+ */
+ public void onDestroyView() {
+ if (mSelectorView != null) {
+ mActionsGridView.getViewTreeObserver().removeOnGlobalFocusChangeListener(
+ mGlobalFocusChangeListener);
+ }
+ endSelectorAnimator();
+ mActionsGridView = null;
+ mSelectorView = null;
+ mContentView = null;
+ mBgView = null;
+ mMainView = null;
+ }
+
+ /**
* Returns the VerticalGridView that displays the list of GuidedActions.
* @return The VerticalGridView for this presenter.
*/
@@ -296,11 +425,25 @@
}
/**
+ * Return view type of action, each different type can have differently associated layout Id.
+ * Default implementation returns {@link #VIEW_TYPE_DEFAULT}.
+ * @param action The action object.
+ * @return View type that used in {@link #onProvideItemLayoutId(int)}.
+ */
+ public int getItemViewType(GuidedAction action) {
+ return VIEW_TYPE_DEFAULT;
+ }
+
+ /**
* Provides the resource ID of the layout defining the view for an individual guided actions.
* Subclasses may override to provide their own customized layouts. The base implementation
* returns {@link android.support.v17.leanback.R.layout#lb_guidedactions_item}. If overridden,
* the substituted layout should contain matching IDs for any views that should be managed by
- * the base class; this can be achieved by starting with a copy of the base layout file.
+ * the base class; this can be achieved by starting with a copy of the base layout file. Note
+ * that in order for the item to support editing, the title view should both subclass {@link
+ * android.widget.EditText} and implement {@link ImeKeyMonitor}; see {@link
+ * GuidedActionEditText}. To support different types of Layouts, override {@link
+ * #onProvideItemLayoutId(int)}.
* @return The resource ID of the layout to be inflated to define the view to display an
* individual GuidedAction.
*/
@@ -309,8 +452,31 @@
}
/**
+ * Provides the resource ID of the layout defining the view for an individual guided actions.
+ * Subclasses may override to provide their own customized layouts. The base implementation
+ * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions_item}. If overridden,
+ * the substituted layout should contain matching IDs for any views that should be managed by
+ * the base class; this can be achieved by starting with a copy of the base layout file. Note
+ * that in order for the item to support editing, the title view should both subclass {@link
+ * android.widget.EditText} and implement {@link ImeKeyMonitor}; see {@link
+ * GuidedActionEditText}.
+ * @param viewType View type returned by {@link #getItemViewType(GuidedAction)}
+ * @return The resource ID of the layout to be inflated to define the view to display an
+ * individual GuidedAction.
+ */
+ public int onProvideItemLayoutId(int viewType) {
+ if (viewType == VIEW_TYPE_DEFAULT) {
+ return onProvideItemLayoutId();
+ } else {
+ throw new RuntimeException("ViewType " + viewType +
+ " not supported in GuidedActionsStylist");
+ }
+ }
+
+ /**
* Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses
- * may choose to return a subclass of ViewHolder.
+ * may choose to return a subclass of ViewHolder. To support different view types, override
+ * {@link #onCreateViewHolder(ViewGroup, int)}
* <p>
* <i>Note: Should not actually add the created view to the parent; the caller will do
* this.</i>
@@ -324,6 +490,25 @@
}
/**
+ * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses
+ * may choose to return a subclass of ViewHolder.
+ * <p>
+ * <i>Note: Should not actually add the created view to the parent; the caller will do
+ * this.</i>
+ * @param parent The view group to be used as the parent of the new view.
+ * @param viewType The viewType returned by {@link #getItemViewType(GuidedAction)}
+ * @return The view to be added to the caller's view hierarchy.
+ */
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (viewType == VIEW_TYPE_DEFAULT) {
+ return onCreateViewHolder(parent);
+ }
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ View v = inflater.inflate(onProvideItemLayoutId(viewType), parent, false);
+ return new ViewHolder(v);
+ }
+
+ /**
* Binds a {@link ViewHolder} to a particular {@link GuidedAction}.
* @param vh The view holder to be associated with the given action.
* @param action The guided action to be displayed by the view holder's view.
@@ -333,31 +518,24 @@
if (vh.mTitleView != null) {
vh.mTitleView.setText(action.getTitle());
+ vh.mTitleView.setAlpha(action.isEnabled() ? mEnabledTextAlpha : mDisabledTextAlpha);
+ vh.mTitleView.setFocusable(action.isEditable());
}
if (vh.mDescriptionView != null) {
vh.mDescriptionView.setText(action.getDescription());
vh.mDescriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ?
View.GONE : View.VISIBLE);
+ vh.mDescriptionView.setAlpha(action.isEnabled() ? mEnabledDescriptionAlpha :
+ mDisabledDescriptionAlpha);
+ vh.mDescriptionView.setFocusable(action.isDescriptionEditable());
}
// Clients might want the check mark view to be gone entirely, in which case, ignore it.
- if (vh.mCheckmarkView != null && vh.mCheckmarkView.getVisibility() != View.GONE) {
- vh.mCheckmarkView.setVisibility(action.isChecked() ? View.VISIBLE : View.INVISIBLE);
- }
-
- if (vh.mContentView != null) {
- ViewGroup.LayoutParams contentLp = vh.mContentView.getLayoutParams();
- if (setIcon(vh.mIconView, action)) {
- contentLp.width = mContentWidth;
- } else {
- contentLp.width = mContentWidthNoIcon;
- }
- vh.mContentView.setLayoutParams(contentLp);
+ if (vh.mCheckmarkView != null) {
+ onBindCheckMarkView(vh, action);
}
if (vh.mChevronView != null) {
- vh.mChevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.INVISIBLE);
- vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha :
- mDisabledChevronAlpha);
+ onBindChevronView(vh, action);
}
if (action.hasMultilineDescription()) {
@@ -376,6 +554,89 @@
vh.mDescriptionView.setMaxLines(mDescriptionMinLines);
}
}
+ setEditingMode(vh, action, false);
+ if (action.isFocusable()) {
+ vh.view.setFocusable(true);
+ if (vh.view instanceof ViewGroup) {
+ ((ViewGroup) vh.view).setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+ }
+ } else {
+ vh.view.setFocusable(false);
+ if (vh.view instanceof ViewGroup) {
+ ((ViewGroup) vh.view).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ }
+ }
+ setupImeOptions(vh, action);
+ }
+
+ /**
+ * Called by {@link #onBindViewHolder(ViewHolder, GuidedAction)} to setup IME options. Default
+ * implementation assigns {@link EditorInfo#IME_ACTION_DONE}. Subclass may override.
+ * @param vh The view holder to be associated with the given action.
+ * @param action The guided action to be displayed by the view holder's view.
+ */
+ protected void setupImeOptions(ViewHolder vh, GuidedAction action) {
+ setupNextImeOptions(vh.getEditableTitleView());
+ setupNextImeOptions(vh.getEditableDescriptionView());
+ }
+
+ private void setupNextImeOptions(EditText edit) {
+ if (edit != null) {
+ edit.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+ }
+ }
+
+ public void setEditingMode(ViewHolder vh, GuidedAction action, boolean editing) {
+ if (editing != vh.mInEditing) {
+ vh.mInEditing = editing;
+ onEditingModeChange(vh, action, editing);
+ }
+ }
+
+ protected void onEditingModeChange(ViewHolder vh, GuidedAction action, boolean editing) {
+ TextView titleView = vh.getTitleView();
+ TextView descriptionView = vh.getDescriptionView();
+ if (editing) {
+ CharSequence editTitle = action.getEditTitle();
+ if (titleView != null && editTitle != null) {
+ titleView.setText(editTitle);
+ }
+ CharSequence editDescription = action.getEditDescription();
+ if (descriptionView != null && editDescription != null) {
+ descriptionView.setText(editDescription);
+ }
+ if (action.isDescriptionEditable()) {
+ if (descriptionView != null) {
+ descriptionView.setVisibility(View.VISIBLE);
+ descriptionView.setInputType(action.getDescriptionEditInputType());
+ }
+ vh.mInEditingDescription = true;
+ } else {
+ vh.mInEditingDescription = false;
+ if (titleView != null) {
+ titleView.setInputType(action.getEditInputType());
+ }
+ }
+ } else {
+ if (titleView != null) {
+ titleView.setText(action.getTitle());
+ }
+ if (descriptionView != null) {
+ descriptionView.setText(action.getDescription());
+ }
+ if (vh.mInEditingDescription) {
+ if (descriptionView != null) {
+ descriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ?
+ View.GONE : View.VISIBLE);
+ descriptionView.setInputType(action.getDescriptionInputType());
+ }
+ vh.mInEditingDescription = false;
+ } else {
+ if (titleView != null) {
+ titleView.setInputType(action.getInputType());
+ }
+ }
+ }
}
/**
@@ -402,31 +663,77 @@
}
/**
- * Animates the view holder's view (or subviews thereof) when the action has had its check
- * state changed.
+ * Resets the view holder's view to unpressed state.
+ * @param vh The view holder associated with the relevant action.
+ */
+ public void onAnimateItemPressedCancelled(ViewHolder vh) {
+ createAnimator(vh.view, R.attr.guidedActionUnpressedAnimation).end();
+ }
+
+ /**
+ * Animates the view holder's view (or subviews thereof) when the action has had its check state
+ * changed. Default implementation calls setChecked() if {@link ViewHolder#getCheckmarkView()}
+ * is instance of {@link Checkable}.
+ *
* @param vh The view holder associated with the relevant action.
* @param checked True if the action has become checked, false if it has become unchecked.
+ * @see #onBindCheckMarkView(ViewHolder, GuidedAction)
*/
public void onAnimateItemChecked(ViewHolder vh, boolean checked) {
- final View checkView = vh.mCheckmarkView;
- if (checkView != null) {
- if (checked) {
- checkView.setVisibility(View.VISIBLE);
- createAnimator(checkView, R.attr.guidedActionCheckedAnimation).start();
- } else {
- Animator animator = createAnimator(checkView,
- R.attr.guidedActionUncheckedAnimation);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- checkView.setVisibility(View.INVISIBLE);
- }
- });
- animator.start();
- }
+ if (vh.mCheckmarkView instanceof Checkable) {
+ ((Checkable) vh.mCheckmarkView).setChecked(checked);
}
}
+ /**
+ * Sets states of check mark view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}
+ * when action's checkset Id is other than {@link GuidedAction#NO_CHECK_SET}. Default
+ * implementation assigns drawable loaded from theme attribute
+ * {@link android.R.attr#listChoiceIndicatorMultiple} for checkbox or
+ * {@link android.R.attr#listChoiceIndicatorSingle} for radio button. Subclass rarely needs
+ * override the method, instead app can provide its own drawable that supports transition
+ * animations, change theme attributes {@link android.R.attr#listChoiceIndicatorMultiple} and
+ * {@link android.R.attr#listChoiceIndicatorSingle} in {android.support.v17.leanback.R.
+ * styleable#LeanbackGuidedStepTheme}.
+ *
+ * @param vh The view holder associated with the relevant action.
+ * @param action The GuidedAction object to bind to.
+ * @see #onAnimateItemChecked(ViewHolder, boolean)
+ */
+ public void onBindCheckMarkView(ViewHolder vh, GuidedAction action) {
+ if (action.getCheckSetId() != GuidedAction.NO_CHECK_SET) {
+ vh.mCheckmarkView.setVisibility(View.VISIBLE);
+ int attrId = action.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID ?
+ android.R.attr.listChoiceIndicatorMultiple :
+ android.R.attr.listChoiceIndicatorSingle;
+ final Context context = vh.mCheckmarkView.getContext();
+ Drawable drawable = null;
+ TypedValue typedValue = new TypedValue();
+ if (context.getTheme().resolveAttribute(attrId, typedValue, true)) {
+ drawable = ContextCompat.getDrawable(context, typedValue.resourceId);
+ }
+ vh.mCheckmarkView.setImageDrawable(drawable);
+ if (vh.mCheckmarkView instanceof Checkable) {
+ ((Checkable) vh.mCheckmarkView).setChecked(action.isChecked());
+ }
+ } else {
+ vh.mCheckmarkView.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Sets states of chevron view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}.
+ * Subclass may override.
+ *
+ * @param vh The view holder associated with the relevant action.
+ * @param action The GuidedAction object to bind to.
+ */
+ public void onBindChevronView(ViewHolder vh, GuidedAction action) {
+ vh.mChevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.GONE);
+ vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha :
+ mDisabledChevronAlpha);
+ }
+
/*
* ==========================================
* FragmentAnimationProvider overrides
@@ -437,50 +744,16 @@
* {@inheritDoc}
*/
@Override
- public void onActivityEnter(@NonNull List<Animator> animators) {
- animators.add(createAnimator(mMainView, R.attr.guidedActionsEntryAnimation));
+ public void onImeAppearing(@NonNull List<Animator> animators) {
+ animators.add(createAnimator(mContentView, R.attr.guidedStepImeAppearingAnimation));
}
/**
* {@inheritDoc}
*/
@Override
- public void onActivityExit(@NonNull List<Animator> animators) {}
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFragmentEnter(@NonNull List<Animator> animators) {
- animators.add(createAnimator(mActionsGridView, R.attr.guidedStepEntryAnimation));
- animators.add(createAnimator(mSelectorView, R.attr.guidedStepEntryAnimation));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFragmentExit(@NonNull List<Animator> animators) {
- animators.add(createAnimator(mActionsGridView, R.attr.guidedStepExitAnimation));
- animators.add(createAnimator(mSelectorView, R.attr.guidedStepExitAnimation));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFragmentReenter(@NonNull List<Animator> animators) {
- animators.add(createAnimator(mActionsGridView, R.attr.guidedStepReentryAnimation));
- animators.add(createAnimator(mSelectorView, R.attr.guidedStepReentryAnimation));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFragmentReturn(@NonNull List<Animator> animators) {
- animators.add(createAnimator(mActionsGridView, R.attr.guidedStepReturnAnimation));
- animators.add(createAnimator(mSelectorView, R.attr.guidedStepReturnAnimation));
+ public void onImeDisappearing(@NonNull List<Animator> animators) {
+ animators.add(createAnimator(mContentView, R.attr.guidedStepImeDisappearingAnimation));
}
/*
@@ -489,15 +762,6 @@
* ==========================================
*/
- private void updateSelectorView(View focusedChild) {
- // Display the selector view.
- int height = focusedChild.getHeight();
- LayoutParams lp = mSelectorView.getLayoutParams();
- lp.height = height;
- mSelectorView.setLayoutParams(lp);
- mSelectorView.setAlpha(1f);
- }
-
private float getFloat(Context ctx, TypedValue typedValue, int attrId) {
ctx.getTheme().resolveAttribute(attrId, typedValue, true);
// Android resources don't have a native float type, so we have to use strings.
@@ -551,96 +815,43 @@
return (int)(mDisplayHeight - 2*mVerticalPadding - 2*mTitleMaxLines*title.getLineHeight());
}
- /**
- * SelectorAnimator
- * Controls animation for selected item backgrounds
- * TODO: Move into focus animation override?
- */
- private static class SelectorAnimator extends RecyclerView.OnScrollListener {
-
- private final View mSelectorView;
- private final ViewGroup mParentView;
- private volatile boolean mFadedOut = true;
-
- SelectorAnimator(View selectorView, ViewGroup parentView) {
- mSelectorView = selectorView;
- mParentView = parentView;
+ private void endSelectorAnimator() {
+ if (mSelectorAnimator != null) {
+ mSelectorAnimator.end();
+ mSelectorAnimator = null;
}
+ }
- // We want to fade in the selector if we've stopped scrolling on it. If
- // we're scrolling, we want to ensure to dim the selector if we haven't
- // already. We dim the last highlighted view so that while a user is
- // scrolling, nothing is highlighted.
- @Override
- public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
- Animator animator = null;
- boolean fadingOut = false;
- if (newState == RecyclerView.SCROLL_STATE_IDLE) {
- // The selector starts with a height of 0. In order to scale up from
- // 0, we first need the set the height to 1 and scale from there.
- View focusedChild = mParentView.getFocusedChild();
- if (focusedChild != null) {
- int selectorHeight = mSelectorView.getHeight();
- float scaleY = (float) focusedChild.getHeight() / selectorHeight;
- AnimatorSet animators = (AnimatorSet)createAnimator(mSelectorView,
- R.attr.guidedActionsSelectorShowAnimation);
- if (mFadedOut) {
- // selector is completely faded out, so we can just scale before fading in.
- mSelectorView.setScaleY(scaleY);
- animator = animators.getChildAnimations().get(0);
- } else {
- // selector is not faded out, so we must animate the scale as we fade in.
- ((ObjectAnimator)animators.getChildAnimations().get(1))
- .setFloatValues(scaleY);
- animator = animators;
- }
- }
+ private void updateSelectorView(boolean animate) {
+ if (mActionsGridView == null || mSelectorView == null || mSelectorView.getHeight() <= 0) {
+ return;
+ }
+ final View focusedChild = mActionsGridView.getFocusedChild();
+ endSelectorAnimator();
+ if (focusedChild == null || !mActionsGridView.hasFocus()
+ || mActionsGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
+ if (animate) {
+ mSelectorAnimator = createAnimator(mSelectorView,
+ R.attr.guidedActionsSelectorHideAnimation);
+ mSelectorAnimator.start();
} else {
- animator = createAnimator(mSelectorView, R.attr.guidedActionsSelectorHideAnimation);
- fadingOut = true;
+ mSelectorView.setAlpha(0f);
}
- if (animator != null) {
- animator.addListener(new Listener(fadingOut));
- animator.start();
- }
- }
-
- /**
- * Sets {@link BaseScrollAdapterFragment#mFadedOut}
- * {@link BaseScrollAdapterFragment#mFadedOut} is true, iff
- * {@link BaseScrollAdapterFragment#mSelectorView} has an alpha of 0
- * (faded out). If false the view either has an alpha of 1 (visible) or
- * is in the process of animating.
- */
- private class Listener implements Animator.AnimatorListener {
- private boolean mFadingOut;
- private boolean mCanceled;
-
- public Listener(boolean fadingOut) {
- mFadingOut = fadingOut;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- if (!mFadingOut) {
- mFadedOut = false;
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mCanceled && mFadingOut) {
- mFadedOut = true;
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCanceled = true;
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
+ } else {
+ final float scaleY = (float) focusedChild.getHeight() / mSelectorView.getHeight();
+ Rect r = new Rect(0, 0, focusedChild.getWidth(), focusedChild.getHeight());
+ mMainView.offsetDescendantRectToMyCoords(focusedChild, r);
+ mMainView.offsetRectIntoDescendantCoords(mSelectorView, r);
+ mSelectorView.setTranslationY(r.exactCenterY() - mSelectorView.getHeight() * 0.5f);
+ if (animate) {
+ mSelectorAnimator = createAnimator(mSelectorView,
+ R.attr.guidedActionsSelectorShowAnimation);
+ ((ObjectAnimator) ((AnimatorSet) mSelectorAnimator).getChildAnimations().get(1))
+ .setFloatValues(scaleY);
+ mSelectorAnimator.start();
+ } else {
+ mSelectorView.setAlpha(1f);
+ mSelectorView.setScaleY(scaleY);
}
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
index 2c1c7e0..08eb617 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
@@ -18,60 +18,288 @@
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
-import android.text.TextUtils;
import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
+import android.widget.RelativeLayout;
import android.widget.TextView;
/**
- * A subclass of {@link BaseCardView} with an {@link ImageView} as its main region.
+ * A subclass of {@link BaseCardView} with an {@link ImageView} as its main
+ * region. The {@link ImageCardView} is highly customizable and can be used for
+ * various use-cases by adjusting the ImageViewCard's type to any combination of
+ * Title, Content, Badge or ImageOnly.
+ * <p>
+ * <h3>Styling</h3> There are three different ways to style the ImageCardView.
+ * <br>
+ * No matter what way you use, all your styles applied to an ImageCardView have
+ * to extend the style {@link R.style#Widget_Leanback_ImageCardViewStyle}.
+ * <p>
+ * <u>Example:</u><br>
+ *
+ * <pre>
+ * {@code <style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
+ <item name="cardBackground">#F0F</item>
+ <item name="lbImageCardViewType">Title|Content</item>
+ <item name="lbImageCardViewInfoAreaStyle">@style/ImageCardViewColoredInfoArea</item>
+ <item name="lbImageCardViewTitleStyle">@style/ImageCardViewColoredTitle</item>
+ </style>}
+ * </pre>
+ * <p>
+ * The first possibility is to set a custom Style in the Leanback Theme's
+ * attribute <code>imageCardViewStyle</code>. The style set here, is the default
+ * style for all ImageCardViews. The other two possibilities allow you to style
+ * a particular ImageCardView. This is usefull if you want to create multiple
+ * types of cards. E.g. you might want to display a card with only a title and
+ * another one with title and content. Thus you need to define two different
+ * <code>ImageCardViewStyles</code> and apply them to the ImageCardViews. You
+ * can do this by either using a the {@link #ImageCardView(Context, int)}
+ * constructor and passing a style as second argument or by setting the style in
+ * a layout.
+ * <p>
+ * <u>Example (using constructor):</u><br>
+ *
+ * <pre>
+ * {@code
+ * new ImageCardView(context, R.style.CustomImageCardViewStyle);
+ * }
+ * </pre>
+ *
+ * <u>Example (using style attribute in a layout):</u><br>
+ *
+ * <pre>
+ * {@code <android.support.v17.leanback.widget.ImageCardView
+ android:id="@+id/imageCardView"
+ style="@style/CustomImageCardViewStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ </android.support.v17.leanback.widget.ImageCardView>}
+ * </pre>
+ * <p>
+ * You can style all ImageCardView's components such as the title, content,
+ * badge, infoArea and the image itself by extending the corresponding style and
+ * overriding the specific attribute in your custom
+ * <code>ImageCardViewStyle</code>.
+ *
+ * <h3>Components</h3> The ImageCardView contains three components which can be
+ * combined in any combination:
+ * <ul>
+ * <li>Title: The card's title</li>
+ * <li>Content: A short description</li>
+ * <li>Badge: An icon which can be displayed on the right or left side of the
+ * card.</li>
+ * </ul>
+ * In order to choose the components you want to use in your ImageCardView, you
+ * have to specify them in the <code>lbImageCardViewType</code> attribute of
+ * your custom <code>ImageCardViewStyle</code>. You can combine the following
+ * values: <code>Title, Content, IconOnRight, IconOnLeft, ImageOnly</code>.
+ * <p>
+ * <u>Examples:</u><br>
+ *
+ * <pre>
+ * {@code <style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
+ ...
+ <item name="lbImageCardViewType">Title|Content|IconOnLeft</item>
+ ...
+ </style>}
+ * </pre>
+ *
+ * <pre>
+ * {@code <style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
+ ...
+ <item name="lbImageCardViewType">ImageOnly</item>
+ ...
+ </style>}
+ * </pre>
+ *
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackTheme_imageCardViewStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewType
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewTitleStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewContentStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewBadgeStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewImageStyle
+ * @attr ref android.support.v17.leanback.R.styleable#lbImageCardView_lbImageCardViewInfoAreaStyle
*/
public class ImageCardView extends BaseCardView {
+ public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0;
+ public static final int CARD_TYPE_FLAG_TITLE = 1;
+ public static final int CARD_TYPE_FLAG_CONTENT = 2;
+ public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4;
+ public static final int CARD_TYPE_FLAG_ICON_LEFT = 8;
+
private ImageView mImageView;
- private View mInfoArea;
+ private ViewGroup mInfoArea;
private TextView mTitleView;
private TextView mContentView;
private ImageView mBadgeImage;
private boolean mAttachedToWindow;
+ /**
+ * Create an ImageCardView using a given style for customization.
+ *
+ * @param context
+ * The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param styleResId
+ * The resourceId of the style you want to apply to the
+ * ImageCardView. The style has to extend
+ * {@link R.style#Widget_Leanback_ImageCardViewStyle}.
+ */
+ public ImageCardView(Context context, int styleResId) {
+ super(new ContextThemeWrapper(context, styleResId), null, 0);
+ buildImageCardView(styleResId);
+ }
+
+ /**
+ * @see #View(Context, AttributeSet, int)
+ */
+ public ImageCardView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(getStyledContext(context, attrs, defStyleAttr), attrs, defStyleAttr);
+ buildImageCardView(getImageCardViewStyle(context, attrs, defStyleAttr));
+ }
+
+ private void buildImageCardView(int styleResId) {
+ // Make sure the ImageCardView is focusable.
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ inflater.inflate(R.layout.lb_image_card_view, this);
+ TypedArray cardAttrs = getContext().obtainStyledAttributes(styleResId, R.styleable.lbImageCardView);
+ int cardType = cardAttrs.getInt(R.styleable.lbImageCardView_lbImageCardViewType, CARD_TYPE_FLAG_IMAGE_ONLY);
+ boolean hasImageOnly = cardType == CARD_TYPE_FLAG_IMAGE_ONLY;
+ boolean hasTitle = (cardType & CARD_TYPE_FLAG_TITLE) == CARD_TYPE_FLAG_TITLE;
+ boolean hasContent = (cardType & CARD_TYPE_FLAG_CONTENT) == CARD_TYPE_FLAG_CONTENT;
+ boolean hasIconRight = (cardType & CARD_TYPE_FLAG_ICON_RIGHT) == CARD_TYPE_FLAG_ICON_RIGHT;
+ boolean hasIconLeft = !hasIconRight && (cardType & CARD_TYPE_FLAG_ICON_LEFT) == CARD_TYPE_FLAG_ICON_LEFT;
+
+ mImageView = (ImageView) findViewById(R.id.main_image);
+ if (mImageView.getDrawable() == null) {
+ mImageView.setVisibility(View.INVISIBLE);
+ }
+
+ mInfoArea = (ViewGroup) findViewById(R.id.info_field);
+ if (hasImageOnly) {
+ removeView(mInfoArea);
+ cardAttrs.recycle();
+ return;
+ }
+ // Create children
+ if (hasTitle) {
+ mTitleView = (TextView) inflater.inflate(R.layout.lb_image_card_view_themed_title, mInfoArea, false);
+ mInfoArea.addView(mTitleView);
+ }
+
+ if (hasContent) {
+ mContentView = (TextView) inflater.inflate(R.layout.lb_image_card_view_themed_content, mInfoArea, false);
+ mInfoArea.addView(mContentView);
+ }
+
+ if (hasIconRight || hasIconLeft) {
+ int layoutId = R.layout.lb_image_card_view_themed_badge_right;
+ if (hasIconLeft) {
+ layoutId = R.layout.lb_image_card_view_themed_badge_left;
+ }
+ mBadgeImage = (ImageView) inflater.inflate(layoutId, mInfoArea, false);
+ mInfoArea.addView(mBadgeImage);
+ }
+
+ // Set up LayoutParams for children
+ if (hasTitle && !hasContent && mBadgeImage != null) {
+ RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams) mTitleView
+ .getLayoutParams();
+ // Adjust title TextView if there is an icon but no content
+ if (hasIconLeft) {
+ relativeLayoutParams.addRule(RelativeLayout.END_OF, mBadgeImage.getId());
+ } else {
+ relativeLayoutParams.addRule(RelativeLayout.START_OF, mBadgeImage.getId());
+ }
+ mTitleView.setLayoutParams(relativeLayoutParams);
+ }
+
+ // Set up LayoutParams for children
+ if (hasContent) {
+ RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams) mContentView
+ .getLayoutParams();
+ if (!hasTitle) {
+ relativeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ }
+ // Adjust content TextView if icon is on the left
+ if (hasIconLeft) {
+ relativeLayoutParams.removeRule(RelativeLayout.START_OF);
+ relativeLayoutParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
+ relativeLayoutParams.addRule(RelativeLayout.END_OF, mBadgeImage.getId());
+ }
+ mContentView.setLayoutParams(relativeLayoutParams);
+ }
+
+ if (mBadgeImage != null) {
+ RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams) mBadgeImage
+ .getLayoutParams();
+ if (hasContent) {
+ relativeLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, mContentView.getId());
+ } else if (hasTitle) {
+ relativeLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, mTitleView.getId());
+ }
+ mBadgeImage.setLayoutParams(relativeLayoutParams);
+ }
+
+ // Backward compatibility: Newly created ImageCardViews should change
+ // the InfoArea's background color in XML using the corresponding style.
+ // However, since older implementations might make use of the
+ // 'infoAreaBackground' attribute, we have to make sure to support it.
+ // If the user has set a specific value here, it will differ from null.
+ // In this case, we do want to override the value set in the style.
+ Drawable background = cardAttrs.getDrawable(R.styleable.lbImageCardView_infoAreaBackground);
+ if (null != background) {
+ setInfoAreaBackground(background);
+ }
+ // Backward compatibility: There has to be an icon in the default
+ // version. If there is one, we have to set it's visibility to 'GONE'.
+ // Disabling 'adjustIconVisibility' allows the user to set the icon's
+ // visibility state in XML rather than code.
+ if (mBadgeImage != null && mBadgeImage.getDrawable() == null) {
+ mBadgeImage.setVisibility(View.GONE);
+ }
+ cardAttrs.recycle();
+ }
+
+ private static Context getStyledContext(Context context, AttributeSet attrs, int defStyleAttr) {
+ int style = getImageCardViewStyle(context, attrs, defStyleAttr);
+ return new ContextThemeWrapper(context, style);
+ }
+
+ private static int getImageCardViewStyle(Context context, AttributeSet attrs, int defStyleAttr) {
+ // Read style attribute defined in XML layout.
+ int style = null == attrs ? 0 : attrs.getStyleAttribute();
+ if (0 == style) {
+ // Not found? Read global ImageCardView style from Theme attribute.
+ TypedArray styledAttrs = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
+ style = styledAttrs.getResourceId(R.styleable.LeanbackTheme_imageCardViewStyle, 0);
+ styledAttrs.recycle();
+ }
+ return style;
+ }
+
+ /**
+ * @see #View(Context)
+ */
public ImageCardView(Context context) {
this(context, null);
}
+ /**
+ * @see #View(Context, AttributeSet)
+ */
public ImageCardView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.imageCardViewStyle);
}
- public ImageCardView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- LayoutInflater inflater = LayoutInflater.from(context);
- View v = inflater.inflate(R.layout.lb_image_card_view, this);
-
- mImageView = (ImageView) v.findViewById(R.id.main_image);
- mImageView.setVisibility(View.INVISIBLE);
- mInfoArea = v.findViewById(R.id.info_field);
- mTitleView = (TextView) v.findViewById(R.id.title_text);
- mContentView = (TextView) v.findViewById(R.id.content_text);
- mBadgeImage = (ImageView) v.findViewById(R.id.extra_badge);
-
- if (mInfoArea != null) {
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbImageCardView,
- defStyle, 0);
- try {
- setInfoAreaBackground(
- a.getDrawable(R.styleable.lbImageCardView_infoAreaBackground));
- } finally {
- a.recycle();
- }
- }
- }
-
/**
* Returns the main image view.
*/
@@ -170,7 +398,7 @@
/**
* Sets the info area background color.
- */
+ */
public void setInfoAreaBackgroundColor(@ColorInt int color) {
if (mInfoArea != null) {
mInfoArea.setBackgroundColor(color);
@@ -184,7 +412,6 @@
if (mTitleView == null) {
return;
}
-
mTitleView.setText(text);
}
@@ -206,7 +433,6 @@
if (mContentView == null) {
return;
}
-
mContentView.setText(text);
}
@@ -229,7 +455,7 @@
return;
}
mBadgeImage.setImageDrawable(drawable);
- if (drawable != null && mContentView!= null && mContentView.getVisibility() != GONE) {
+ if (drawable != null) {
mBadgeImage.setVisibility(View.VISIBLE);
} else {
mBadgeImage.setVisibility(View.GONE);
@@ -250,8 +476,8 @@
private void fadeIn() {
mImageView.setAlpha(0f);
if (mAttachedToWindow) {
- mImageView.animate().alpha(1f).setDuration(mImageView.getResources().getInteger(
- android.R.integer.config_shortAnimTime));
+ mImageView.animate().alpha(1f)
+ .setDuration(mImageView.getResources().getInteger(android.R.integer.config_shortAnimTime));
}
}
@@ -276,4 +502,5 @@
mImageView.setAlpha(1f);
super.onDetachedFromWindow();
}
+
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ImeKeyMonitor.java b/v17/leanback/src/android/support/v17/leanback/widget/ImeKeyMonitor.java
new file mode 100644
index 0000000..4691ad2
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ImeKeyMonitor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import android.widget.EditText;
+import android.view.KeyEvent;
+
+/**
+ * Interface for an EditText subclass that can delegate calls to onKeyPreIme up to a registered
+ * listener.
+ * <p>
+ * Used in editable actions within {@link android.support.v17.leanback.app.GuidedStepFragment} to
+ * allow for custom back key handling. Specifically, this is used to implement the behavior that
+ * dismissing the IME also clears edit text focus. Clients who need to supply custom layouts for
+ * {@link GuidedActionsStylist} with their own EditText classes should satisfy this interface in
+ * order to inherit this behavior.
+ */
+public interface ImeKeyMonitor {
+
+ /**
+ * Listener interface for key events intercepted pre-IME by edit text objects.
+ */
+ public interface ImeKeyListener {
+ /**
+ * Callback invoked from EditText's onKeyPreIme method override. Returning true tells the
+ * caller that the key event is handled and should not be propagated.
+ */
+ public abstract boolean onKeyPreIme(EditText editText, int keyCode, KeyEvent event);
+ }
+
+ /**
+ * Set the listener for this edit text object. The listener's onKeyPreIme method will be
+ * invoked from the host edit text's onKeyPreIme method.
+ */
+ public void setImeKeyListener(ImeKeyListener listener);
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
index 8e3aea3..57e8bfe 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
@@ -177,11 +177,15 @@
* Sets the {@link ObjectAdapter}.
*/
public void setAdapter(ObjectAdapter adapter) {
+ if (adapter == mAdapter) {
+ return;
+ }
if (mAdapter != null) {
mAdapter.unregisterObserver(mDataObserver);
}
mAdapter = adapter;
if (mAdapter == null) {
+ notifyDataSetChanged();
return;
}
@@ -189,6 +193,7 @@
if (hasStableIds() != mAdapter.hasStableIds()) {
setHasStableIds(mAdapter.hasStableIds());
}
+ notifyDataSetChanged();
}
/**
@@ -233,7 +238,7 @@
@Override
public int getItemCount() {
- return mAdapter.size();
+ return mAdapter != null ? mAdapter.size() : 0;
}
@Override
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
new file mode 100644
index 0000000..19e6e9a
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+/**
+ * A wrapper class working with {@link ItemBridgeAdapter} to wrap item view in a
+ * {@link ShadowOverlayContainer}. The ShadowOverlayContainer is created from conditions
+ * of {@link ShadowOverlayHelper}.
+ */
+public class ItemBridgeAdapterShadowOverlayWrapper extends ItemBridgeAdapter.Wrapper {
+
+ private final ShadowOverlayHelper mHelper;
+
+ public ItemBridgeAdapterShadowOverlayWrapper(ShadowOverlayHelper helper) {
+ mHelper = helper;
+ }
+
+ @Override
+ public View createWrapper(View root) {
+ Context context = root.getContext();
+ ShadowOverlayContainer wrapper = mHelper.createShadowOverlayContainer(context);
+ return wrapper;
+ }
+ @Override
+ public void wrap(View wrapper, View wrapped) {
+ ((ShadowOverlayContainer) wrapper).wrap(wrapped);
+ }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
index 9e588eb..5540f78 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
@@ -15,8 +15,10 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.support.v17.leanback.R;
import android.support.v17.leanback.system.Settings;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -96,6 +98,16 @@
}
@Override
+ protected void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) {
+ if (viewHolder.itemView instanceof ViewGroup) {
+ TransitionHelper.setTransitionGroup((ViewGroup) viewHolder.itemView, true);
+ }
+ if (mShadowOverlayHelper != null) {
+ mShadowOverlayHelper.onViewCreated(viewHolder.itemView);
+ }
+ }
+
+ @Override
public void onBind(final ItemBridgeAdapter.ViewHolder viewHolder) {
// Only when having an OnItemClickListner, we will attach the OnClickListener.
if (mRowViewHolder.getOnItemViewClickedListener() != null) {
@@ -122,9 +134,9 @@
@Override
public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
- if (needsDefaultListSelectEffect()) {
+ if (mShadowOverlayHelper != null && mShadowOverlayHelper.needsOverlay()) {
int dimmedColor = mRowViewHolder.mColorDimmer.getPaint().getColor();
- ((ShadowOverlayContainer) viewHolder.itemView).setOverlayColor(dimmedColor);
+ mShadowOverlayHelper.setOverlayColor(viewHolder.itemView, dimmedColor);
}
mRowViewHolder.syncActivatedStatus(viewHolder.itemView);
}
@@ -144,7 +156,10 @@
private boolean mShadowEnabled = true;
private int mBrowseRowsFadingEdgeLength = -1;
private boolean mRoundedCornersEnabled = true;
+ private boolean mKeepChildForeground = true;
private HashMap<Presenter, Integer> mRecycledPoolSize = new HashMap<Presenter, Integer>();
+ private ShadowOverlayHelper mShadowOverlayHelper;
+ private ItemBridgeAdapter.Wrapper mShadowOverlayWrapper;
private static int sSelectedRowTopPadding;
private static int sExpandedSelectedRowTopPadding;
@@ -253,44 +268,34 @@
return mUseFocusDimmer;
}
- private ItemBridgeAdapter.Wrapper mCardWrapper = new ItemBridgeAdapter.Wrapper() {
- @Override
- public View createWrapper(View root) {
- ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext());
- wrapper.setLayoutParams(
- new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- if (isUsingZOrder(root.getContext())) {
- wrapper.useDynamicShadow();
- } else {
- wrapper.useStaticShadow();
- }
- wrapper.initialize(needsDefaultShadow(),
- needsDefaultListSelectEffect(),
- areChildRoundedCornersEnabled());
- return wrapper;
- }
- @Override
- public void wrap(View wrapper, View wrapped) {
- ((ShadowOverlayContainer) wrapper).wrap(wrapped);
- }
- };
-
@Override
protected void initializeRowViewHolder(RowPresenter.ViewHolder holder) {
super.initializeRowViewHolder(holder);
final ViewHolder rowViewHolder = (ViewHolder) holder;
+ Context context = holder.view.getContext();
+ if (mShadowOverlayHelper == null) {
+ mShadowOverlayHelper = new ShadowOverlayHelper.Builder()
+ .needsOverlay(needsDefaultListSelectEffect())
+ .needsShadow(needsDefaultShadow())
+ .needsRoundedCorner(areChildRoundedCornersEnabled())
+ .preferZOrder(isUsingZOrder(context))
+ .keepForegroundDrawable(mKeepChildForeground)
+ .options(createShadowOverlayOptions())
+ .build(context);
+ if (mShadowOverlayHelper.needsWrapper()) {
+ mShadowOverlayWrapper = new ItemBridgeAdapterShadowOverlayWrapper(
+ mShadowOverlayHelper);
+ }
+ }
rowViewHolder.mItemBridgeAdapter = new ListRowPresenterItemBridgeAdapter(rowViewHolder);
- if (needsDefaultListSelectEffect() || needsDefaultShadow()
- || areChildRoundedCornersEnabled()) {
- rowViewHolder.mItemBridgeAdapter.setWrapper(mCardWrapper);
- }
- if (needsDefaultShadow()) {
- ShadowOverlayContainer.prepareParentForShadow(rowViewHolder.mGridView);
- }
+ // set wrapper if needed
+ rowViewHolder.mItemBridgeAdapter.setWrapper(mShadowOverlayWrapper);
+ mShadowOverlayHelper.prepareParentForShadow(rowViewHolder.mGridView);
+
FocusHighlightHelper.setupBrowseItemFocusHighlight(rowViewHolder.mItemBridgeAdapter,
mFocusZoomFactor, mUseFocusDimmer);
- rowViewHolder.mGridView.setFocusDrawingOrderEnabled(
- !isUsingZOrder(rowViewHolder.getGridView().getContext()));
+ rowViewHolder.mGridView.setFocusDrawingOrderEnabled(mShadowOverlayHelper.getShadowType()
+ == ShadowOverlayHelper.SHADOW_STATIC);
rowViewHolder.mGridView.setOnChildSelectedListener(
new OnChildSelectedListener() {
@Override
@@ -545,7 +550,7 @@
* Subclass may return false to disable.
*/
public boolean isUsingDefaultShadow() {
- return ShadowOverlayContainer.supportsShadow();
+ return ShadowOverlayHelper.supportsShadow();
}
/**
@@ -554,8 +559,7 @@
* and does not use Z-shadow on SDK >= L, it should override isUsingZOrder() return false.
*/
public boolean isUsingZOrder(Context context) {
- return ShadowOverlayContainer.supportsDynamicShadow() &&
- !Settings.getInstance(context).preferStaticShadows();
+ return !Settings.getInstance(context).preferStaticShadows();
}
/**
@@ -595,9 +599,41 @@
return isUsingDefaultShadow() && getShadowEnabled();
}
- @Override
- public boolean canDrawOutOfBounds() {
- return needsDefaultShadow();
+ /**
+ * When ListRowPresenter applies overlay color on the child, it may change child's foreground
+ * Drawable. If application uses child's foreground for other purposes such as ripple effect,
+ * it needs tell ListRowPresenter to keep the child's foreground. The default value is true.
+ *
+ * @param keep true if keep foreground of child of this row, false ListRowPresenter might change
+ * the foreground of the child.
+ */
+ public final void setKeepChildForeground(boolean keep) {
+ mKeepChildForeground = keep;
+ }
+
+ /**
+ * Returns true if keeps foreground of child of this row, false otherwise. When
+ * ListRowPresenter applies overlay color on the child, it may change child's foreground
+ * Drawable. If application uses child's foreground for other purposes such as ripple effect,
+ * it needs tell ListRowPresenter to keep the child's foreground. The default value is true.
+ *
+ * @return true if keeps foreground of child of this row, false otherwise.
+ */
+ public final boolean isKeepChildForeground() {
+ return mKeepChildForeground;
+ }
+
+ /**
+ * Create ShadowOverlayHelper Options. Subclass may override.
+ * e.g.
+ * <code>
+ * return new ShadowOverlayHelper.Options().roundedCornerRadius(10);
+ * </code>
+ *
+ * @return The options to be used for shadow, overlay and rouded corner.
+ */
+ protected ShadowOverlayHelper.Options createShadowOverlayOptions() {
+ return ShadowOverlayHelper.Options.DEFAULT;
}
/**
@@ -615,12 +651,11 @@
@Override
protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) {
super.onSelectLevelChanged(holder);
- if (needsDefaultListSelectEffect()) {
+ if (mShadowOverlayHelper != null && mShadowOverlayHelper.needsOverlay()) {
ViewHolder vh = (ViewHolder) holder;
int dimmedColor = vh.mColorDimmer.getPaint().getColor();
for (int i = 0, count = vh.mGridView.getChildCount(); i < count; i++) {
- ShadowOverlayContainer wrapper = (ShadowOverlayContainer) vh.mGridView.getChildAt(i);
- wrapper.setOverlayColor(dimmedColor);
+ mShadowOverlayHelper.setOverlayColor(vh.mGridView.getChildAt(i), dimmedColor);
}
if (vh.mGridView.getFadingLeftEdge()) {
vh.mGridView.invalidate();
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
index f1db00b..17225f8 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
@@ -58,7 +58,7 @@
final TextView mCurrentTime;
final TextView mTotalTime;
final ProgressBar mProgressBar;
- int mCurrentTimeInSeconds;
+ int mCurrentTimeInSeconds = -1;
StringBuilder mTotalTimeStringBuilder = new StringBuilder();
StringBuilder mCurrentTimeStringBuilder = new StringBuilder();
int mCurrentTimeMarginStart;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java
index e1c5979..35a5b67 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java
@@ -13,8 +13,7 @@
*/
package android.support.v17.leanback.widget;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
+import android.support.v17.leanback.R;
import android.os.Build;
import android.view.View;
@@ -24,7 +23,7 @@
final class RoundedRectHelper {
private final static RoundedRectHelper sInstance = new RoundedRectHelper();
- private Impl mImpl;
+ private final Impl mImpl;
/**
* Returns an instance of the helper.
@@ -33,15 +32,27 @@
return sInstance;
}
+ public static boolean supportsRoundedCorner() {
+ return Build.VERSION.SDK_INT >= 21;
+ }
+
+ /**
+ * Sets or removes a rounded rectangle outline on the given view.
+ */
+ public void setClipToRoundedOutline(View view, boolean clip, int radius) {
+ mImpl.setClipToRoundedOutline(view, clip, radius);
+ }
+
/**
* Sets or removes a rounded rectangle outline on the given view.
*/
public void setClipToRoundedOutline(View view, boolean clip) {
- mImpl.setClipToRoundedOutline(view, clip);
+ mImpl.setClipToRoundedOutline(view, clip, view.getResources().getDimensionPixelSize(
+ R.dimen.lb_rounded_rect_corner_radius));
}
static interface Impl {
- public void setClipToRoundedOutline(View view, boolean clip);
+ public void setClipToRoundedOutline(View view, boolean clip, int radius);
}
/**
@@ -49,7 +60,7 @@
*/
private static final class StubImpl implements Impl {
@Override
- public void setClipToRoundedOutline(View view, boolean clip) {
+ public void setClipToRoundedOutline(View view, boolean clip, int radius) {
// Not supported
}
}
@@ -59,13 +70,13 @@
*/
private static final class Api21Impl implements Impl {
@Override
- public void setClipToRoundedOutline(View view, boolean clip) {
- RoundedRectHelperApi21.setClipToRoundedOutline(view, clip);
+ public void setClipToRoundedOutline(View view, boolean clip, int radius) {
+ RoundedRectHelperApi21.setClipToRoundedOutline(view, clip, radius);
}
}
private RoundedRectHelper() {
- if (Build.VERSION.SDK_INT >= 21) {
+ if (supportsRoundedCorner()) {
mImpl = new Api21Impl();
} else {
mImpl = new StubImpl();
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
index 4f078f1..cb1f2ac7 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
@@ -565,13 +565,6 @@
return mHeaderPresenter != null || needsDefaultSelectEffect();
}
- /**
- * Returns true if the Row view can draw outside its bounds.
- */
- public boolean canDrawOutOfBounds() {
- return false;
- }
-
@Override
public final void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
onBindRowViewHolder(getRowViewHolder(viewHolder), item);
@@ -642,12 +635,16 @@
* Changes the visibility of views. The entrance transition will be run against the views that
* change visibilities. A subclass may override and begin with calling
* super.setEntranceTransitionState(). This method is called by the fragment,
- * it should not call it directly by the application.
+ * it should not be called directly by the application.
+ *
+ * @param holder The ViewHolder of the row.
+ * @param afterEntrance true if children of row participating in entrance transition
+ * should be set to visible, false otherwise.
*/
- public void setEntranceTransitionState(ViewHolder holder, boolean afterTransition) {
+ public void setEntranceTransitionState(ViewHolder holder, boolean afterEntrance) {
if (holder.mHeaderViewHolder != null &&
holder.mHeaderViewHolder.view.getVisibility() != View.GONE) {
- holder.mHeaderViewHolder.view.setVisibility(afterTransition ?
+ holder.mHeaderViewHolder.view.setVisibility(afterEntrance ?
View.VISIBLE : View.INVISIBLE);
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
index acdebcb..1c3835f 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
@@ -406,15 +406,23 @@
* @param completions list of completions shown in the IME, can be null or empty to clear them
*/
public void displayCompletions(List<String> completions) {
- List<CompletionInfo> infos = new ArrayList<CompletionInfo>();
+ List<CompletionInfo> infos = new ArrayList<>();
if (null != completions) {
for (String completion : completions) {
infos.add(new CompletionInfo(infos.size(), infos.size(), completion));
}
}
+ CompletionInfo[] array = new CompletionInfo[infos.size()];
+ displayCompletions(infos.toArray(array));
+ }
- mInputMethodManager.displayCompletions(mSearchTextEditor,
- infos.toArray(new CompletionInfo[] {}));
+ /**
+ * Updates the completion list shown by the IME
+ *
+ * @param completions list of completions shown in the IME, can be null or empty to clear them
+ */
+ public void displayCompletions(CompletionInfo[] completions) {
+ mInputMethodManager.displayCompletions(mSearchTextEditor, completions);
}
/**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java
index be70575..aec9673 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java
@@ -14,7 +14,6 @@
package android.support.v17.leanback.widget;
import android.os.Build;
-import android.view.ViewGroup;
import android.view.View;
@@ -32,7 +31,7 @@
*/
static interface ShadowHelperVersionImpl {
public Object addDynamicShadow(
- ViewGroup shadowContainer, float unfocusedZ, float focusedZ, boolean roundedCorners);
+ View shadowContainer, float unfocusedZ, float focusedZ, int roundedCornerRadius);
public void setZ(View view, float z);
public void setShadowFocusLevel(Object impl, float level);
}
@@ -43,7 +42,7 @@
private static final class ShadowHelperStubImpl implements ShadowHelperVersionImpl {
@Override
public Object addDynamicShadow(
- ViewGroup shadowContainer, float focusedZ, float unfocusedZ, boolean roundedCorners) {
+ View shadowContainer, float focusedZ, float unfocusedZ, int roundedCornerRadius) {
// do nothing
return null;
}
@@ -65,9 +64,9 @@
private static final class ShadowHelperApi21Impl implements ShadowHelperVersionImpl {
@Override
public Object addDynamicShadow(
- ViewGroup shadowContainer, float unfocusedZ, float focusedZ, boolean roundedCorners) {
+ View shadowContainer, float unfocusedZ, float focusedZ, int roundedCornerRadius) {
return ShadowHelperApi21.addDynamicShadow(
- shadowContainer, unfocusedZ, focusedZ, roundedCorners);
+ shadowContainer, unfocusedZ, focusedZ, roundedCornerRadius);
}
@Override
@@ -102,8 +101,8 @@
}
public Object addDynamicShadow(
- ViewGroup shadowContainer, float unfocusedZ, float focusedZ, boolean roundedCorners) {
- return mImpl.addDynamicShadow(shadowContainer, unfocusedZ, focusedZ, roundedCorners);
+ View shadowContainer, float unfocusedZ, float focusedZ, int roundedCornerRadius) {
+ return mImpl.addDynamicShadow(shadowContainer, unfocusedZ, focusedZ, roundedCornerRadius);
}
public void setShadowFocusLevel(Object impl, float level) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
index e367494..fdb7c71 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
@@ -20,11 +20,16 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.Rect;
/**
* Provides an SDK version-independent wrapper to support shadows, color overlays, and rounded
- * corners.
+ * corners. It's not always preferred to create a ShadowOverlayContainer, use
+ * {@link ShadowOverlayHelper} instead.
* <p>
* {@link #prepareParentForShadow(ViewGroup)} must be called on parent of container
* before using shadow. Depending on sdk version, optical bounds might be applied
@@ -46,41 +51,52 @@
* Call {@link #setOverlayColor(int)} to control overlay color.
* </p>
*/
-public class ShadowOverlayContainer extends ViewGroup {
+public class ShadowOverlayContainer extends FrameLayout {
/**
* No shadow.
*/
- public static final int SHADOW_NONE = 1;
+ public static final int SHADOW_NONE = ShadowOverlayHelper.SHADOW_NONE;
/**
* Shadows are fixed.
*/
- public static final int SHADOW_STATIC = 2;
+ public static final int SHADOW_STATIC = ShadowOverlayHelper.SHADOW_STATIC;
/**
* Shadows depend on the size, shape, and position of the view.
*/
- public static final int SHADOW_DYNAMIC = 3;
+ public static final int SHADOW_DYNAMIC = ShadowOverlayHelper.SHADOW_DYNAMIC;
private boolean mInitialized;
- private View mColorDimOverlay;
private Object mShadowImpl;
private View mWrappedView;
private boolean mRoundedCorners;
private int mShadowType = SHADOW_NONE;
private float mUnfocusedZ;
private float mFocusedZ;
+ private int mRoundedCornerRadius;
private static final Rect sTempRect = new Rect();
+ private Paint mOverlayPaint;
+ private int mOverlayColor;
+ /**
+ * Create ShadowOverlayContainer and auto select shadow type.
+ */
public ShadowOverlayContainer(Context context) {
this(context, null, 0);
}
+ /**
+ * Create ShadowOverlayContainer and auto select shadow type.
+ */
public ShadowOverlayContainer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
+ /**
+ * Create ShadowOverlayContainer and auto select shadow type.
+ */
public ShadowOverlayContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
useStaticShadow();
@@ -88,6 +104,18 @@
}
/**
+ * Create ShadowOverlayContainer with specific shadowType.
+ */
+ ShadowOverlayContainer(Context context,
+ int shadowType, boolean hasColorDimOverlay,
+ float unfocusedZ, float focusedZ, int roundedCornerRadius) {
+ super(context);
+ mUnfocusedZ = unfocusedZ;
+ mFocusedZ = focusedZ;
+ initialize(shadowType, hasColorDimOverlay, roundedCornerRadius);
+ }
+
+ /**
* Return true if the platform sdk supports shadow.
*/
public static boolean supportsShadow() {
@@ -155,7 +183,7 @@
/**
* Initialize shadows, color overlay.
- * @deprecated use {@link #initialize(boolean, boolean, boolean)} instead.
+ * @deprecated use {@link ShadowOverlayHelper#createShadowOverlayContainer(Context)} instead.
*/
@Deprecated
public void initialize(boolean hasShadow, boolean hasColorDimOverlay) {
@@ -164,29 +192,62 @@
/**
* Initialize shadows, color overlay, and rounded corners. All are optional.
+ * Shadow type are auto-selected based on {@link #useStaticShadow()} and
+ * {@link #useDynamicShadow()} call.
+ * @deprecated use {@link ShadowOverlayHelper#createShadowOverlayContainer(Context)} instead.
*/
+ @Deprecated
public void initialize(boolean hasShadow, boolean hasColorDimOverlay, boolean roundedCorners) {
+ int shadowType;
+ if (!hasShadow) {
+ shadowType = SHADOW_NONE;
+ } else {
+ shadowType = mShadowType;
+ }
+ int roundedCornerRadius = roundedCorners ? getContext().getResources().getDimensionPixelSize(
+ R.dimen.lb_rounded_rect_corner_radius) : 0;
+ initialize(shadowType, hasColorDimOverlay, roundedCornerRadius);
+ }
+
+ /**
+ * Initialize shadows, color overlay, and rounded corners. All are optional.
+ */
+ void initialize(int shadowType, boolean hasColorDimOverlay, int roundedCornerRadius) {
if (mInitialized) {
throw new IllegalStateException();
}
mInitialized = true;
- if (hasShadow) {
- switch (mShadowType) {
- case SHADOW_DYNAMIC:
- mShadowImpl = ShadowHelper.getInstance().addDynamicShadow(
- this, mUnfocusedZ, mFocusedZ, roundedCorners);
- break;
- case SHADOW_STATIC:
- mShadowImpl = StaticShadowHelper.getInstance().addStaticShadow(
- this, roundedCorners);
- break;
- }
+ mRoundedCornerRadius = roundedCornerRadius;
+ mRoundedCorners = roundedCornerRadius > 0;
+ mShadowType = shadowType;
+ switch (mShadowType) {
+ case SHADOW_DYNAMIC:
+ mShadowImpl = ShadowHelper.getInstance().addDynamicShadow(
+ this, mUnfocusedZ, mFocusedZ, mRoundedCornerRadius);
+ break;
+ case SHADOW_STATIC:
+ mShadowImpl = StaticShadowHelper.getInstance().addStaticShadow(this);
+ break;
}
- mRoundedCorners = roundedCorners;
if (hasColorDimOverlay) {
- mColorDimOverlay = LayoutInflater.from(getContext())
- .inflate(R.layout.lb_card_color_overlay, this, false);
- addView(mColorDimOverlay);
+ setWillNotDraw(false);
+ mOverlayColor = Color.TRANSPARENT;
+ mOverlayPaint = new Paint();
+ mOverlayPaint.setColor(mOverlayColor);
+ mOverlayPaint.setStyle(Paint.Style.FILL);
+ } else {
+ setWillNotDraw(true);
+ mOverlayPaint = null;
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ if (mOverlayPaint != null && mOverlayColor != Color.TRANSPARENT) {
+ canvas.drawRect(mWrappedView.getLeft(), mWrappedView.getTop(),
+ mWrappedView.getRight(), mWrappedView.getBottom(),
+ mOverlayPaint);
}
}
@@ -195,19 +256,7 @@
*/
public void setShadowFocusLevel(float level) {
if (mShadowImpl != null) {
- if (level < 0f) {
- level = 0f;
- } else if (level > 1f) {
- level = 1f;
- }
- switch (mShadowType) {
- case SHADOW_DYNAMIC:
- ShadowHelper.getInstance().setShadowFocusLevel(mShadowImpl, level);
- break;
- case SHADOW_STATIC:
- StaticShadowHelper.getInstance().setShadowFocusLevel(mShadowImpl, level);
- break;
- }
+ ShadowOverlayHelper.setShadowFocusLevel(mShadowImpl, mShadowType, level);
}
}
@@ -215,8 +264,12 @@
* Set color (with alpha) of the overlay.
*/
public void setOverlayColor(@ColorInt int overlayColor) {
- if (mColorDimOverlay != null) {
- mColorDimOverlay.setBackgroundColor(overlayColor);
+ if (mOverlayPaint != null) {
+ if (overlayColor != mOverlayColor) {
+ mOverlayColor = overlayColor;
+ mOverlayPaint.setColor(overlayColor);
+ invalidate();
+ }
}
}
@@ -227,15 +280,27 @@
if (!mInitialized || mWrappedView != null) {
throw new IllegalStateException();
}
- if (mColorDimOverlay != null) {
- addView(view, indexOfChild(mColorDimOverlay));
+ ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp != null) {
+ // if wrapped view has layout params, inherit everything but width/height.
+ // Wrapped view is assigned a FrameLayout.LayoutParams with width and height only.
+ // Margins, etc are assigned to the wrapper and take effect in parent container.
+ ViewGroup.LayoutParams wrapped_lp = new FrameLayout.LayoutParams(lp.width, lp.height);
+ // Uses MATCH_PARENT for MATCH_PARENT, WRAP_CONTENT for WRAP_CONTENT and fixed size,
+ // App can still change wrapped view fixed width/height afterwards.
+ lp.width = lp.width == LayoutParams.MATCH_PARENT ?
+ LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
+ lp.height = lp.height == LayoutParams.MATCH_PARENT ?
+ LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
+ this.setLayoutParams(lp);
+ addView(view, wrapped_lp);
} else {
addView(view);
}
- mWrappedView = view;
- if (mRoundedCorners) {
- RoundedRectHelper.getInstance().setClipToRoundedOutline(mWrappedView, true);
+ if (mRoundedCorners && mShadowType == SHADOW_STATIC) {
+ RoundedRectHelper.getInstance().setClipToRoundedOutline(view, true);
}
+ mWrappedView = view;
}
/**
@@ -246,67 +311,9 @@
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mWrappedView == null) {
- throw new IllegalStateException();
- }
- // padding and child margin are not supported.
- // first measure the wrapped view, then measure the shadow view and/or overlay view.
- int childWidthMeasureSpec, childHeightMeasureSpec;
- LayoutParams lp = mWrappedView.getLayoutParams();
- if (lp.width == LayoutParams.MATCH_PARENT) {
- childWidthMeasureSpec = MeasureSpec.makeMeasureSpec
- (MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY);
- } else {
- childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
- }
- if (lp.height == LayoutParams.MATCH_PARENT) {
- childHeightMeasureSpec = MeasureSpec.makeMeasureSpec
- (MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY);
- } else {
- childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
- }
- mWrappedView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-
- int measuredWidth = mWrappedView.getMeasuredWidth();
- int measuredHeight = mWrappedView.getMeasuredHeight();
-
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (child == mWrappedView) {
- continue;
- }
- lp = child.getLayoutParams();
- if (lp.width == LayoutParams.MATCH_PARENT) {
- childWidthMeasureSpec = MeasureSpec.makeMeasureSpec
- (measuredWidth, MeasureSpec.EXACTLY);
- } else {
- childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
- }
-
- if (lp.height == LayoutParams.MATCH_PARENT) {
- childHeightMeasureSpec = MeasureSpec.makeMeasureSpec
- (measuredHeight, MeasureSpec.EXACTLY);
- } else {
- childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
- }
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- }
- setMeasuredDimension(measuredWidth, measuredHeight);
- }
-
- @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() != GONE) {
- final int width = child.getMeasuredWidth();
- final int height = child.getMeasuredHeight();
- child.layout(0, 0, width, height);
- }
- }
- if (mWrappedView != null) {
+ super.onLayout(changed, l, t, r, b);
+ if (changed && mWrappedView != null) {
sTempRect.left = (int) mWrappedView.getPivotX();
sTempRect.top = (int) mWrappedView.getPivotY();
offsetDescendantRectToMyCoords(mWrappedView, sTempRect);
@@ -315,4 +322,8 @@
}
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayHelper.java
new file mode 100644
index 0000000..5f942c6
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayHelper.java
@@ -0,0 +1,467 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.system.Settings;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.View;
+
+
+/**
+ * ShadowOverlayHelper is a helper class for shadow, overlay color and rounded corner.
+ * There are many choices to implement Shadow, overlay color.
+ * Initialize it with ShadowOverlayHelper.Builder and it decides the best strategy based
+ * on options user choose and current platform version.
+ *
+ * <li> For shadow: it may use 9-patch with opticalBounds or Z-value based shadow for
+ * API >= 21. When 9-patch is used, it requires a ShadowOverlayContainer
+ * to include 9-patch views.
+ * <li> For overlay: it may use ShadowOverlayContainer which overrides draw() or it may
+ * use setForeground(new ColorDrawable()) for API>=23. The foreground support
+ * might be disabled if rounded corner is applied due to performance reason.
+ * <li> For rounded-corner: it uses a ViewOutlineProvider for API>=21.
+ *
+ * There are two different strategies: use Wrapper with a ShadowOverlayContainer;
+ * or apply rounded corner, overlay and rounded-corner to the view itself. Below is an example
+ * of how helper is used.
+ *
+ * <code>
+ * ShadowOverlayHelper mHelper = new ShadowOverlayHelper.Builder().
+ * .needsOverlay(true).needsRoundedCorner(true).needsShadow(true)
+ * .build();
+ * mHelper.prepareParentForShadow(parentView); // apply optical-bounds for 9-patch shadow.
+ * mHelper.setOverlayColor(view, Color.argb(0x80, 0x80, 0x80, 0x80));
+ * mHelper.setShadowFocusLevel(view, 1.0f);
+ * ...
+ * View initializeView(View view) {
+ * if (mHelper.needsWrapper()) {
+ * ShadowOverlayContainer wrapper = mHelper.createShadowOverlayContainer(context);
+ * wrapper.wrap(view);
+ * return wrapper;
+ * } else {
+ * mHelper.onViewCreated(view);
+ * return view;
+ * }
+ * }
+ * ...
+ *
+ * </code>
+ */
+public final class ShadowOverlayHelper {
+
+ /**
+ * Builder for creating ShadowOverlayHelper.
+ */
+ public static final class Builder {
+
+ private boolean needsOverlay;
+ private boolean needsRoundedCorner;
+ private boolean needsShadow;
+ private boolean preferZOrder = true;
+ private boolean keepForegroundDrawable;
+ private Options options = Options.DEFAULT;
+
+ /**
+ * Set if needs overlay color.
+ * @param needsOverlay True if needs overlay.
+ * @return The Builder object itself.
+ */
+ public Builder needsOverlay(boolean needsOverlay) {
+ this.needsOverlay = needsOverlay;
+ return this;
+ }
+
+ /**
+ * Set if needs shadow.
+ * @param needsShadow True if needs shadow.
+ * @return The Builder object itself.
+ */
+ public Builder needsShadow(boolean needsShadow) {
+ this.needsShadow = needsShadow;
+ return this;
+ }
+
+ /**
+ * Set if needs rounded corner.
+ * @param needsRoundedCorner True if needs rounded corner.
+ * @return The Builder object itself.
+ */
+ public Builder needsRoundedCorner(boolean needsRoundedCorner) {
+ this.needsRoundedCorner = needsRoundedCorner;
+ return this;
+ }
+
+ /**
+ * Set if prefer z-order shadow. On old devices, z-order shadow might be slow,
+ * set to false to fall back to static 9-patch shadow. Recommend to read
+ * from system wide Setting value: see {@link Settings}.
+ *
+ * @param preferZOrder True if prefer Z shadow. Default is true.
+ * @return The Builder object itself.
+ */
+ public Builder preferZOrder(boolean preferZOrder) {
+ this.preferZOrder = preferZOrder;
+ return this;
+ }
+
+ /**
+ * Set if not using foreground drawable for overlay color. For example if
+ * the view has already assigned a foreground drawable for other purposes.
+ * When it's true, helper will use a ShadowOverlayContainer for overlay color.
+ *
+ * @param keepForegroundDrawable True to keep the original foreground drawable.
+ * @return The Builder object itself.
+ */
+ public Builder keepForegroundDrawable(boolean keepForegroundDrawable) {
+ this.keepForegroundDrawable = keepForegroundDrawable;
+ return this;
+ }
+
+ /**
+ * Set option values e.g. Shadow Z value, rounded corner radius.
+ *
+ * @param options The Options object to create ShadowOverlayHelper.
+ */
+ public Builder options(Options options) {
+ this.options = options;
+ return this;
+ }
+
+ /**
+ * Create ShadowOverlayHelper object
+ * @param context The context uses to read Resources settings.
+ * @return The ShadowOverlayHelper object.
+ */
+ public ShadowOverlayHelper build(Context context) {
+ final ShadowOverlayHelper helper = new ShadowOverlayHelper();
+ helper.mNeedsOverlay = needsOverlay;
+ helper.mNeedsRoundedCorner = needsRoundedCorner && supportsRoundedCorner();
+ helper.mNeedsShadow = needsShadow && supportsShadow();
+
+ if (helper.mNeedsRoundedCorner) {
+ helper.setupRoundedCornerRadius(options, context);
+ }
+
+ // figure out shadow type and if we need use wrapper:
+ if (helper.mNeedsShadow) {
+ // if static shadow is prefered or dynamic shadow is not supported,
+ // use static shadow, otherwise use dynamic shadow.
+ if (!preferZOrder || !supportsDynamicShadow()) {
+ helper.mShadowType = SHADOW_STATIC;
+ // static shadow requires ShadowOverlayContainer to support crossfading
+ // of two shadow views.
+ helper.mNeedsWrapper = true;
+ } else {
+ helper.mShadowType = SHADOW_DYNAMIC;
+ helper.setupDynamicShadowZ(options, context);
+ helper.mNeedsWrapper = ((!supportsForeground() || keepForegroundDrawable)
+ && helper.mNeedsOverlay);
+ }
+ } else {
+ helper.mShadowType = SHADOW_NONE;
+ helper.mNeedsWrapper = ((!supportsForeground() || keepForegroundDrawable)
+ && helper.mNeedsOverlay);
+ }
+
+ return helper;
+ }
+
+ }
+
+ /**
+ * Option values for ShadowOverlayContainer.
+ */
+ public static final class Options {
+
+ /**
+ * Default Options for values.
+ */
+ public static final Options DEFAULT = new Options();
+
+ private int roundedCornerRadius = 0; // 0 for default value
+ private float dynamicShadowUnfocusedZ = -1; // < 0 for default value
+ private float dynamicShadowFocusedZ = -1; // < 0 for default value
+ /**
+ * Set value of rounded corner radius.
+ *
+ * @param roundedCornerRadius Number of pixels of rounded corner radius.
+ * Set to 0 to use default settings.
+ * @return The Options object itself.
+ */
+ public Options roundedCornerRadius(int roundedCornerRadius){
+ this.roundedCornerRadius = roundedCornerRadius;
+ return this;
+ }
+
+ /**
+ * Set value of focused and unfocused Z value for shadow.
+ *
+ * @param unfocusedZ Number of pixels for unfocused Z value.
+ * @param focusedZ Number of pixels for foucsed Z value.
+ * @return The Options object itself.
+ */
+ public Options dynamicShadowZ(float unfocusedZ, float focusedZ){
+ this.dynamicShadowUnfocusedZ = unfocusedZ;
+ this.dynamicShadowFocusedZ = focusedZ;
+ return this;
+ }
+
+ /**
+ * Get radius of rounded corner in pixels.
+ *
+ * @return Radius of rounded corner in pixels.
+ */
+ public final int getRoundedCornerRadius() {
+ return roundedCornerRadius;
+ }
+
+ /**
+ * Get z value of shadow when a view is not focused.
+ *
+ * @return Z value of shadow when a view is not focused.
+ */
+ public final float getDynamicShadowUnfocusedZ() {
+ return dynamicShadowUnfocusedZ;
+ }
+
+ /**
+ * Get z value of shadow when a view is focused.
+ *
+ * @return Z value of shadow when a view is focused.
+ */
+ public final float getDynamicShadowFocusedZ() {
+ return dynamicShadowFocusedZ;
+ }
+ }
+
+ /**
+ * No shadow.
+ */
+ public static final int SHADOW_NONE = 1;
+
+ /**
+ * Shadows are fixed.
+ */
+ public static final int SHADOW_STATIC = 2;
+
+ /**
+ * Shadows depend on the size, shape, and position of the view.
+ */
+ public static final int SHADOW_DYNAMIC = 3;
+
+ int mShadowType = SHADOW_NONE;
+ boolean mNeedsOverlay;
+ boolean mNeedsRoundedCorner;
+ boolean mNeedsShadow;
+ boolean mNeedsWrapper;
+
+ int mRoundedCornerRadius;
+ float mUnfocusedZ;
+ float mFocusedZ;
+
+ /**
+ * Return true if the platform sdk supports shadow.
+ */
+ public static boolean supportsShadow() {
+ return StaticShadowHelper.getInstance().supportsShadow();
+ }
+
+ /**
+ * Returns true if the platform sdk supports dynamic shadows.
+ */
+ public static boolean supportsDynamicShadow() {
+ return ShadowHelper.getInstance().supportsDynamicShadow();
+ }
+
+ /**
+ * Returns true if the platform sdk supports rounded corner through outline.
+ */
+ public static boolean supportsRoundedCorner() {
+ return RoundedRectHelper.supportsRoundedCorner();
+ }
+
+ /**
+ * Returns true if view.setForeground() is supported.
+ */
+ public static boolean supportsForeground() {
+ return ForegroundHelper.supportsForeground();
+ }
+
+ /*
+ * hide from external, should be only created by ShadowOverlayHelper.Options.
+ */
+ ShadowOverlayHelper() {
+ }
+
+ /**
+ * {@link #prepareParentForShadow(ViewGroup)} must be called on parent of container
+ * before using shadow. Depending on Shadow type, optical bounds might be applied.
+ */
+ public void prepareParentForShadow(ViewGroup parent) {
+ if (mShadowType == SHADOW_STATIC) {
+ StaticShadowHelper.getInstance().prepareParent(parent);
+ }
+ }
+
+ public int getShadowType() {
+ return mShadowType;
+ }
+
+ public boolean needsOverlay() {
+ return mNeedsOverlay;
+ }
+
+ public boolean needsRoundedCorner() {
+ return mNeedsRoundedCorner;
+ }
+
+ /**
+ * Returns true if a "wrapper" ShadowOverlayContainer is needed.
+ * When needsWrapper() is true, call {@link #createShadowOverlayContainer(Context)}
+ * to create the wrapper.
+ */
+ public boolean needsWrapper() {
+ return mNeedsWrapper;
+ }
+
+ /**
+ * Create ShadowOverlayContainer for this helper.
+ * @param context Context to create view.
+ * @return ShadowOverlayContainer.
+ */
+ public ShadowOverlayContainer createShadowOverlayContainer(Context context) {
+ if (!needsWrapper()) {
+ throw new IllegalArgumentException();
+ }
+ return new ShadowOverlayContainer(context, mShadowType, mNeedsOverlay,
+ mUnfocusedZ, mFocusedZ, mRoundedCornerRadius);
+ }
+
+ /**
+ * Set overlay color for view other than ShadowOverlayContainer.
+ * See also {@link ShadowOverlayContainer#setOverlayColor(int)}.
+ */
+ public static void setNoneWrapperOverlayColor(View view, int color) {
+ Drawable d = ForegroundHelper.getInstance().getForeground(view);
+ if (d instanceof ColorDrawable) {
+ ((ColorDrawable) d).setColor(color);
+ } else {
+ ForegroundHelper.getInstance().setForeground(view, new ColorDrawable(color));
+ }
+ }
+
+ /**
+ * Set overlay color for view, it can be a ShadowOverlayContainer if needsWrapper() is true,
+ * or other view type.
+ */
+ public void setOverlayColor(View view, int color) {
+ if (needsWrapper()) {
+ ((ShadowOverlayContainer) view).setOverlayColor(color);
+ } else {
+ setNoneWrapperOverlayColor(view, color);
+ }
+ }
+
+ /**
+ * Must be called when view is created for cases {@link #needsWrapper()} is false.
+ * @param view
+ */
+ public void onViewCreated(View view) {
+ if (!needsWrapper()) {
+ if (!mNeedsShadow) {
+ if (mNeedsRoundedCorner) {
+ RoundedRectHelper.getInstance().setClipToRoundedOutline(view,
+ true, mRoundedCornerRadius);
+ }
+ } else {
+ if (mShadowType == SHADOW_DYNAMIC) {
+ Object tag = ShadowHelper.getInstance().addDynamicShadow(
+ view, mUnfocusedZ, mFocusedZ, mRoundedCornerRadius);
+ view.setTag(R.id.lb_shadow_impl, tag);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set shadow focus level (0 to 1). 0 for unfocused, 1 for fully focused.
+ * This is for view other than ShadowOverlayContainer.
+ * See also {@link ShadowOverlayContainer#setShadowFocusLevel(float)}.
+ */
+ public static void setNoneWrapperShadowFocusLevel(View view, float level) {
+ setShadowFocusLevel(getNoneWrapperDyamicShadowImpl(view), SHADOW_DYNAMIC, level);
+ }
+
+ /**
+ * Set shadow focus level (0 to 1). 0 for unfocused, 1 for fully focused.
+ */
+ public void setShadowFocusLevel(View view, float level) {
+ if (needsWrapper()) {
+ ((ShadowOverlayContainer) view).setShadowFocusLevel(level);
+ } else {
+ setShadowFocusLevel(getNoneWrapperDyamicShadowImpl(view), SHADOW_DYNAMIC, level);
+ }
+ }
+
+ void setupDynamicShadowZ(Options options, Context context) {
+ if (options.getDynamicShadowUnfocusedZ() < 0f) {
+ Resources res = context.getResources();
+ mFocusedZ = res.getDimension(R.dimen.lb_material_shadow_focused_z);
+ mUnfocusedZ = res.getDimension(R.dimen.lb_material_shadow_normal_z);
+ } else {
+ mFocusedZ = options.getDynamicShadowFocusedZ();
+ mUnfocusedZ = options.getDynamicShadowUnfocusedZ();
+ }
+ }
+
+ void setupRoundedCornerRadius(Options options, Context context) {
+ if (options.getRoundedCornerRadius() == 0) {
+ Resources res = context.getResources();
+ mRoundedCornerRadius = res.getDimensionPixelSize(
+ R.dimen.lb_rounded_rect_corner_radius);
+ } else {
+ mRoundedCornerRadius = options.getRoundedCornerRadius();
+ }
+ }
+
+ static Object getNoneWrapperDyamicShadowImpl(View view) {
+ return view.getTag(R.id.lb_shadow_impl);
+ }
+
+ static void setShadowFocusLevel(Object impl, int shadowType, float level) {
+ if (impl != null) {
+ if (level < 0f) {
+ level = 0f;
+ } else if (level > 1f) {
+ level = 1f;
+ }
+ switch (shadowType) {
+ case SHADOW_DYNAMIC:
+ ShadowHelper.getInstance().setShadowFocusLevel(impl, level);
+ break;
+ case SHADOW_STATIC:
+ StaticShadowHelper.getInstance().setShadowFocusLevel(impl, level);
+ break;
+ }
+ }
+ }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
index 4d8411b..022ff1d 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
@@ -34,7 +34,7 @@
*/
static interface ShadowHelperVersionImpl {
public void prepareParent(ViewGroup parent);
- public Object addStaticShadow(ViewGroup shadowContainer, boolean roundedCorners);
+ public Object addStaticShadow(ViewGroup shadowContainer);
public void setShadowFocusLevel(Object impl, float level);
}
@@ -48,7 +48,7 @@
}
@Override
- public Object addStaticShadow(ViewGroup shadowContainer, boolean roundedCorners) {
+ public Object addStaticShadow(ViewGroup shadowContainer) {
// do nothing
return null;
}
@@ -69,8 +69,7 @@
}
@Override
- public Object addStaticShadow(ViewGroup shadowContainer, boolean roundedCorners) {
- // Static shadows are always rounded
+ public Object addStaticShadow(ViewGroup shadowContainer) {
return ShadowHelperJbmr2.addShadow(shadowContainer);
}
@@ -105,8 +104,8 @@
mImpl.prepareParent(parent);
}
- public Object addStaticShadow(ViewGroup shadowContainer, boolean roundedCorners) {
- return mImpl.addStaticShadow(shadowContainer, roundedCorners);
+ public Object addStaticShadow(ViewGroup shadowContainer) {
+ return mImpl.addStaticShadow(shadowContainer);
}
public void setShadowFocusLevel(Object impl, float level) {
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 c61087b..9282bb1 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
@@ -36,8 +36,6 @@
private Object mSceneWithTitle;
private Object mSceneWithoutTitle;
- static TransitionHelper sTransitionHelper = TransitionHelper.getInstance();
-
// When moving focus off the TitleView, this focus search listener assumes that the view that
// should take focus comes before the TitleView in a focus search starting at the scene root.
private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
@@ -68,16 +66,16 @@
private void createTransitions() {
mTitleUpTransition = LeanbackTransitionHelper.loadTitleOutTransition(
- mSceneRoot.getContext(), sTransitionHelper);
+ mSceneRoot.getContext());
mTitleDownTransition = LeanbackTransitionHelper.loadTitleInTransition(
- mSceneRoot.getContext(), sTransitionHelper);
- mSceneWithTitle = sTransitionHelper.createScene(mSceneRoot, new Runnable() {
+ mSceneRoot.getContext());
+ mSceneWithTitle = TransitionHelper.createScene(mSceneRoot, new Runnable() {
@Override
public void run() {
mTitleView.setVisibility(View.VISIBLE);
}
});
- mSceneWithoutTitle = sTransitionHelper.createScene(mSceneRoot, new Runnable() {
+ mSceneWithoutTitle = TransitionHelper.createScene(mSceneRoot, new Runnable() {
@Override
public void run() {
mTitleView.setVisibility(View.INVISIBLE);
@@ -90,9 +88,9 @@
*/
public void showTitle(boolean show) {
if (show) {
- sTransitionHelper.runTransition(mSceneWithTitle, mTitleDownTransition);
+ TransitionHelper.runTransition(mSceneWithTitle, mTitleDownTransition);
} else {
- sTransitionHelper.runTransition(mSceneWithoutTitle, mTitleUpTransition);
+ TransitionHelper.runTransition(mSceneWithoutTitle, mTitleUpTransition);
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
index 16b66cd..7af5ea0 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
@@ -16,6 +16,7 @@
import android.content.Context;
import android.support.v17.leanback.R;
import android.support.v17.leanback.system.Settings;
+import android.support.v17.leanback.transition.TransitionHelper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -31,6 +32,17 @@
class VerticalGridItemBridgeAdapter extends ItemBridgeAdapter {
@Override
+ protected void onCreate(ItemBridgeAdapter.ViewHolder viewHolder) {
+ if (viewHolder.itemView instanceof ViewGroup) {
+ TransitionHelper.setTransitionGroup((ViewGroup) viewHolder.itemView,
+ true);
+ }
+ if (mShadowOverlayHelper != null) {
+ mShadowOverlayHelper.onViewCreated(viewHolder.itemView);
+ }
+ }
+
+ @Override
public void onBind(final ItemBridgeAdapter.ViewHolder itemViewHolder) {
// Only when having an OnItemClickListner, we attach the OnClickListener.
if (getOnItemViewClickedListener() != null) {
@@ -83,9 +95,12 @@
private int mFocusZoomFactor;
private boolean mUseFocusDimmer;
private boolean mShadowEnabled = true;
+ private boolean mKeepChildForeground = true;
private OnItemViewSelectedListener mOnItemViewSelectedListener;
private OnItemViewClickedListener mOnItemViewClickedListener;
private boolean mRoundedCornersEnabled = true;
+ private ShadowOverlayHelper mShadowOverlayHelper;
+ private ItemBridgeAdapter.Wrapper mShadowOverlayWrapper;
/**
* Constructs a VerticalGridPresenter with defaults.
@@ -170,7 +185,7 @@
* Subclass may return false to disable.
*/
public boolean isUsingDefaultShadow() {
- return ShadowOverlayContainer.supportsShadow();
+ return ShadowOverlayHelper.supportsShadow();
}
/**
@@ -194,8 +209,7 @@
* and does not use Z-shadow on SDK >= L, it should override isUsingZOrder() return false.
*/
public boolean isUsingZOrder(Context context) {
- return ShadowOverlayContainer.supportsDynamicShadow() &&
- !Settings.getInstance(context).preferStaticShadows();
+ return !Settings.getInstance(context).preferStaticShadows();
}
final boolean needsDefaultShadow() {
@@ -216,7 +230,6 @@
return mUseFocusDimmer;
}
-
@Override
public final ViewHolder onCreateViewHolder(ViewGroup parent) {
ViewHolder vh = createGridViewHolder(parent);
@@ -238,21 +251,6 @@
return new ViewHolder((VerticalGridView) root.findViewById(R.id.browse_grid));
}
- private ItemBridgeAdapter.Wrapper mWrapper = new ItemBridgeAdapter.Wrapper() {
- @Override
- public View createWrapper(View root) {
- ShadowOverlayContainer wrapper = new ShadowOverlayContainer(root.getContext());
- wrapper.setLayoutParams(
- new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- wrapper.initialize(needsDefaultShadow(), true, areChildRoundedCornersEnabled());
- return wrapper;
- }
- @Override
- public void wrap(View wrapper, View wrapped) {
- ((ShadowOverlayContainer) wrapper).wrap(wrapped);
- }
- };
-
/**
* Called after a {@link VerticalGridPresenter.ViewHolder} is created.
* Subclasses may override this method and start by calling
@@ -268,12 +266,25 @@
vh.getGridView().setNumColumns(mNumColumns);
vh.mInitialized = true;
- vh.mItemBridgeAdapter.setWrapper(mWrapper);
- if (needsDefaultShadow() || areChildRoundedCornersEnabled()) {
- ShadowOverlayContainer.prepareParentForShadow(vh.getGridView());
- ((ViewGroup) vh.view).setClipChildren(false);
+ Context context = vh.mGridView.getContext();
+ if (mShadowOverlayHelper == null) {
+ mShadowOverlayHelper = new ShadowOverlayHelper.Builder()
+ .needsOverlay(mUseFocusDimmer)
+ .needsShadow(needsDefaultShadow())
+ .needsRoundedCorner(areChildRoundedCornersEnabled())
+ .preferZOrder(isUsingZOrder(context))
+ .keepForegroundDrawable(mKeepChildForeground)
+ .options(createShadowOverlayOptions())
+ .build(context);
+ if (mShadowOverlayHelper.needsWrapper()) {
+ mShadowOverlayWrapper = new ItemBridgeAdapterShadowOverlayWrapper(
+ mShadowOverlayHelper);
+ }
}
- vh.getGridView().setFocusDrawingOrderEnabled(!isUsingZOrder(vh.getGridView().getContext()));
+ vh.mItemBridgeAdapter.setWrapper(mShadowOverlayWrapper);
+ mShadowOverlayHelper.prepareParentForShadow(vh.mGridView);
+ vh.getGridView().setFocusDrawingOrderEnabled(mShadowOverlayHelper.getShadowType()
+ == ShadowOverlayHelper.SHADOW_STATIC);
FocusHighlightHelper.setupBrowseItemFocusHighlight(vh.mItemBridgeAdapter,
mFocusZoomFactor, mUseFocusDimmer);
@@ -286,6 +297,39 @@
});
}
+ /**
+ * Set if keeps foreground of child of this grid, the foreground will not
+ * be used for overlay color. Default value is true.
+ *
+ * @param keep True if keep foreground of child of this grid.
+ */
+ public final void setKeepChildForeground(boolean keep) {
+ mKeepChildForeground = keep;
+ }
+
+ /**
+ * Returns true if keeps foreground of child of this grid, the foreground will not
+ * be used for overlay color. Default value is true.
+ *
+ * @return True if keeps foreground of child of this grid.
+ */
+ public final boolean getKeepChildForeground() {
+ return mKeepChildForeground;
+ }
+
+ /**
+ * Create ShadowOverlayHelper Options. Subclass may override.
+ * e.g.
+ * <code>
+ * return new ShadowOverlayHelper.Options().roundedCornerRadius(10);
+ * </code>
+ *
+ * @return The options to be used for shadow, overlay and rouded corner.
+ */
+ protected ShadowOverlayHelper.Options createShadowOverlayOptions() {
+ return ShadowOverlayHelper.Options.DEFAULT;
+ }
+
@Override
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
if (DEBUG) Log.v(TAG, "onBindViewHolder " + item);
@@ -345,4 +389,18 @@
}
}
}
+
+ /**
+ * Changes the visibility of views. The entrance transition will be run against the views that
+ * change visibilities. This method is called by the fragment, it should not be called
+ * directly by the application.
+ *
+ * @param holder The ViewHolder for the vertical grid.
+ * @param afterEntrance true if children of vertical grid participating in entrance transition
+ * should be set to visible, false otherwise.
+ */
+ public void setEntranceTransitionState(VerticalGridPresenter.ViewHolder holder,
+ boolean afterEntrance) {
+ holder.mGridView.setChildrenVisibility(afterEntrance? View.VISIBLE : View.INVISIBLE);
+ }
}
diff --git a/v17/preference-leanback/Android.mk b/v17/preference-leanback/Android.mk
index c3bc803..14be7eb 100644
--- a/v17/preference-leanback/Android.mk
+++ b/v17/preference-leanback/Android.mk
@@ -34,6 +34,8 @@
LOCAL_JAR_EXCLUDE_FILES := none
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files := $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of API 21.
@@ -41,9 +43,12 @@
LOCAL_MODULE := android-support-v17-preference-leanback-api21
LOCAL_SDK_VERSION := 21
LOCAL_SRC_FILES := $(call all-java-files-under, api21)
-LOCAL_JAVA_LIBRARIES := android-support-v17-preference-leanback-res
+LOCAL_JAVA_LIBRARIES := android-support-v17-preference-leanback-res \
+ android-support-v17-leanback
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# Here is the final static library that apps can link against.
# The R class is automatically excluded from the generated library.
# Applications that use this library must specify LOCAL_RESOURCE_DIR
@@ -65,11 +70,12 @@
android-support-v17-preference-leanback-res
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# API Check
# ---------------------------------------------
support_module := $(LOCAL_MODULE)
support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(LOCAL_SRC_FILES)
support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
support_module_java_packages := android.support.v17.preference
include $(SUPPORT_API_CHECK)
diff --git a/v17/preference-leanback/api/23.txt b/v17/preference-leanback/api/23.0.0.txt
similarity index 100%
rename from v17/preference-leanback/api/23.txt
rename to v17/preference-leanback/api/23.0.0.txt
diff --git a/v17/preference-leanback/api/23.txt b/v17/preference-leanback/api/23.1.0.txt
similarity index 100%
copy from v17/preference-leanback/api/23.txt
copy to v17/preference-leanback/api/23.1.0.txt
diff --git a/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java b/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
index 2002a54..37e7a79 100644
--- a/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
+++ b/v17/preference-leanback/api21/android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21.java
@@ -16,21 +16,10 @@
package android.support.v17.preference;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
+import android.support.v17.leanback.transition.FadeAndShortSlide;
import android.app.Fragment;
-import android.graphics.Path;
-import android.transition.Fade;
import android.transition.Transition;
-import android.transition.TransitionValues;
-import android.transition.Visibility;
import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
/**
* @hide
@@ -38,8 +27,8 @@
public class LeanbackPreferenceFragmentTransitionHelperApi21 {
public static void addTransitions(Fragment f) {
- final Transition transitionStartEdge = new FadeAndShortSlideTransition(Gravity.START);
- final Transition transitionEndEdge = new FadeAndShortSlideTransition(Gravity.END);
+ final Transition transitionStartEdge = new FadeAndShortSlide(Gravity.START);
+ final Transition transitionEndEdge = new FadeAndShortSlide(Gravity.END);
f.setEnterTransition(transitionEndEdge);
f.setExitTransition(transitionStartEdge);
@@ -47,273 +36,5 @@
f.setReturnTransition(transitionEndEdge);
}
- private static class FadeAndShortSlideTransition extends Visibility {
-
- private static final TimeInterpolator sDecelerate = new DecelerateInterpolator();
-// private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
- private static final String PROPNAME_SCREEN_POSITION =
- "android:fadeAndShortSlideTransition:screenPosition";
-
- private CalculateSlide mSlideCalculator = sCalculateEnd;
- private Visibility mFade = new Fade();
-
- private interface CalculateSlide {
-
- /** Returns the translation value for view when it goes out of the scene */
- float getGoneX(ViewGroup sceneRoot, View view);
- }
-
- private static final CalculateSlide sCalculateStart = new CalculateSlide() {
- @Override
- public float getGoneX(ViewGroup sceneRoot, View view) {
- final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
- final float x;
- if (isRtl) {
- x = view.getTranslationX() + sceneRoot.getWidth() / 4;
- } else {
- x = view.getTranslationX() - sceneRoot.getWidth() / 4;
- }
- return x;
- }
- };
-
- private static final CalculateSlide sCalculateEnd = new CalculateSlide() {
- @Override
- public float getGoneX(ViewGroup sceneRoot, View view) {
- final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
- final float x;
- if (isRtl) {
- x = view.getTranslationX() - sceneRoot.getWidth() / 4;
- } else {
- x = view.getTranslationX() + sceneRoot.getWidth() / 4;
- }
- return x;
- }
- };
-
- public FadeAndShortSlideTransition(int slideEdge) {
- setSlideEdge(slideEdge);
- }
-
- @Override
- public void setEpicenterCallback(EpicenterCallback epicenterCallback) {
- super.setEpicenterCallback(epicenterCallback);
- mFade.setEpicenterCallback(epicenterCallback);
- }
-
- private void captureValues(TransitionValues transitionValues) {
- View view = transitionValues.view;
- int[] position = new int[2];
- view.getLocationOnScreen(position);
- transitionValues.values.put(PROPNAME_SCREEN_POSITION, position[0]);
- }
-
- @Override
- public void captureStartValues(TransitionValues transitionValues) {
- super.captureStartValues(transitionValues);
- mFade.captureStartValues(transitionValues);
- captureValues(transitionValues);
- }
-
- @Override
- public void captureEndValues(TransitionValues transitionValues) {
- super.captureEndValues(transitionValues);
- mFade.captureEndValues(transitionValues);
- captureValues(transitionValues);
- }
-
- public void setSlideEdge(int slideEdge) {
- switch (slideEdge) {
- case Gravity.START:
- mSlideCalculator = sCalculateStart;
- break;
- case Gravity.END:
- mSlideCalculator = sCalculateEnd;
- break;
- default:
- throw new IllegalArgumentException("Invalid slide direction");
- }
-// SidePropagation propagation = new SidePropagation();
-// propagation.setSide(slideEdge);
-// setPropagation(propagation);
- }
-
- @Override
- public Animator onAppear(ViewGroup sceneRoot, View view,
- TransitionValues startValues, TransitionValues endValues) {
- if (endValues == null) {
- return null;
- }
- Integer position = (Integer) endValues.values.get(PROPNAME_SCREEN_POSITION);
- float endX = view.getTranslationX();
- float startX = mSlideCalculator.getGoneX(sceneRoot, view);
- final Animator slideAnimator = TranslationAnimationCreator
- .createAnimation(view, endValues, position,
- startX, endX, sDecelerate, this);
- final AnimatorSet set = new AnimatorSet();
- set.play(slideAnimator)
- .with(mFade.onAppear(sceneRoot, view, startValues, endValues));
-
- return set;
- }
-
- @Override
- public Animator onDisappear(ViewGroup sceneRoot, View view,
- TransitionValues startValues, TransitionValues endValues) {
- if (startValues == null) {
- return null;
- }
- Integer position = (Integer) startValues.values.get(PROPNAME_SCREEN_POSITION);
- float startX = view.getTranslationX();
- float endX = mSlideCalculator.getGoneX(sceneRoot, view);
- final Animator slideAnimator = TranslationAnimationCreator
- .createAnimation(view, startValues, position,
- startX, endX, sDecelerate /*sAccelerate*/, this);
- final AnimatorSet set = new AnimatorSet();
- set.play(slideAnimator)
- .with(mFade.onDisappear(sceneRoot, view, startValues, endValues));
-
- return set;
- }
-
- @Override
- public Transition addListener(TransitionListener listener) {
- mFade.addListener(listener);
- return super.addListener(listener);
- }
-
- @Override
- public Transition removeListener(TransitionListener listener) {
- mFade.removeListener(listener);
- return super.removeListener(listener);
- }
-
- @Override
- public Transition clone() {
- FadeAndShortSlideTransition clone = null;
- clone = (FadeAndShortSlideTransition) super.clone();
- clone.mFade = (Visibility) mFade.clone();
- return clone;
- }
- }
-
- /**
- * This class is used by Slide and Explode to create an animator that goes from the start
- * position to the end position. It takes into account the canceled position so that it
- * will not blink out or shift suddenly when the transition is interrupted.
- */
- private static class TranslationAnimationCreator {
-
- /**
- * Creates an animator that can be used for x and/or y translations. When interrupted,
- * it sets a tag to keep track of the position so that it may be continued from position.
- *
- * @param view The view being moved. This may be in the overlay for onDisappear.
- * @param values The values containing the view in the view hierarchy.
- * @param viewPosX The x screen coordinate of view
- * @param startX The start translation x of view
- * @param endX The end translation x of view
- * @param interpolator The interpolator to use with this animator.
- * @return An animator that moves from (startX, startY) to (endX, endY) unless there was
- * a previous interruption, in which case it moves from the current position to
- * (endX, endY).
- */
- static Animator createAnimation(View view, TransitionValues values, int viewPosX,
- float startX, float endX, TimeInterpolator interpolator,
- Transition transition) {
- float terminalX = view.getTranslationX();
- Integer startPosition = (Integer) values.view.getTag(R.id.transitionPosition);
- if (startPosition != null) {
- startX = startPosition - viewPosX + terminalX;
- }
- // Initial position is at translation startX, startY, so position is offset by that
- // amount
- int startPosX = viewPosX + Math.round(startX - terminalX);
-
- view.setTranslationX(startX);
- if (startX == endX) {
- return null;
- }
- Path path = new Path();
- path.moveTo(startX, 0);
- path.lineTo(endX, 0);
- ObjectAnimator anim =
- ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y, path);
-
- TransitionPositionListener listener = new TransitionPositionListener(view, values.view,
- startPosX, terminalX);
- transition.addListener(listener);
- anim.addListener(listener);
- anim.addPauseListener(listener);
- anim.setInterpolator(interpolator);
- return anim;
- }
-
- private static class TransitionPositionListener extends AnimatorListenerAdapter implements
- Transition.TransitionListener {
-
- private final View mViewInHierarchy;
- private final View mMovingView;
- private final int mStartX;
- private Integer mTransitionPosition;
- private float mPausedX;
- private final float mTerminalX;
-
- private TransitionPositionListener(View movingView, View viewInHierarchy,
- int startX, float terminalX) {
- mMovingView = movingView;
- mViewInHierarchy = viewInHierarchy;
- mStartX = startX - Math.round(mMovingView.getTranslationX());
- mTerminalX = terminalX;
- mTransitionPosition = (Integer) mViewInHierarchy.getTag(R.id.transitionPosition);
- if (mTransitionPosition != null) {
- mViewInHierarchy.setTag(R.id.transitionPosition, null);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mTransitionPosition = Math.round(mStartX + mMovingView.getTranslationX());
- mViewInHierarchy.setTag(R.id.transitionPosition, mTransitionPosition);
- }
-
- @Override
- public void onAnimationEnd(Animator animator) {
- }
-
- @Override
- public void onAnimationPause(Animator animator) {
- mPausedX = mMovingView.getTranslationX();
- mMovingView.setTranslationX(mTerminalX);
- }
-
- @Override
- public void onAnimationResume(Animator animator) {
- mMovingView.setTranslationX(mPausedX);
- }
-
- @Override
- public void onTransitionStart(Transition transition) {
- }
-
- @Override
- public void onTransitionEnd(Transition transition) {
- mMovingView.setTranslationX(mTerminalX);
- }
-
- @Override
- public void onTransitionCancel(Transition transition) {
- }
-
- @Override
- public void onTransitionPause(Transition transition) {
- }
-
- @Override
- public void onTransitionResume(Transition transition) {
- }
- }
-
- }
}
diff --git a/v17/preference-leanback/build.gradle b/v17/preference-leanback/build.gradle
index 4063122..0ddcdd2 100644
--- a/v17/preference-leanback/build.gradle
+++ b/v17/preference-leanback/build.gradle
@@ -56,3 +56,37 @@
abortOnError false
}
}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: uri(rootProject.ext.supportRepoOut)) {
+ }
+
+ pom.project {
+ name 'Android Support Leanback Preference v17'
+ description "Android Support Leanback Preference v17"
+ url 'http://developer.android.com/tools/extras/support-library.html'
+ inceptionYear '2015'
+
+ licenses {
+ license {
+ name 'The Apache Software License, Version 2.0'
+ url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ distribution 'repo'
+ }
+ }
+
+ scm {
+ url "http://source.android.com"
+ connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+ }
+ developers {
+ developer {
+ name 'The Android Open Source Project'
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/v17/preference-leanback/res/values/ids.xml b/v17/preference-leanback/res/color/lb_preference_item_primary_text_color.xml
similarity index 70%
copy from v17/preference-leanback/res/values/ids.xml
copy to v17/preference-leanback/res/color/lb_preference_item_primary_text_color.xml
index 20c1eda..efdf1c0 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v17/preference-leanback/res/color/lb_preference_item_primary_text_color.xml
@@ -15,6 +15,7 @@
~ limitations under the License
-->
-<resources>
- <item name="transitionPosition" type="id" />
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/lb_preference_item_primary_text_color_disabled" />
+ <item android:color="@color/lb_preference_item_primary_text_color_default"/>
+</selector>
diff --git a/v17/preference-leanback/res/values/ids.xml b/v17/preference-leanback/res/color/lb_preference_item_secondary_text_color.xml
similarity index 70%
copy from v17/preference-leanback/res/values/ids.xml
copy to v17/preference-leanback/res/color/lb_preference_item_secondary_text_color.xml
index 20c1eda..68bb81a 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v17/preference-leanback/res/color/lb_preference_item_secondary_text_color.xml
@@ -15,6 +15,7 @@
~ limitations under the License
-->
-<resources>
- <item name="transitionPosition" type="id" />
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/lb_preference_item_secondary_text_color_disabled" />
+ <item android:color="@color/lb_preference_item_secondary_text_color_default"/>
+</selector>
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml b/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
index 9fae0f8..f073f3e 100644
--- a/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
@@ -20,6 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/lb_preference_decor_list_background"
+ android:elevation="@dimen/lb_preference_decor_elevation"
android:orientation="vertical"
android:transitionGroup="false"
>
@@ -29,17 +30,18 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/defaultBrandColor"
+ android:elevation="@dimen/lb_preference_decor_title_container_elevation"
android:transitionGroup="false"
>
<TextView
android:id="@+id/decor_title"
android:layout_width="match_parent"
android:layout_height="@dimen/lb_preference_decor_title_text_height"
+ android:layout_marginTop="@dimen/lb_preference_decor_title_margin_top"
+ android:layout_marginStart="@dimen/lb_preference_decor_title_margin_start"
+ android:layout_marginEnd="@dimen/lb_preference_decor_title_margin_end"
android:fontFamily="sans-serif-condensed"
android:gravity="center_vertical"
- android:paddingTop="@dimen/lb_preference_decor_title_padding_top"
- android:paddingStart="@dimen/lb_preference_decor_title_padding_start"
- android:paddingEnd="@dimen/lb_preference_decor_title_padding_end"
android:singleLine="true"
android:textSize="@dimen/lb_preference_decor_title_text_size"
android:textColor="?android:attr/textColorPrimary"
@@ -50,6 +52,7 @@
android:id="@android:id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:fontFamily="sans-serif-condensed"
android:paddingTop="14dp"
android:paddingBottom="14dp"
android:paddingStart="24dp"
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml b/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml
index 3b1345c..728ecff 100644
--- a/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml
@@ -18,20 +18,35 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
+ android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:descendantFocusability="blocksDescendants"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/lb_preference_item_padding_start"
+ android:paddingEnd="@dimen/lb_preference_item_padding_end" >
+
<CheckBox
android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <TextView
- android:id="@android:id/title"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_vertical" />
+ android:layout_width="@dimen/lb_preference_item_icon_size"
+ android:layout_height="@dimen/lb_preference_item_icon_size"
+ android:layout_marginEnd="@dimen/lb_preference_item_icon_margin_end"
+ android:layout_gravity="center_vertical" />
+
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_top" />
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/lb_preference_item_primary_text_margin_bottom"
+ android:fontFamily="sans-serif-condensed"
+ android:textColor="@color/lb_preference_item_primary_text_color"
+ android:textSize="@dimen/lb_preference_item_primary_text_size"/>
+ <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_bottom" />
+ </LinearLayout>
+
</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml b/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml
index eaf42a4..354ca41 100644
--- a/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml
@@ -18,20 +18,35 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
+ android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:descendantFocusability="blocksDescendants"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/lb_preference_item_padding_start"
+ android:paddingEnd="@dimen/lb_preference_item_padding_end" >
+
<RadioButton
android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <TextView
- android:id="@android:id/title"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_vertical" />
+ android:layout_width="@dimen/lb_preference_item_icon_size"
+ android:layout_height="@dimen/lb_preference_item_icon_size"
+ android:layout_marginEnd="@dimen/lb_preference_item_icon_margin_end"
+ android:layout_gravity="center_vertical" />
+
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_top" />
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/lb_preference_item_primary_text_margin_bottom"
+ android:fontFamily="sans-serif-condensed"
+ android:textColor="@color/lb_preference_item_primary_text_color"
+ android:textSize="@dimen/lb_preference_item_primary_text_size"/>
+ <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_bottom" />
+ </LinearLayout>
+
</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preference.xml b/v17/preference-leanback/res/layout/leanback_preference.xml
new file mode 100644
index 0000000..05ca21c
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_preference.xml
@@ -0,0 +1,74 @@
+<?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/container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true"
+ android:focusable="true"
+ android:descendantFocusability="blocksDescendants"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/lb_preference_item_padding_start"
+ android:paddingEnd="@dimen/lb_preference_item_padding_end" >
+
+ <FrameLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical" >
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/lb_preference_item_icon_size"
+ android:layout_height="@dimen/lb_preference_item_icon_size"
+ android:layout_marginEnd="@dimen/lb_preference_item_icon_margin_end"
+ />
+ </FrameLayout>
+
+ <LinearLayout android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_top" />
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/lb_preference_item_primary_text_margin_bottom"
+ android:fontFamily="sans-serif-condensed"
+ android:textColor="@color/lb_preference_item_primary_text_color"
+ android:textSize="@dimen/lb_preference_item_primary_text_size"/>
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="sans-serif-condensed"
+ android:textColor="@color/lb_preference_item_secondary_text_color"
+ android:textSize="@dimen/lb_preference_item_secondary_text_size"
+ android:maxLines="4" />
+ <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_bottom" />
+ </LinearLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preference_category.xml b/v17/preference-leanback/res/layout/leanback_preference_category.xml
new file mode 100644
index 0000000..9b978f3
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_preference_category.xml
@@ -0,0 +1,33 @@
+<?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
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/lb_preference_category_height"
+ android:clipToPadding="false"
+ android:paddingStart="@dimen/lb_preference_item_padding_start"
+ android:paddingEnd="@dimen/lb_preference_item_padding_end">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:fontFamily="sans-serif-condensed"
+ android:textColor="?android:attr/colorAccent"
+ android:textSize="@dimen/lb_preference_category_text_size"/>
+</FrameLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preference_fragment.xml b/v17/preference-leanback/res/layout/leanback_preference_fragment.xml
index d119c2d..199e0f7 100644
--- a/v17/preference-leanback/res/layout/leanback_preference_fragment.xml
+++ b/v17/preference-leanback/res/layout/leanback_preference_fragment.xml
@@ -20,6 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/lb_preference_decor_list_background"
+ android:elevation="@dimen/lb_preference_decor_elevation"
android:orientation="vertical"
android:transitionGroup="false"
>
@@ -29,17 +30,18 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/defaultBrandColor"
+ android:elevation="@dimen/lb_preference_decor_title_container_elevation"
android:transitionGroup="false"
>
<TextView
android:id="@+id/decor_title"
android:layout_width="match_parent"
android:layout_height="@dimen/lb_preference_decor_title_text_height"
+ android:layout_marginTop="@dimen/lb_preference_decor_title_margin_top"
+ android:layout_marginStart="@dimen/lb_preference_decor_title_margin_start"
+ android:layout_marginEnd="@dimen/lb_preference_decor_title_margin_end"
android:fontFamily="sans-serif-condensed"
android:gravity="center_vertical"
- android:paddingTop="@dimen/lb_preference_decor_title_padding_top"
- android:paddingStart="@dimen/lb_preference_decor_title_padding_start"
- android:paddingEnd="@dimen/lb_preference_decor_title_padding_end"
android:singleLine="true"
android:textSize="@dimen/lb_preference_decor_title_text_size"
android:textColor="?android:attr/textColorPrimary"
diff --git a/v17/preference-leanback/res/layout/leanback_preference_information.xml b/v17/preference-leanback/res/layout/leanback_preference_information.xml
new file mode 100644
index 0000000..18da8d9
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_preference_information.xml
@@ -0,0 +1,61 @@
+<?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/container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="false"
+ android:focusable="false"
+ android:descendantFocusability="blocksDescendants"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/lb_preference_item_padding_start"
+ android:paddingEnd="@dimen/lb_preference_item_padding_end" >
+
+ <LinearLayout android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_top" />
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/lb_preference_item_primary_text_margin_bottom"
+ android:fontFamily="sans-serif-condensed"
+ android:textColor="@color/lb_preference_item_primary_text_color"
+ android:textSize="@dimen/lb_preference_item_primary_text_size"/>
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="sans-serif-condensed"
+ android:textColor="@color/lb_preference_item_secondary_text_color"
+ android:textSize="@dimen/lb_preference_item_secondary_text_size"
+ android:maxLines="4" />
+ <Space android:layout_width="0dp" android:layout_height="@dimen/lb_preference_item_text_space_bottom" />
+ </LinearLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preferences_list.xml b/v17/preference-leanback/res/layout/leanback_preferences_list.xml
index 15ecebc..21e4e4a 100644
--- a/v17/preference-leanback/res/layout/leanback_preferences_list.xml
+++ b/v17/preference-leanback/res/layout/leanback_preferences_list.xml
@@ -19,4 +19,5 @@
android:id="@+id/list"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ style="?attr/preferenceFragmentListStyle" />
diff --git a/v17/preference-leanback/res/values/colors.xml b/v17/preference-leanback/res/values/colors.xml
index de6c888..30a373a 100644
--- a/v17/preference-leanback/res/values/colors.xml
+++ b/v17/preference-leanback/res/values/colors.xml
@@ -16,4 +16,11 @@
-->
<resources>
<color name="lb_preference_decor_list_background">#263238</color>
+
+ <color name="lb_preference_item_primary_text_color_default">#EEEEEE</color>
+ <color name="lb_preference_item_primary_text_color_disabled">#4DEEEEEE</color>
+
+ <color name="lb_preference_item_secondary_text_color_default">#B3EEEEEE</color>
+ <color name="lb_preference_item_secondary_text_color_disabled">#4DEEEEEE</color>
+
</resources>
diff --git a/v17/preference-leanback/res/values/dimens.xml b/v17/preference-leanback/res/values/dimens.xml
index 49763fe..f3d36af 100644
--- a/v17/preference-leanback/res/values/dimens.xml
+++ b/v17/preference-leanback/res/values/dimens.xml
@@ -15,11 +15,27 @@
~ limitations under the License
-->
<resources>
- <dimen name="lb_preference_decor_title_text_height">64dp</dimen>
- <dimen name="lb_preference_decor_title_padding_top">27dp</dimen>
- <dimen name="lb_preference_decor_title_padding_start">24dp</dimen>
- <dimen name="lb_preference_decor_title_padding_end">56dp</dimen>
- <dimen name="lb_preference_decor_title_text_size">20sp</dimen>
+ <dimen name="lb_preference_decor_title_text_height">64dp</dimen>
+ <dimen name="lb_preference_decor_title_margin_top">27dp</dimen>
+ <dimen name="lb_preference_decor_title_margin_start">24dp</dimen>
+ <dimen name="lb_preference_decor_title_margin_end">56dp</dimen>
+ <dimen name="lb_preference_decor_title_text_size">20sp</dimen>
+ <dimen name="lb_preference_decor_title_container_elevation">2dp</dimen>
+ <dimen name="lb_preference_decor_elevation">6dp</dimen>
- <dimen name="lb_settings_pane_width">360dp</dimen>
+ <dimen name="lb_preference_item_padding_start">24dp</dimen>
+ <dimen name="lb_preference_item_padding_end">56dp</dimen>
+ <dimen name="lb_preference_item_icon_size">32dp</dimen>
+ <dimen name="lb_preference_item_icon_margin_end">16dp</dimen>
+
+ <dimen name="lb_preference_item_primary_text_size">14sp</dimen>
+ <dimen name="lb_preference_item_primary_text_margin_bottom">2dp</dimen>
+ <dimen name="lb_preference_item_secondary_text_size">12sp</dimen>
+ <dimen name="lb_preference_item_text_space_top">14dp</dimen>
+ <dimen name="lb_preference_item_text_space_bottom">13dp</dimen>
+
+ <dimen name="lb_preference_category_text_size">12sp</dimen>
+ <dimen name="lb_preference_category_height">40dp</dimen>
+
+ <dimen name="lb_settings_pane_width">360dp</dimen>
</resources>
diff --git a/v17/preference-leanback/res/values/styles.xml b/v17/preference-leanback/res/values/styles.xml
new file mode 100644
index 0000000..42d2b5b
--- /dev/null
+++ b/v17/preference-leanback/res/values/styles.xml
@@ -0,0 +1,74 @@
+<?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
+ -->
+
+<resources>
+
+ <style name="LeanbackPreference">
+ <item name="android:layout">@layout/leanback_preference</item>
+ </style>
+
+ <style name="LeanbackPreference.Information">
+ <item name="android:layout">@layout/leanback_preference_information</item>
+ <item name="android:enabled">false</item>
+ <item name="android:shouldDisableView">false</item>
+ </style>
+
+ <style name="LeanbackPreference.Category">
+ <item name="android:layout">@layout/leanback_preference_category</item>
+ <!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
+ <item name="android:shouldDisableView">false</item>
+ <item name="android:selectable">false</item>
+ </style>
+
+ <style name="LeanbackPreference.CheckBoxPreference">
+ <item name="android:widgetLayout">@layout/preference_widget_checkbox</item>
+ </style>
+
+ <style name="LeanbackPreference.SwitchPreferenceCompat">
+ <item name="android:widgetLayout">@layout/preference_widget_switch_compat</item>
+ <item name="android:switchTextOn">@string/v7_preference_on</item>
+ <item name="android:switchTextOff">@string/v7_preference_off</item>
+ </style>
+
+ <style name="LeanbackPreference.SwitchPreference">
+ <item name="android:widgetLayout">@layout/preference_widget_switch</item>
+ <item name="android:switchTextOn">@string/v7_preference_on</item>
+ <item name="android:switchTextOff">@string/v7_preference_off</item>
+ </style>
+
+ <style name="LeanbackPreference.PreferenceScreen">
+ </style>
+
+ <style name="LeanbackPreference.DialogPreference">
+ <item name="android:positiveButtonText">@android:string/ok</item>
+ <item name="android:negativeButtonText">@android:string/cancel</item>
+ </style>
+
+ <style name="LeanbackPreference.DialogPreference.EditTextPreference">
+ <item name="android:dialogLayout">@layout/preference_dialog_edittext</item>
+ </style>
+
+ <style name="PreferenceFragment.Leanback">
+ <item name="android:divider">@null</item>
+ </style>
+
+ <style name="PreferenceFragmentList.Leanback">
+ <item name="android:paddingStart">0dp</item>
+ <item name="android:paddingEnd">0dp</item>
+ </style>
+
+</resources>
diff --git a/v17/preference-leanback/res/values/themes.xml b/v17/preference-leanback/res/values/themes.xml
new file mode 100644
index 0000000..591fdfa
--- /dev/null
+++ b/v17/preference-leanback/res/values/themes.xml
@@ -0,0 +1,33 @@
+<?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
+ -->
+
+<resources>
+ <style name="PreferenceThemeOverlay.v14.Leanback">
+ <item name="preferenceScreenStyle">@style/LeanbackPreference.PreferenceScreen</item>
+ <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment.Leanback</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment.Leanback</item>
+ <item name="preferenceCategoryStyle">@style/LeanbackPreference.Category</item>
+ <item name="preferenceStyle">@style/LeanbackPreference</item>
+ <item name="preferenceInformationStyle">@style/LeanbackPreference.Information</item>
+ <item name="checkBoxPreferenceStyle">@style/LeanbackPreference.CheckBoxPreference</item>
+ <item name="switchPreferenceCompatStyle">@style/LeanbackPreference.SwitchPreferenceCompat</item>
+ <item name="switchPreferenceStyle">@style/LeanbackPreference.SwitchPreference</item>
+ <item name="dialogPreferenceStyle">@style/LeanbackPreference.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@style/LeanbackPreference.DialogPreference.EditTextPreference</item>
+ <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Leanback</item>
+ </style>
+</resources>
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
index 92fdd62..a82f543 100644
--- a/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
@@ -156,8 +156,15 @@
public void onItemClick(ViewHolder viewHolder) {
final int index = viewHolder.getAdapterPosition();
final CharSequence entry = mEntryValues[index];
- mSelectedValue = entry;
- ((ListPreference) getPreference()).setValue(entry.toString());
+ final ListPreference preference = (ListPreference) getPreference();
+ if (index >= 0) {
+ String value = mEntryValues[index].toString();
+ if (preference.callChangeListener(value)) {
+ preference.setValue(value);
+ mSelectedValue = entry;
+ }
+ }
+
getFragmentManager().popBackStack();
notifyDataSetChanged();
}
@@ -206,7 +213,20 @@
} else {
mSelections.add(entry);
}
- ((MultiSelectListPreference) getPreference()).setValues(mSelections);
+ final MultiSelectListPreference multiSelectListPreference
+ = (MultiSelectListPreference) getPreference();
+ // Pass copies of the set to callChangeListener and setValues to avoid mutations
+ if (multiSelectListPreference.callChangeListener(new HashSet<>(mSelections))) {
+ multiSelectListPreference.setValues(new HashSet<>(mSelections));
+ } else {
+ // Change refused, back it out
+ if (mSelections.contains(entry)) {
+ mSelections.remove(entry);
+ } else {
+ mSelections.add(entry);
+ }
+ }
+
notifyDataSetChanged();
}
}
diff --git a/v17/tests/AndroidManifest.xml b/v17/tests/AndroidManifest.xml
index f78d435..f4dd293 100644
--- a/v17/tests/AndroidManifest.xml
+++ b/v17/tests/AndroidManifest.xml
@@ -15,7 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.support.v17.leanback.tests">
- <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="17"/>
+ <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="23"/>
<!--
This declares that this application uses the instrumentation test runner targeting
@@ -33,6 +33,14 @@
<activity android:name="android.support.v17.leanback.widget.GridActivity"
android:exported="true" />
- </application>
+ <activity android:name="android.support.v17.leanback.app.BrowseFragmentTestActivity"
+ android:theme="@style/Theme.Leanback.Browse"
+ android:exported="true" />
+
+ <activity android:name="android.support.v17.leanback.app.BrowseSupportFragmentTestActivity"
+ android:theme="@style/Theme.Leanback.Browse"
+ android:exported="true" />
+
+ </application>
</manifest>
diff --git a/v17/tests/generatev4.py b/v17/tests/generatev4.py
new file mode 100755
index 0000000..8dc4dc2
--- /dev/null
+++ b/v17/tests/generatev4.py
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+
+# 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.
+
+import os
+import sys
+
+print "Generate v4 fragment related code for leanback"
+
+files = ['BrowseTest']
+
+cls = ['BrowseTest', 'Background', 'Base', 'BaseRow', 'Browse', 'Details', 'Error', 'Headers',
+ 'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded']
+
+for w in files:
+ print "copy {}Fragment to {}SupportFragment".format(w, w)
+
+ file = open('src/android/support/v17/leanback/app/{}Fragment.java'.format(w), 'r')
+ outfile = open('src/android/support/v17/leanback/app/{}SupportFragment.java'.format(w), 'w')
+
+ outfile.write("/* This file is auto-generated from {}Fragment.java. DO NOT MODIFY. */\n\n".format(w))
+
+ for line in file:
+ for w in cls:
+ line = line.replace('{}Fragment'.format(w), '{}SupportFragment'.format(w))
+ line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
+ line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+ outfile.write(line)
+ file.close()
+ outfile.close()
+
+testcls = ['Browse']
+
+for w in testcls:
+ print "copy {}FrgamentTest to {}SupportFragmentTest".format(w, w)
+
+ file = open('src/android/support/v17/leanback/app/{}FragmentTest.java'.format(w), 'r')
+ outfile = open('src/android/support/v17/leanback/app/{}SupportFragmentTest.java'.format(w), 'w')
+
+ outfile.write("/* This file is auto-generated from {}FrgamentTest.java. DO NOT MODIFY. */\n\n".format(w))
+
+ for line in file:
+ for w in testcls:
+ line = line.replace('{}FragmentTest'.format(w), '{}SupportFragmentTest'.format(w))
+ line = line.replace('{}FragmentTestActivity'.format(w), '{}SupportFragmentTestActivity'.format(w))
+ line = line.replace('{}TestFragment'.format(w), '{}TestSupportFragment'.format(w))
+ outfile.write(line)
+ file.close()
+ outfile.close()
+
+
+print "copy BrowseFragmentTestActivity to BrowseSupportFragmentTestActivity"
+file = open('src/android/support/v17/leanback/app/BrowseFragmentTestActivity.java', 'r')
+outfile = open('src/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java', 'w')
+outfile.write("/* This file is auto-generated from BrowseFragmentTestActivity.java. DO NOT MODIFY. */\n\n")
+for line in file:
+ line = line.replace('BrowseTestFragment', 'BrowseTestSupportFragment')
+ line = line.replace('BrowseFragmentTestActivity', 'BrowseSupportFragmentTestActivity')
+ line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
+ line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+ line = line.replace('extends Activity', 'extends FragmentActivity')
+ line = line.replace('getFragmentManager', 'getSupportFragmentManager')
+ outfile.write(line)
+file.close()
+outfile.close()
+
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml b/v17/tests/res/layout/browse.xml
similarity index 61%
copy from v17/leanback/res/animator/lb_guidedactions_item_checked.xml
copy to v17/tests/res/layout/browse.xml
index 463b9f7..01226da 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml
+++ b/v17/tests/res/layout/browse.xml
@@ -14,9 +14,15 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="@integer/lb_guidedactions_item_animation_duration"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType" />
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/main_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- container for hosting GuidedStepFragment background -->
+ <FrameLayout android:id="@+id/lb_guidedstep_background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</FrameLayout>
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTest.java b/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTest.java
new file mode 100644
index 0000000..e9b1063
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.support.v17.leanback.tests.R;
+import android.test.ActivityInstrumentationTestCase2;
+import android.text.Selection;
+import android.text.Spannable;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseFragmentTest extends
+ ActivityInstrumentationTestCase2<BrowseFragmentTestActivity> {
+
+ static final long TRANSITION_LENGTH = 1000;
+
+ Instrumentation mInstrumentation;
+ BrowseFragmentTestActivity mActivity;
+
+ public BrowseFragmentTest() {
+ super(BrowseFragmentTestActivity.class);
+ }
+
+ private void initActivity(Intent intent) {
+ setActivityIntent(intent);
+ mActivity = getActivity();
+ try {
+ Thread.sleep(intent.getLongExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY,
+ BrowseTestFragment.DEFAULT_LOAD_DATA_DELAY) + TRANSITION_LENGTH);
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ public void testTwoBackKeysWithBackStack() throws Throwable {
+ mInstrumentation = getInstrumentation();
+ Intent intent = new Intent(mInstrumentation.getContext(), BrowseFragmentTestActivity.class);
+ intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, (long) 1000);
+ intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
+ initActivity(intent);
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ Thread.sleep(TRANSITION_LENGTH);
+
+ sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
+ }
+
+ public void testTwoBackKeysWithoutBackStack() throws Throwable {
+ mInstrumentation = getInstrumentation();
+ Intent intent = new Intent(mInstrumentation.getContext(), BrowseFragmentTestActivity.class);
+ intent.putExtra(BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, (long) 1000);
+ intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
+ initActivity(intent);
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ Thread.sleep(TRANSITION_LENGTH);
+
+ sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
+ }
+
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTestActivity.java b/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
new file mode 100644
index 0000000..ee433bd
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.app.Activity;
+import android.app.FragmentTransaction;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v17.leanback.tests.R;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseFragmentTestActivity extends Activity {
+
+ public static final String EXTRA_ADD_TO_BACKSTACK = "addToBackStack";
+ public static final String EXTRA_NUM_ROWS = "numRows";
+ public static final String EXTRA_REPEAT_PER_ROW = "repeatPerRow";
+ public static final String EXTRA_LOAD_DATA_DELAY = "loadDataDelay";
+ public static final String EXTRA_TEST_ENTRANCE_TRANSITION = "testEntranceTransition";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+
+ BrowseTestFragment.NUM_ROWS = intent.getIntExtra(EXTRA_NUM_ROWS,
+ BrowseTestFragment.DEFAULT_NUM_ROWS);
+ BrowseTestFragment.REPEAT_PER_ROW = intent.getIntExtra(EXTRA_REPEAT_PER_ROW,
+ BrowseTestFragment.DEFAULT_REPEAT_PER_ROW);
+ BrowseTestFragment.LOAD_DATA_DELAY = intent.getLongExtra(EXTRA_LOAD_DATA_DELAY,
+ BrowseTestFragment.DEFAULT_LOAD_DATA_DELAY);
+ BrowseTestFragment.TEST_ENTRANCE_TRANSITION = intent.getBooleanExtra(
+ EXTRA_TEST_ENTRANCE_TRANSITION,
+ BrowseTestFragment.DEFAULT_TEST_ENTRANCE_TRANSITION);
+ setContentView(R.layout.browse);
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(R.id.main_frame, new BrowseTestFragment());
+ if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
+ ft.addToBackStack(null);
+ }
+ ft.commit();
+ }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTest.java b/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
new file mode 100644
index 0000000..0c901be
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
@@ -0,0 +1,95 @@
+/* This file is auto-generated from BrowseFrgamentTest.java. DO NOT MODIFY. */
+
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.support.v17.leanback.tests.R;
+import android.test.ActivityInstrumentationTestCase2;
+import android.text.Selection;
+import android.text.Spannable;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseSupportFragmentTest extends
+ ActivityInstrumentationTestCase2<BrowseSupportFragmentTestActivity> {
+
+ static final long TRANSITION_LENGTH = 1000;
+
+ Instrumentation mInstrumentation;
+ BrowseSupportFragmentTestActivity mActivity;
+
+ public BrowseSupportFragmentTest() {
+ super(BrowseSupportFragmentTestActivity.class);
+ }
+
+ private void initActivity(Intent intent) {
+ setActivityIntent(intent);
+ mActivity = getActivity();
+ try {
+ Thread.sleep(intent.getLongExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY,
+ BrowseTestSupportFragment.DEFAULT_LOAD_DATA_DELAY) + TRANSITION_LENGTH);
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ public void testTwoBackKeysWithBackStack() throws Throwable {
+ mInstrumentation = getInstrumentation();
+ Intent intent = new Intent(mInstrumentation.getContext(), BrowseSupportFragmentTestActivity.class);
+ intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, (long) 1000);
+ intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , true);
+ initActivity(intent);
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ Thread.sleep(TRANSITION_LENGTH);
+
+ sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
+ }
+
+ public void testTwoBackKeysWithoutBackStack() throws Throwable {
+ mInstrumentation = getInstrumentation();
+ Intent intent = new Intent(mInstrumentation.getContext(), BrowseSupportFragmentTestActivity.class);
+ intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY, (long) 1000);
+ intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
+ initActivity(intent);
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ Thread.sleep(TRANSITION_LENGTH);
+
+ sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
+ }
+
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java b/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
new file mode 100644
index 0000000..036d254
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
@@ -0,0 +1,60 @@
+/* This file is auto-generated from BrowseFragmentTestActivity.java. DO NOT MODIFY. */
+
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v17.leanback.tests.R;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseSupportFragmentTestActivity extends FragmentActivity {
+
+ public static final String EXTRA_ADD_TO_BACKSTACK = "addToBackStack";
+ public static final String EXTRA_NUM_ROWS = "numRows";
+ public static final String EXTRA_REPEAT_PER_ROW = "repeatPerRow";
+ public static final String EXTRA_LOAD_DATA_DELAY = "loadDataDelay";
+ public static final String EXTRA_TEST_ENTRANCE_TRANSITION = "testEntranceTransition";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+
+ BrowseTestSupportFragment.NUM_ROWS = intent.getIntExtra(EXTRA_NUM_ROWS,
+ BrowseTestSupportFragment.DEFAULT_NUM_ROWS);
+ BrowseTestSupportFragment.REPEAT_PER_ROW = intent.getIntExtra(EXTRA_REPEAT_PER_ROW,
+ BrowseTestSupportFragment.DEFAULT_REPEAT_PER_ROW);
+ BrowseTestSupportFragment.LOAD_DATA_DELAY = intent.getLongExtra(EXTRA_LOAD_DATA_DELAY,
+ BrowseTestSupportFragment.DEFAULT_LOAD_DATA_DELAY);
+ BrowseTestSupportFragment.TEST_ENTRANCE_TRANSITION = intent.getBooleanExtra(
+ EXTRA_TEST_ENTRANCE_TRANSITION,
+ BrowseTestSupportFragment.DEFAULT_TEST_ENTRANCE_TRANSITION);
+ setContentView(R.layout.browse);
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.replace(R.id.main_frame, new BrowseTestSupportFragment());
+ if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
+ ft.addToBackStack(null);
+ }
+ ft.commit();
+ }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseTestFragment.java b/v17/tests/src/android/support/v17/leanback/app/BrowseTestFragment.java
new file mode 100644
index 0000000..744a926
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseTestFragment.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseTestFragment extends BrowseFragment {
+ private static final String TAG = "BrowseTestFragment";
+
+ final static int DEFAULT_NUM_ROWS = 100;
+ final static int DEFAULT_REPEAT_PER_ROW = 20;
+ final static long DEFAULT_LOAD_DATA_DELAY = 2000;
+ final static boolean DEFAULT_TEST_ENTRANCE_TRANSITION = true;
+
+ static int NUM_ROWS = DEFAULT_NUM_ROWS;
+ static int REPEAT_PER_ROW = DEFAULT_REPEAT_PER_ROW;
+ static long LOAD_DATA_DELAY = DEFAULT_LOAD_DATA_DELAY;
+ static boolean TEST_ENTRANCE_TRANSITION = DEFAULT_TEST_ENTRANCE_TRANSITION;
+
+ private ArrayObjectAdapter mRowsAdapter;
+
+ // For good performance, it's important to use a single instance of
+ // a card presenter for all rows using that presenter.
+ final static StringPresenter sCardPresenter = new StringPresenter();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Log.i(TAG, "onCreate");
+ super.onCreate(savedInstanceState);
+
+ setTitle("BrowseTestFragment");
+ setHeadersState(HEADERS_ENABLED);
+
+ setOnSearchClickedListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Log.i(TAG, "onSearchClicked");
+ }
+ });
+
+ setupRows();
+ setOnItemViewClickedListener(new ItemViewClickedListener());
+ setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
+ @Override
+ public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ Log.i(TAG, "onItemSelected: " + item + " row " + row);
+ }
+ });
+ if (TEST_ENTRANCE_TRANSITION) {
+ // don't run entrance transition if fragment is restored.
+ if (savedInstanceState == null) {
+ prepareEntranceTransition();
+ }
+ }
+ // simulates in a real world use case data being loaded two seconds later
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ loadData();
+ startEntranceTransition();
+ }
+ }, LOAD_DATA_DELAY);
+ }
+
+ private void setupRows() {
+ ListRowPresenter lrp = new ListRowPresenter();
+
+ mRowsAdapter = new ArrayObjectAdapter(lrp);
+
+ setAdapter(mRowsAdapter);
+ }
+
+ private void loadData() {
+ for (int i = 0; i < NUM_ROWS; ++i) {
+ ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(sCardPresenter);
+ for (int j = 0; j < REPEAT_PER_ROW; ++j) {
+ listRowAdapter.add("Hello world");
+ listRowAdapter.add("This is a test");
+ listRowAdapter.add("Android TV");
+ listRowAdapter.add("Leanback");
+ listRowAdapter.add("Hello world");
+ listRowAdapter.add("Android TV");
+ listRowAdapter.add("Leanback");
+ listRowAdapter.add("GuidedStepFragment");
+ }
+ HeaderItem header = new HeaderItem(i, "Row " + i);
+ mRowsAdapter.add(new ListRow(header, listRowAdapter));
+ }
+
+ }
+
+ private final class ItemViewClickedListener implements OnItemViewClickedListener {
+ @Override
+ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ Log.i(TAG, "onItemClicked: " + item + " row " + row);
+ }
+ }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/BrowseTestSupportFragment.java b/v17/tests/src/android/support/v17/leanback/app/BrowseTestSupportFragment.java
new file mode 100644
index 0000000..1a01b7b
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/BrowseTestSupportFragment.java
@@ -0,0 +1,128 @@
+/* This file is auto-generated from BrowseTestFragment.java. DO NOT MODIFY. */
+
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * @hide from javadoc
+ */
+public class BrowseTestSupportFragment extends BrowseSupportFragment {
+ private static final String TAG = "BrowseTestSupportFragment";
+
+ final static int DEFAULT_NUM_ROWS = 100;
+ final static int DEFAULT_REPEAT_PER_ROW = 20;
+ final static long DEFAULT_LOAD_DATA_DELAY = 2000;
+ final static boolean DEFAULT_TEST_ENTRANCE_TRANSITION = true;
+
+ static int NUM_ROWS = DEFAULT_NUM_ROWS;
+ static int REPEAT_PER_ROW = DEFAULT_REPEAT_PER_ROW;
+ static long LOAD_DATA_DELAY = DEFAULT_LOAD_DATA_DELAY;
+ static boolean TEST_ENTRANCE_TRANSITION = DEFAULT_TEST_ENTRANCE_TRANSITION;
+
+ private ArrayObjectAdapter mRowsAdapter;
+
+ // For good performance, it's important to use a single instance of
+ // a card presenter for all rows using that presenter.
+ final static StringPresenter sCardPresenter = new StringPresenter();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Log.i(TAG, "onCreate");
+ super.onCreate(savedInstanceState);
+
+ setTitle("BrowseTestSupportFragment");
+ setHeadersState(HEADERS_ENABLED);
+
+ setOnSearchClickedListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Log.i(TAG, "onSearchClicked");
+ }
+ });
+
+ setupRows();
+ setOnItemViewClickedListener(new ItemViewClickedListener());
+ setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
+ @Override
+ public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ Log.i(TAG, "onItemSelected: " + item + " row " + row);
+ }
+ });
+ if (TEST_ENTRANCE_TRANSITION) {
+ // don't run entrance transition if fragment is restored.
+ if (savedInstanceState == null) {
+ prepareEntranceTransition();
+ }
+ }
+ // simulates in a real world use case data being loaded two seconds later
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ loadData();
+ startEntranceTransition();
+ }
+ }, LOAD_DATA_DELAY);
+ }
+
+ private void setupRows() {
+ ListRowPresenter lrp = new ListRowPresenter();
+
+ mRowsAdapter = new ArrayObjectAdapter(lrp);
+
+ setAdapter(mRowsAdapter);
+ }
+
+ private void loadData() {
+ for (int i = 0; i < NUM_ROWS; ++i) {
+ ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(sCardPresenter);
+ for (int j = 0; j < REPEAT_PER_ROW; ++j) {
+ listRowAdapter.add("Hello world");
+ listRowAdapter.add("This is a test");
+ listRowAdapter.add("Android TV");
+ listRowAdapter.add("Leanback");
+ listRowAdapter.add("Hello world");
+ listRowAdapter.add("Android TV");
+ listRowAdapter.add("Leanback");
+ listRowAdapter.add("GuidedStepFragment");
+ }
+ HeaderItem header = new HeaderItem(i, "Row " + i);
+ mRowsAdapter.add(new ListRow(header, listRowAdapter));
+ }
+
+ }
+
+ private final class ItemViewClickedListener implements OnItemViewClickedListener {
+ @Override
+ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ Log.i(TAG, "onItemClicked: " + item + " row " + row);
+ }
+ }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/app/StringPresenter.java b/v17/tests/src/android/support/v17/leanback/app/StringPresenter.java
new file mode 100644
index 0000000..e6e0793
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/app/StringPresenter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.app;
+
+import android.graphics.Color;
+import android.support.v17.leanback.widget.Presenter;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * @hide from javadoc
+ */
+public class StringPresenter extends Presenter {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "StringPresenter";
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent) {
+ if (DEBUG) Log.d(TAG, "onCreateViewHolder");
+ TextView tv = new TextView(parent.getContext());
+ tv.setFocusable(true);
+ tv.setFocusableInTouchMode(true);
+ tv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 200));
+ tv.setBackgroundColor(Color.CYAN);
+ tv.setTextColor(Color.BLACK);
+ return new ViewHolder(tv);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder viewHolder, Object item) {
+ if (DEBUG) Log.d(TAG, "onBindViewHolder for " + item.toString());
+ ((TextView) viewHolder.view).setText(item.toString());
+ }
+
+ @Override
+ public void onUnbindViewHolder(ViewHolder viewHolder) {
+ if (DEBUG) Log.d(TAG, "onUnbindViewHolder");
+ }
+}
diff --git a/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java b/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
index 145ae48..902a665 100644
--- a/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
+++ b/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
@@ -360,7 +360,8 @@
holder.mItemAlignment = null;
}
if (mChildLayout == -1) {
- ((TextView) holder.itemView).setText("Item "+mItemLengths[position]);
+ ((TextView) holder.itemView).setText("Item "+mItemLengths[position]
+ + " type=" + getItemViewType(position));
boolean focusable = true;
if (mItemFocusables != null) {
focusable = mItemFocusables[position];
@@ -370,7 +371,8 @@
holder.itemView.setBackgroundColor(Color.LTGRAY);
} else {
if (holder.itemView instanceof TextView) {
- ((TextView) holder.itemView).setText("Item "+mItemLengths[position]);
+ ((TextView) holder.itemView).setText("Item "+mItemLengths[position]
+ + " type=" + getItemViewType(position));
}
}
updateSize(holder.itemView, position);
@@ -380,6 +382,7 @@
public int getItemCount() {
return mNumItems;
}
+
}
void updateSize(View view, int position) {
diff --git a/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
index e9e53e4..335f449 100644
--- a/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -21,6 +21,7 @@
import android.text.Spannable;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -105,6 +106,23 @@
Thread.sleep(500);
}
+ protected void waitForScrollIdleAndItemAnimation(Runnable verify) throws Throwable {
+ waitForScrollIdle();
+ waitForItemAnimation();
+ verify.run();
+ }
+
+ protected void waitForItemAnimation() throws Throwable {
+ Thread.sleep(100);
+ while (mGridView.getItemAnimator() != null && mGridView.getItemAnimator().isRunning()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ex) {
+ break;
+ }
+ }
+ }
+
/**
* Wait for grid view stop scroll and optionally verify state of grid view.
*/
@@ -1161,12 +1179,12 @@
initActivity(intent);
mGridView.setSelectedPositionSmooth(0);
- waitForScrollIdle(mVerifyLayout);
+ waitForScrollIdleAndItemAnimation(mVerifyLayout);
for (int i = 0; i < pressDown; i++) {
sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
}
- waitForScrollIdle(mVerifyLayout);
+ waitForScrollIdleAndItemAnimation(mVerifyLayout);
assertFalse(mGridView.isFocused());
}
@@ -1570,6 +1588,40 @@
((VerticalGridViewEx) mGridView).mSmoothScrollByCalled < 10);
}
+ public void testSmoothscrollerCancelled() throws Throwable {
+ mInstrumentation = getInstrumentation();
+ Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+ intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+ R.layout.vertical_linear);
+ intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+ int[] items = new int[100];
+ for (int i = 0; i < items.length; i++) {
+ items[i] = 680;
+ }
+ intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+ intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+ mOrientation = BaseGridView.VERTICAL;
+ mNumRows = 1;
+
+ initActivity(intent);
+
+ mGridView.setSelectedPositionSmooth(0);
+ waitForScrollIdle(mVerifyLayout);
+ assertTrue(mGridView.getChildAt(0).hasFocus());
+
+ int targetPosition = items.length - 1;
+ mGridView.setSelectedPositionSmooth(targetPosition);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ mGridView.stopScroll();
+ }
+ });
+ Thread.sleep(100);
+ assertEquals(mGridView.getSelectedPosition(), targetPosition);
+ assertSame(mGridView.getLayoutManager().findViewByPosition(targetPosition),
+ mGridView.findFocus());
+ }
+
public void testSetNumRowsAndAddItem() throws Throwable {
mInstrumentation = getInstrumentation();
Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
@@ -1656,7 +1708,7 @@
mGridView.setSelectedPositionSmooth(0);
}
});
- waitForScrollIdle(mVerifyLayout);
+ waitForScrollIdleAndItemAnimation(mVerifyLayout);
verifyMargin();
runTestOnUiThread(new Runnable() {
@@ -1664,7 +1716,7 @@
mGridView.setSelectedPositionSmooth(1);
}
});
- waitForScrollIdle(mVerifyLayout);
+ waitForScrollIdleAndItemAnimation(mVerifyLayout);
verifyMargin();
}
@@ -1735,7 +1787,7 @@
mGridView.setSelectedPositionSmooth(1);
}
});
- waitForScrollIdle(mVerifyLayout);
+ waitForScrollIdleAndItemAnimation(mVerifyLayout);
assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1);
assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2);
assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1);
@@ -1753,7 +1805,7 @@
mGridView.setSelectedPositionSmooth(0);
}
});
- waitForScrollIdle(mVerifyLayout);
+ waitForScrollIdleAndItemAnimation(mVerifyLayout);
assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1);
assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2);
assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1);
@@ -1835,6 +1887,20 @@
}
}
+ static class ChangeableViewTypesProvider implements ViewTypeProvider {
+ static SparseIntArray sViewTypes = new SparseIntArray();
+ @Override
+ public int getViewType(int position) {
+ return sViewTypes.get(position);
+ }
+ public static void clear() {
+ sViewTypes.clear();
+ }
+ public static void setViewType(int position, int type) {
+ sViewTypes.put(position, type);
+ }
+ }
+
static class PositionItemAlignmentFacetProviderForRelativeLayout1
implements ItemAlignmentFacetProvider {
ItemAlignmentFacet mMultipleFacet;
@@ -2050,6 +2116,38 @@
assertEquals(0, mGridView.getSelectedPosition());
}
+ public void testNotifyItemTypeChangedSelectionEvent() throws Throwable {
+ mInstrumentation = getInstrumentation();
+ Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+ intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+ R.layout.vertical_linear);
+ intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+ intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+ ChangeableViewTypesProvider.class.getName());
+ ChangeableViewTypesProvider.clear();
+ initActivity(intent);
+ mOrientation = BaseGridView.HORIZONTAL;
+ mNumRows = 1;
+
+ final ArrayList<Integer> selectedLog = new ArrayList<Integer>();
+ mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
+ public void onChildSelected(ViewGroup parent, View view, int position, long id) {
+ selectedLog.add(position);
+ }
+ });
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ ChangeableViewTypesProvider.setViewType(0, 1);
+ mGridView.getAdapter().notifyItemChanged(0, 1);
+ }
+ });
+ waitForTransientStateGone(null);
+ assertEquals(0, mGridView.getSelectedPosition());
+ assertEquals(selectedLog.size(), 1);
+ assertEquals((int) selectedLog.get(0), 0);
+ }
+
public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable {
mInstrumentation = getInstrumentation();
Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
diff --git a/v17/tests/src/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java b/v17/tests/src/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
new file mode 100644
index 0000000..e7ec4bf
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package android.support.v17.leanback.widget;
+
+import android.test.AndroidTestCase;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+
+public class ShadowOverlayContainerTest extends AndroidTestCase {
+
+ public void testWrapContent() {
+ FrameLayout frameLayout = new FrameLayout(getContext());
+ TextView textView = new TextView(getContext());
+ textView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT));
+ textView.setText("abc");
+ ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+ container.initialize(true, true, true);
+ container.wrap(textView);
+ frameLayout.addView(container);
+ frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+ frameLayout.layout(0, 0, 500, 500);
+ assertTrue(textView.getWidth() > 0);
+ assertTrue(textView.getWidth() < 500);
+ assertTrue(textView.getHeight() > 0);
+ assertTrue(textView.getHeight() < 500);
+ assertEquals(container.getWidth(), textView.getWidth());
+ assertEquals(container.getHeight(), textView.getHeight());
+
+ // change layout size of textView after wrap()
+ textView.setLayoutParams(new FrameLayout.LayoutParams(123, 123));
+ frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+ frameLayout.layout(0, 0, 500, 500);
+ assertTrue(textView.getWidth() == 123);
+ assertTrue(textView.getHeight() == 123);
+ assertEquals(container.getWidth(), textView.getWidth());
+ assertEquals(container.getHeight(), textView.getHeight());
+ }
+
+ public void testFixedSize() {
+ FrameLayout frameLayout = new FrameLayout(getContext());
+ TextView textView = new TextView(getContext());
+ textView.setLayoutParams(new FrameLayout.LayoutParams(200, LayoutParams.WRAP_CONTENT));
+ textView.setText("abc");
+ ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+ container.initialize(true, true, true);
+ container.wrap(textView);
+ frameLayout.addView(container);
+ frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+ frameLayout.layout(0, 0, 500, 500);
+ assertTrue(textView.getWidth() == 200);
+ assertTrue(textView.getHeight() > 0);
+ assertTrue(textView.getHeight() < 500);
+ assertEquals(container.getWidth(), textView.getWidth());
+ assertEquals(container.getHeight(), textView.getHeight());
+
+ // change layout size of textView after wrap()
+ textView.setLayoutParams(new FrameLayout.LayoutParams(123, 123));
+ frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+ frameLayout.layout(0, 0, 500, 500);
+ assertTrue(textView.getWidth() == 123);
+ assertTrue(textView.getHeight() == 123);
+ assertEquals(container.getWidth(), textView.getWidth());
+ assertEquals(container.getHeight(), textView.getHeight());
+ }
+
+ public void testMatchParent() {
+ FrameLayout frameLayout = new FrameLayout(getContext());
+ TextView textView = new TextView(getContext());
+ textView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ textView.setText("abc");
+ ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+ container.initialize(true, true, true);
+ container.wrap(textView);
+ frameLayout.addView(container);
+ frameLayout.measure(MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+ frameLayout.layout(0, 0, 500, 500);
+ assertTrue(textView.getWidth() == 500);
+ assertTrue(textView.getHeight() > 0);
+ assertTrue(textView.getHeight() < 500);
+ assertEquals(container.getWidth(), textView.getWidth());
+ assertEquals(container.getHeight(), textView.getHeight());
+ }
+}
diff --git a/v4/Android.mk b/v4/Android.mk
index 2050725..4336e40 100644
--- a/v4/Android.mk
+++ b/v4/Android.mk
@@ -22,6 +22,9 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-annotations
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files := $(LOCAL_SRC_FILES)
+support_module_java_libraries := android-support-annotations
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Eclair APIs.
@@ -32,6 +35,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-donut
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Eclair MR1 APIs.
@@ -42,6 +47,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-eclair
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Froyo APIs.
@@ -52,6 +59,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-eclair-mr1
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Gingerbread APIs.
@@ -62,6 +71,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-froyo
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Honeycomb APIs.
@@ -72,6 +83,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-gingerbread
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Honeycomb MR1 APIs.
@@ -82,6 +95,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-honeycomb
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Honeycomb MR2 APIs.
@@ -92,6 +107,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-honeycomb-mr1
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Ice Cream Sandwich APIs.
@@ -102,6 +119,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-honeycomb-mr2
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Ice Cream Sandwich MR1 APIs.
@@ -112,6 +131,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-ics
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of JellyBean APIs.
@@ -122,6 +143,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-ics-mr1
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of JellyBean MR1 APIs.
@@ -132,6 +155,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-jellybean
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of JellyBean MR2 APIs.
@@ -142,6 +167,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-jellybean-mr1
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of KitKat APIs.
@@ -152,6 +179,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-jellybean-mr2
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of V20 APIs.
@@ -162,16 +191,33 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-kitkat
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
+# -----------------------------------------------------------------------
+
+# A helper sub-library that allows to use Lollipop internal APIs.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v4-api21-internal
+LOCAL_SDK_VERSION := 21
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, api21/android/content/pm) \
+ $(call all-java-files-under, api21/android/service/media)
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_JAVA_LIBRARY)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of Lollipop APIs.
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v4-api21
LOCAL_SDK_VERSION := 21
-LOCAL_SRC_FILES := $(call all-java-files-under, api21)
+LOCAL_SRC_FILES := $(call all-java-files-under, api21/android/support)
+LOCAL_JAVA_LIBRARIES := android-support-v4-api21-internal
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-api20
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of V22 APIs.
@@ -182,6 +228,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-api21
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# A helper sub-library that makes direct use of V23 APIs.
@@ -189,9 +237,12 @@
LOCAL_MODULE := android-support-v4-api23
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, api23)
+LOCAL_JAVA_LIBRARIES := android-support-v4-api21-internal
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-api22
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# -----------------------------------------------------------------------
# Here is the final static library that apps can link against.
@@ -204,11 +255,12 @@
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4-api23
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+support_module_aidl_includes := $(LOCAL_AIDL_INCLUDES)
+
# API Check
# ---------------------------------------------
support_module := $(LOCAL_MODULE)
support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(LOCAL_SRC_FILES)
-support_module_java_libraries := android-support-v4
support_module_java_packages := android.support.v4.*
include $(SUPPORT_API_CHECK)
diff --git a/v4/api/23.txt b/v4/api/23.0.0.txt
similarity index 100%
rename from v4/api/23.txt
rename to v4/api/23.0.0.txt
diff --git a/v4/api/23.1.0.txt b/v4/api/23.1.0.txt
new file mode 100644
index 0000000..ccefe22
--- /dev/null
+++ b/v4/api/23.1.0.txt
@@ -0,0 +1,3520 @@
+package android.support.v4.accessibilityservice {
+
+ public class AccessibilityServiceInfoCompat {
+ method public static java.lang.String capabilityToString(int);
+ method public static java.lang.String feedbackTypeToString(int);
+ method public static java.lang.String flagToString(int);
+ method public static boolean getCanRetrieveWindowContent(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static java.lang.String getDescription(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static java.lang.String getId(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static android.content.pm.ResolveInfo getResolveInfo(android.accessibilityservice.AccessibilityServiceInfo);
+ method public static java.lang.String getSettingsActivityName(android.accessibilityservice.AccessibilityServiceInfo);
+ field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+ field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+ field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+ field public static final int DEFAULT = 1; // 0x1
+ field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+ field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+ field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+ field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+ field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+ field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+ }
+
+}
+
+package android.support.v4.animation {
+
+ public abstract class AnimatorCompatHelper {
+ method public static void clearInterpolator(android.view.View);
+ method public static android.support.v4.animation.ValueAnimatorCompat emptyValueAnimator();
+ }
+
+ public abstract interface AnimatorListenerCompat {
+ method public abstract void onAnimationCancel(android.support.v4.animation.ValueAnimatorCompat);
+ method public abstract void onAnimationEnd(android.support.v4.animation.ValueAnimatorCompat);
+ method public abstract void onAnimationRepeat(android.support.v4.animation.ValueAnimatorCompat);
+ method public abstract void onAnimationStart(android.support.v4.animation.ValueAnimatorCompat);
+ }
+
+ public abstract interface AnimatorUpdateListenerCompat {
+ method public abstract void onAnimationUpdate(android.support.v4.animation.ValueAnimatorCompat);
+ }
+
+ public abstract interface ValueAnimatorCompat {
+ method public abstract void addListener(android.support.v4.animation.AnimatorListenerCompat);
+ method public abstract void addUpdateListener(android.support.v4.animation.AnimatorUpdateListenerCompat);
+ method public abstract void cancel();
+ method public abstract float getAnimatedFraction();
+ method public abstract void setDuration(long);
+ method public abstract void setTarget(android.view.View);
+ method public abstract void start();
+ }
+
+}
+
+package android.support.v4.app {
+
+ public deprecated class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+ ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int, int);
+ ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, boolean, int, int, int);
+ method public boolean isDrawerIndicatorEnabled();
+ method public void onConfigurationChanged(android.content.res.Configuration);
+ method public void onDrawerClosed(android.view.View);
+ method public void onDrawerOpened(android.view.View);
+ method public void onDrawerSlide(android.view.View, float);
+ method public void onDrawerStateChanged(int);
+ method public boolean onOptionsItemSelected(android.view.MenuItem);
+ method public void setDrawerIndicatorEnabled(boolean);
+ method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+ method public void setHomeAsUpIndicator(int);
+ method public void syncState();
+ }
+
+ public static abstract interface ActionBarDrawerToggle.Delegate {
+ method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+ method public abstract void setActionBarDescription(int);
+ method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+ }
+
+ public static abstract interface ActionBarDrawerToggle.DelegateProvider {
+ method public abstract android.support.v4.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+ }
+
+ public class ActivityCompat extends android.support.v4.content.ContextCompat {
+ ctor public ActivityCompat();
+ method public static void finishAffinity(android.app.Activity);
+ method public static void finishAfterTransition(android.app.Activity);
+ method public 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);
+ method public static void setEnterSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+ method public static void setExitSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+ method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, java.lang.String);
+ method public static void startActivity(android.app.Activity, android.content.Intent, android.os.Bundle);
+ method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle);
+ method public static void startPostponedEnterTransition(android.app.Activity);
+ }
+
+ public static abstract interface ActivityCompat.OnRequestPermissionsResultCallback {
+ method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
+ }
+
+ public final class ActivityManagerCompat {
+ method public static boolean isLowRamDevice(android.app.ActivityManager);
+ }
+
+ public class ActivityOptionsCompat {
+ ctor protected ActivityOptionsCompat();
+ method public static android.support.v4.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+ method public static android.support.v4.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+ method public static android.support.v4.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
+ method public static android.support.v4.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.support.v4.util.Pair<android.view.View, java.lang.String>...);
+ method public static android.support.v4.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+ method public android.os.Bundle toBundle();
+ method public void update(android.support.v4.app.ActivityOptionsCompat);
+ }
+
+ public class AppOpsManagerCompat {
+ ctor public AppOpsManagerCompat();
+ method public static int noteOp(android.content.Context, java.lang.String, int, java.lang.String);
+ method public static int noteProxyOp(android.content.Context, java.lang.String, java.lang.String);
+ method public static java.lang.String permissionToOp(java.lang.String);
+ field public static final int MODE_ALLOWED = 0; // 0x0
+ field public static final int MODE_DEFAULT = 3; // 0x3
+ field public static final int MODE_IGNORED = 1; // 0x1
+ }
+
+ abstract class BaseFragmentActivityDonut extends android.app.Activity {
+ }
+
+ abstract class BaseFragmentActivityHoneycomb extends android.support.v4.app.BaseFragmentActivityDonut {
+ }
+
+ public class BundleCompat {
+ ctor public BundleCompat();
+ method public static android.os.IBinder getBinder(android.os.Bundle, java.lang.String);
+ method public static void putBinder(android.os.Bundle, java.lang.String, android.os.IBinder);
+ }
+
+ public class DialogFragment extends android.support.v4.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+ ctor public DialogFragment();
+ method public void dismiss();
+ method public void dismissAllowingStateLoss();
+ method public android.app.Dialog getDialog();
+ method public boolean getShowsDialog();
+ method public int getTheme();
+ method public boolean isCancelable();
+ method public void onCancel(android.content.DialogInterface);
+ method public android.app.Dialog onCreateDialog(android.os.Bundle);
+ method public void onDismiss(android.content.DialogInterface);
+ method public void setCancelable(boolean);
+ method public void setShowsDialog(boolean);
+ method public void setStyle(int, int);
+ method public void show(android.support.v4.app.FragmentManager, java.lang.String);
+ method public int show(android.support.v4.app.FragmentTransaction, java.lang.String);
+ field public static final int STYLE_NORMAL = 0; // 0x0
+ field public static final int STYLE_NO_FRAME = 2; // 0x2
+ field public static final int STYLE_NO_INPUT = 3; // 0x3
+ field public static final int STYLE_NO_TITLE = 1; // 0x1
+ }
+
+ public class Fragment implements android.content.ComponentCallbacks android.view.View.OnCreateContextMenuListener {
+ ctor public Fragment();
+ method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public final boolean equals(java.lang.Object);
+ method public final android.support.v4.app.FragmentActivity getActivity();
+ method public boolean getAllowEnterTransitionOverlap();
+ method public boolean getAllowReturnTransitionOverlap();
+ method public final android.os.Bundle getArguments();
+ method public final android.support.v4.app.FragmentManager getChildFragmentManager();
+ method public android.content.Context getContext();
+ method public java.lang.Object getEnterTransition();
+ method public java.lang.Object getExitTransition();
+ method public final android.support.v4.app.FragmentManager getFragmentManager();
+ method public final java.lang.Object getHost();
+ method public final int getId();
+ method public android.support.v4.app.LoaderManager getLoaderManager();
+ method public final android.support.v4.app.Fragment getParentFragment();
+ method public java.lang.Object getReenterTransition();
+ method public final android.content.res.Resources getResources();
+ method public final boolean getRetainInstance();
+ method public java.lang.Object getReturnTransition();
+ method public java.lang.Object getSharedElementEnterTransition();
+ method public java.lang.Object getSharedElementReturnTransition();
+ method public final java.lang.String getString(int);
+ method public final java.lang.String getString(int, java.lang.Object...);
+ method public final java.lang.String getTag();
+ method public final android.support.v4.app.Fragment getTargetFragment();
+ method public final int getTargetRequestCode();
+ method public final java.lang.CharSequence getText(int);
+ method public boolean getUserVisibleHint();
+ method public android.view.View getView();
+ method public final int hashCode();
+ method public static android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String);
+ method public static android.support.v4.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
+ method public final boolean isAdded();
+ method public final boolean isDetached();
+ method public final boolean isHidden();
+ method public final boolean isInLayout();
+ method public final boolean isRemoving();
+ method public final boolean isResumed();
+ method public final boolean isVisible();
+ method public void onActivityCreated(android.os.Bundle);
+ method public void onActivityResult(int, int, android.content.Intent);
+ method public void onAttach(android.content.Context);
+ method public deprecated void onAttach(android.app.Activity);
+ method public void onConfigurationChanged(android.content.res.Configuration);
+ method public boolean onContextItemSelected(android.view.MenuItem);
+ method public void onCreate(android.os.Bundle);
+ method public android.view.animation.Animation onCreateAnimation(int, boolean, int);
+ method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
+ method public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method public void onDestroy();
+ method public void onDestroyOptionsMenu();
+ method public void onDestroyView();
+ method public void onDetach();
+ method public void onHiddenChanged(boolean);
+ method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
+ method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
+ method public void onLowMemory();
+ method public boolean onOptionsItemSelected(android.view.MenuItem);
+ method public void onOptionsMenuClosed(android.view.Menu);
+ method public void onPause();
+ method public void onPrepareOptionsMenu(android.view.Menu);
+ method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
+ method public void onResume();
+ method public void onSaveInstanceState(android.os.Bundle);
+ method public void onStart();
+ method public void onStop();
+ method public void onViewCreated(android.view.View, android.os.Bundle);
+ method public void onViewStateRestored(android.os.Bundle);
+ method public void registerForContextMenu(android.view.View);
+ method public final void requestPermissions(java.lang.String[], int);
+ method public void setAllowEnterTransitionOverlap(boolean);
+ method public void setAllowReturnTransitionOverlap(boolean);
+ method public void setArguments(android.os.Bundle);
+ method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
+ method public void setEnterTransition(java.lang.Object);
+ method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+ method public void setExitTransition(java.lang.Object);
+ method public void setHasOptionsMenu(boolean);
+ method public void setInitialSavedState(android.support.v4.app.Fragment.SavedState);
+ method public void setMenuVisibility(boolean);
+ method public void setReenterTransition(java.lang.Object);
+ method public void setRetainInstance(boolean);
+ method public void setReturnTransition(java.lang.Object);
+ method public void setSharedElementEnterTransition(java.lang.Object);
+ method public void setSharedElementReturnTransition(java.lang.Object);
+ method public void setTargetFragment(android.support.v4.app.Fragment, int);
+ method public void setUserVisibleHint(boolean);
+ method public boolean shouldShowRequestPermissionRationale(java.lang.String);
+ method public void startActivity(android.content.Intent);
+ method public void startActivityForResult(android.content.Intent, int);
+ method public void unregisterForContextMenu(android.view.View);
+ }
+
+ public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+ ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
+ }
+
+ public static class Fragment.SavedState implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.app.Fragment.SavedState> CREATOR;
+ }
+
+ public class FragmentActivity extends android.support.v4.app.BaseFragmentActivityHoneycomb implements android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback {
+ ctor public FragmentActivity();
+ method public java.lang.Object getLastCustomNonConfigurationInstance();
+ method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+ method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+ method public final android.support.v4.media.session.MediaControllerCompat getSupportMediaController();
+ method public void onAttachFragment(android.support.v4.app.Fragment);
+ method protected void onResumeFragments();
+ method public java.lang.Object onRetainCustomNonConfigurationInstance();
+ method public final java.lang.Object onRetainNonConfigurationInstance();
+ method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
+ method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+ method public final void setSupportMediaController(android.support.v4.media.session.MediaControllerCompat);
+ method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+ method public void supportFinishAfterTransition();
+ method public void supportInvalidateOptionsMenu();
+ method public void supportPostponeEnterTransition();
+ method public void supportStartPostponedEnterTransition();
+ method public final void validateRequestPermissionsRequestCode(int);
+ }
+
+ public abstract class FragmentContainer {
+ ctor public FragmentContainer();
+ method public abstract android.view.View onFindViewById(int);
+ method public abstract boolean onHasView();
+ }
+
+ public class FragmentController {
+ method public void attachHost(android.support.v4.app.Fragment);
+ method public static final android.support.v4.app.FragmentController createController(android.support.v4.app.FragmentHostCallback<?>);
+ method public void dispatchActivityCreated();
+ method public void dispatchConfigurationChanged(android.content.res.Configuration);
+ method public boolean dispatchContextItemSelected(android.view.MenuItem);
+ method public void dispatchCreate();
+ method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method public void dispatchDestroy();
+ method public void dispatchDestroyView();
+ method public void dispatchLowMemory();
+ method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+ method public void dispatchOptionsMenuClosed(android.view.Menu);
+ method public void dispatchPause();
+ method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+ method public void dispatchReallyStop();
+ method public void dispatchResume();
+ method public void dispatchStart();
+ method public void dispatchStop();
+ method public void doLoaderDestroy();
+ method public void doLoaderRetain();
+ method public void doLoaderStart();
+ method public void doLoaderStop(boolean);
+ method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public boolean execPendingActions();
+ method public java.util.List<android.support.v4.app.Fragment> getActiveFragments(java.util.List<android.support.v4.app.Fragment>);
+ method public int getActiveFragmentsCount();
+ method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+ method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+ method public void noteStateNotSaved();
+ method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+ method public void reportLoaderStart();
+ method public void restoreAllState(android.os.Parcelable, java.util.List<android.support.v4.app.Fragment>);
+ method public void restoreLoaderNonConfig(android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager>);
+ method public android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager> retainLoaderNonConfig();
+ method public java.util.List<android.support.v4.app.Fragment> retainNonConfig();
+ method public android.os.Parcelable saveAllState();
+ }
+
+ public abstract class FragmentHostCallback extends android.support.v4.app.FragmentContainer {
+ ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+ method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public android.view.View onFindViewById(int);
+ method public abstract E onGetHost();
+ method public android.view.LayoutInflater onGetLayoutInflater();
+ method public int onGetWindowAnimations();
+ method public boolean onHasView();
+ method public boolean onHasWindowAnimations();
+ method public void onRequestPermissionsFromFragment(android.support.v4.app.Fragment, java.lang.String[], int);
+ method public boolean onShouldSaveFragmentState(android.support.v4.app.Fragment);
+ method public boolean onShouldShowRequestPermissionRationale(java.lang.String);
+ method public void onStartActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+ method public void onSupportInvalidateOptionsMenu();
+ }
+
+ public abstract class FragmentManager {
+ ctor public FragmentManager();
+ method public abstract void addOnBackStackChangedListener(android.support.v4.app.FragmentManager.OnBackStackChangedListener);
+ method public abstract android.support.v4.app.FragmentTransaction beginTransaction();
+ method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public static void enableDebugLogging(boolean);
+ method public abstract boolean executePendingTransactions();
+ method public abstract android.support.v4.app.Fragment findFragmentById(int);
+ method public abstract android.support.v4.app.Fragment findFragmentByTag(java.lang.String);
+ method public abstract android.support.v4.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+ method public abstract int getBackStackEntryCount();
+ method public abstract android.support.v4.app.Fragment getFragment(android.os.Bundle, java.lang.String);
+ method public abstract boolean isDestroyed();
+ method public abstract void popBackStack();
+ method public abstract void popBackStack(java.lang.String, int);
+ method public abstract void popBackStack(int, int);
+ method public abstract boolean popBackStackImmediate();
+ method public abstract boolean popBackStackImmediate(java.lang.String, int);
+ method public abstract boolean popBackStackImmediate(int, int);
+ method public abstract void putFragment(android.os.Bundle, java.lang.String, android.support.v4.app.Fragment);
+ method public abstract void removeOnBackStackChangedListener(android.support.v4.app.FragmentManager.OnBackStackChangedListener);
+ method public abstract android.support.v4.app.Fragment.SavedState saveFragmentInstanceState(android.support.v4.app.Fragment);
+ field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+ }
+
+ public static abstract interface FragmentManager.BackStackEntry {
+ method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
+ method public abstract int getBreadCrumbShortTitleRes();
+ method public abstract java.lang.CharSequence getBreadCrumbTitle();
+ method public abstract int getBreadCrumbTitleRes();
+ method public abstract int getId();
+ method public abstract java.lang.String getName();
+ }
+
+ public static abstract interface FragmentManager.OnBackStackChangedListener {
+ method public abstract void onBackStackChanged();
+ }
+
+ public abstract class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
+ ctor public FragmentPagerAdapter(android.support.v4.app.FragmentManager);
+ method public abstract android.support.v4.app.Fragment getItem(int);
+ method public long getItemId(int);
+ method public boolean isViewFromObject(android.view.View, java.lang.Object);
+ }
+
+ public abstract class FragmentStatePagerAdapter extends android.support.v4.view.PagerAdapter {
+ ctor public FragmentStatePagerAdapter(android.support.v4.app.FragmentManager);
+ method public abstract android.support.v4.app.Fragment getItem(int);
+ method public boolean isViewFromObject(android.view.View, java.lang.Object);
+ }
+
+ public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+ ctor public FragmentTabHost(android.content.Context);
+ ctor public FragmentTabHost(android.content.Context, android.util.AttributeSet);
+ method public void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
+ method public void onTabChanged(java.lang.String);
+ method public void setup(android.content.Context, android.support.v4.app.FragmentManager);
+ method public void setup(android.content.Context, android.support.v4.app.FragmentManager, int);
+ }
+
+ public abstract class FragmentTransaction {
+ ctor public FragmentTransaction();
+ method public abstract android.support.v4.app.FragmentTransaction add(android.support.v4.app.Fragment, java.lang.String);
+ method public abstract android.support.v4.app.FragmentTransaction add(int, android.support.v4.app.Fragment);
+ method public abstract android.support.v4.app.FragmentTransaction add(int, android.support.v4.app.Fragment, java.lang.String);
+ method public abstract android.support.v4.app.FragmentTransaction addSharedElement(android.view.View, java.lang.String);
+ method public abstract android.support.v4.app.FragmentTransaction addToBackStack(java.lang.String);
+ method public abstract android.support.v4.app.FragmentTransaction attach(android.support.v4.app.Fragment);
+ method public abstract int commit();
+ method public abstract int commitAllowingStateLoss();
+ method public abstract android.support.v4.app.FragmentTransaction detach(android.support.v4.app.Fragment);
+ method public abstract android.support.v4.app.FragmentTransaction disallowAddToBackStack();
+ method public abstract android.support.v4.app.FragmentTransaction hide(android.support.v4.app.Fragment);
+ method public abstract boolean isAddToBackStackAllowed();
+ method public abstract boolean isEmpty();
+ method public abstract android.support.v4.app.FragmentTransaction remove(android.support.v4.app.Fragment);
+ method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment);
+ method public abstract android.support.v4.app.FragmentTransaction replace(int, android.support.v4.app.Fragment, java.lang.String);
+ method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbShortTitle(int);
+ method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
+ method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(int);
+ method public abstract android.support.v4.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
+ method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int);
+ method public abstract android.support.v4.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+ method public abstract android.support.v4.app.FragmentTransaction setTransition(int);
+ method public abstract android.support.v4.app.FragmentTransaction setTransitionStyle(int);
+ method public abstract android.support.v4.app.FragmentTransaction show(android.support.v4.app.Fragment);
+ field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+ field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+ field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+ field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+ field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+ field public static final int TRANSIT_NONE = 0; // 0x0
+ field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+ }
+
+ public class ListFragment extends android.support.v4.app.Fragment {
+ ctor public ListFragment();
+ method public android.widget.ListAdapter getListAdapter();
+ method public android.widget.ListView getListView();
+ method public long getSelectedItemId();
+ method public int getSelectedItemPosition();
+ method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+ method public void setEmptyText(java.lang.CharSequence);
+ method public void setListAdapter(android.widget.ListAdapter);
+ method public void setListShown(boolean);
+ method public void setListShownNoAnimation(boolean);
+ method public void setSelection(int);
+ }
+
+ public abstract class LoaderManager {
+ ctor public LoaderManager();
+ method public abstract void destroyLoader(int);
+ method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public static void enableDebugLogging(boolean);
+ method public abstract android.support.v4.content.Loader<D> getLoader(int);
+ method public boolean hasRunningLoaders();
+ method public abstract android.support.v4.content.Loader<D> initLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+ method public abstract android.support.v4.content.Loader<D> restartLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+ }
+
+ public static abstract interface LoaderManager.LoaderCallbacks {
+ method public abstract android.support.v4.content.Loader<D> onCreateLoader(int, android.os.Bundle);
+ method public abstract void onLoadFinished(android.support.v4.content.Loader<D>, D);
+ method public abstract void onLoaderReset(android.support.v4.content.Loader<D>);
+ }
+
+ public class NavUtils {
+ method public static android.content.Intent getParentActivityIntent(android.app.Activity);
+ method public static android.content.Intent getParentActivityIntent(android.content.Context, java.lang.Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static android.content.Intent getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static java.lang.String getParentActivityName(android.app.Activity);
+ method public static java.lang.String getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public static void navigateUpFromSameTask(android.app.Activity);
+ method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+ method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+ field public static final java.lang.String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+ }
+
+ public class NotificationCompat {
+ ctor public NotificationCompat();
+ method public static android.support.v4.app.NotificationCompat.Action getAction(android.app.Notification, int);
+ method public static int getActionCount(android.app.Notification);
+ method public static java.lang.String getCategory(android.app.Notification);
+ method public static android.os.Bundle getExtras(android.app.Notification);
+ method public static java.lang.String getGroup(android.app.Notification);
+ method public static boolean getLocalOnly(android.app.Notification);
+ method public static java.lang.String getSortKey(android.app.Notification);
+ method public static boolean isGroupSummary(android.app.Notification);
+ field public static final java.lang.String CATEGORY_ALARM = "alarm";
+ field public static final java.lang.String CATEGORY_CALL = "call";
+ field public static final java.lang.String CATEGORY_EMAIL = "email";
+ field public static final java.lang.String CATEGORY_ERROR = "err";
+ field public static final java.lang.String CATEGORY_EVENT = "event";
+ field public static final java.lang.String CATEGORY_MESSAGE = "msg";
+ field public static final java.lang.String CATEGORY_PROGRESS = "progress";
+ field public static final java.lang.String CATEGORY_PROMO = "promo";
+ field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
+ field public static final java.lang.String CATEGORY_SERVICE = "service";
+ field public static final java.lang.String CATEGORY_SOCIAL = "social";
+ field public static final java.lang.String CATEGORY_STATUS = "status";
+ field public static final java.lang.String CATEGORY_SYSTEM = "sys";
+ field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
+ field public static final int COLOR_DEFAULT = 0; // 0x0
+ field public static final int DEFAULT_ALL = -1; // 0xffffffff
+ field public static final int DEFAULT_LIGHTS = 4; // 0x4
+ field public static final int DEFAULT_SOUND = 1; // 0x1
+ field public static final int DEFAULT_VIBRATE = 2; // 0x2
+ field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+ field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+ field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
+ field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
+ field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+ field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession";
+ field public static final java.lang.String EXTRA_PEOPLE = "android.people";
+ field public static final java.lang.String EXTRA_PICTURE = "android.picture";
+ field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
+ field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+ field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+ field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
+ field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
+ field public static final java.lang.String EXTRA_SUB_TEXT = "android.subText";
+ field public static final java.lang.String EXTRA_SUMMARY_TEXT = "android.summaryText";
+ field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
+ field public static final java.lang.String EXTRA_TEXT = "android.text";
+ field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
+ field public static final java.lang.String EXTRA_TITLE = "android.title";
+ field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
+ field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+ field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+ field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+ field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80
+ field public static final int FLAG_INSISTENT = 4; // 0x4
+ field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+ field public static final int FLAG_NO_CLEAR = 32; // 0x20
+ field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+ field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+ field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int PRIORITY_DEFAULT = 0; // 0x0
+ field public static final int PRIORITY_HIGH = 1; // 0x1
+ field public static final int PRIORITY_LOW = -1; // 0xffffffff
+ field public static final int PRIORITY_MAX = 2; // 0x2
+ field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+ field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+ field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+ field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+ field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+ }
+
+ public static class NotificationCompat.Action extends android.support.v4.app.NotificationCompatBase.Action {
+ ctor public NotificationCompat.Action(int, java.lang.CharSequence, android.app.PendingIntent);
+ method public android.app.PendingIntent getActionIntent();
+ method public android.os.Bundle getExtras();
+ method public int getIcon();
+ method public android.support.v4.app.RemoteInput[] getRemoteInputs();
+ method public java.lang.CharSequence getTitle();
+ field public android.app.PendingIntent actionIntent;
+ field public int icon;
+ field public java.lang.CharSequence title;
+ }
+
+ public static final class NotificationCompat.Action.Builder {
+ ctor public NotificationCompat.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public NotificationCompat.Action.Builder(android.support.v4.app.NotificationCompat.Action);
+ method public android.support.v4.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle);
+ method public android.support.v4.app.NotificationCompat.Action.Builder addRemoteInput(android.support.v4.app.RemoteInput);
+ method public android.support.v4.app.NotificationCompat.Action build();
+ method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Extender);
+ method public android.os.Bundle getExtras();
+ }
+
+ public static abstract interface NotificationCompat.Action.Extender {
+ method public abstract android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
+ }
+
+ public static final class NotificationCompat.Action.WearableExtender implements android.support.v4.app.NotificationCompat.Action.Extender {
+ ctor public NotificationCompat.Action.WearableExtender();
+ ctor public NotificationCompat.Action.WearableExtender(android.support.v4.app.NotificationCompat.Action);
+ method public android.support.v4.app.NotificationCompat.Action.WearableExtender clone();
+ method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
+ method public java.lang.CharSequence getCancelLabel();
+ method public java.lang.CharSequence getConfirmLabel();
+ method public java.lang.CharSequence getInProgressLabel();
+ method public boolean isAvailableOffline();
+ method public android.support.v4.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+ method public android.support.v4.app.NotificationCompat.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
+ }
+
+ public static class NotificationCompat.BigPictureStyle extends android.support.v4.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigPictureStyle();
+ ctor public NotificationCompat.BigPictureStyle(android.support.v4.app.NotificationCompat.Builder);
+ method public android.support.v4.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
+ method public android.support.v4.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap);
+ method public android.support.v4.app.NotificationCompat.BigPictureStyle setBigContentTitle(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.BigPictureStyle setSummaryText(java.lang.CharSequence);
+ }
+
+ public static class NotificationCompat.BigTextStyle extends android.support.v4.app.NotificationCompat.Style {
+ ctor public NotificationCompat.BigTextStyle();
+ ctor public NotificationCompat.BigTextStyle(android.support.v4.app.NotificationCompat.Builder);
+ method public android.support.v4.app.NotificationCompat.BigTextStyle bigText(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.BigTextStyle setBigContentTitle(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.BigTextStyle setSummaryText(java.lang.CharSequence);
+ }
+
+ public static class NotificationCompat.Builder {
+ ctor public NotificationCompat.Builder(android.content.Context);
+ method public android.support.v4.app.NotificationCompat.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+ method public android.support.v4.app.NotificationCompat.Builder addAction(android.support.v4.app.NotificationCompat.Action);
+ method public android.support.v4.app.NotificationCompat.Builder addExtras(android.os.Bundle);
+ method public android.support.v4.app.NotificationCompat.Builder addPerson(java.lang.String);
+ method public android.app.Notification build();
+ method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Extender);
+ method public android.os.Bundle getExtras();
+ method public deprecated android.app.Notification getNotification();
+ method protected static java.lang.CharSequence limitCharSequenceLength(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.Builder setAutoCancel(boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setCategory(java.lang.String);
+ method public android.support.v4.app.NotificationCompat.Builder setColor(int);
+ method public android.support.v4.app.NotificationCompat.Builder setContent(android.widget.RemoteViews);
+ method public android.support.v4.app.NotificationCompat.Builder setContentInfo(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent);
+ method public android.support.v4.app.NotificationCompat.Builder setContentText(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.Builder setContentTitle(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.Builder setDefaults(int);
+ method public android.support.v4.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent);
+ method public android.support.v4.app.NotificationCompat.Builder setExtras(android.os.Bundle);
+ method public android.support.v4.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setGroup(java.lang.String);
+ method public android.support.v4.app.NotificationCompat.Builder setGroupSummary(boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap);
+ method public android.support.v4.app.NotificationCompat.Builder setLights(int, int, int);
+ method public android.support.v4.app.NotificationCompat.Builder setLocalOnly(boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setNumber(int);
+ method public android.support.v4.app.NotificationCompat.Builder setOngoing(boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setPriority(int);
+ method public android.support.v4.app.NotificationCompat.Builder setProgress(int, int, boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setPublicVersion(android.app.Notification);
+ method public android.support.v4.app.NotificationCompat.Builder setShowWhen(boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setSmallIcon(int);
+ method public android.support.v4.app.NotificationCompat.Builder setSmallIcon(int, int);
+ method public android.support.v4.app.NotificationCompat.Builder setSortKey(java.lang.String);
+ method public android.support.v4.app.NotificationCompat.Builder setSound(android.net.Uri);
+ method public android.support.v4.app.NotificationCompat.Builder setSound(android.net.Uri, int);
+ method public android.support.v4.app.NotificationCompat.Builder setStyle(android.support.v4.app.NotificationCompat.Style);
+ method public android.support.v4.app.NotificationCompat.Builder setSubText(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.Builder setTicker(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+ method public android.support.v4.app.NotificationCompat.Builder setUsesChronometer(boolean);
+ method public android.support.v4.app.NotificationCompat.Builder setVibrate(long[]);
+ method public android.support.v4.app.NotificationCompat.Builder setVisibility(int);
+ method public android.support.v4.app.NotificationCompat.Builder setWhen(long);
+ field public java.util.ArrayList<java.lang.String> mPeople;
+ }
+
+ public static final class NotificationCompat.CarExtender implements android.support.v4.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.CarExtender();
+ ctor public NotificationCompat.CarExtender(android.app.Notification);
+ method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+ method public int getColor();
+ method public android.graphics.Bitmap getLargeIcon();
+ method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation getUnreadConversation();
+ method public android.support.v4.app.NotificationCompat.CarExtender setColor(int);
+ method public android.support.v4.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap);
+ method public android.support.v4.app.NotificationCompat.CarExtender setUnreadConversation(android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation);
+ }
+
+ public static class NotificationCompat.CarExtender.UnreadConversation extends android.support.v4.app.NotificationCompatBase.UnreadConversation {
+ method public long getLatestTimestamp();
+ method public java.lang.String[] getMessages();
+ method public java.lang.String getParticipant();
+ method public java.lang.String[] getParticipants();
+ method public android.app.PendingIntent getReadPendingIntent();
+ method public android.support.v4.app.RemoteInput getRemoteInput();
+ method public android.app.PendingIntent getReplyPendingIntent();
+ }
+
+ public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(java.lang.String);
+ method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(java.lang.String);
+ method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation build();
+ method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+ method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent);
+ method public android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent, android.support.v4.app.RemoteInput);
+ }
+
+ public static abstract interface NotificationCompat.Extender {
+ method public abstract android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+ }
+
+ public static class NotificationCompat.InboxStyle extends android.support.v4.app.NotificationCompat.Style {
+ ctor public NotificationCompat.InboxStyle();
+ ctor public NotificationCompat.InboxStyle(android.support.v4.app.NotificationCompat.Builder);
+ method public android.support.v4.app.NotificationCompat.InboxStyle addLine(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.InboxStyle setBigContentTitle(java.lang.CharSequence);
+ method public android.support.v4.app.NotificationCompat.InboxStyle setSummaryText(java.lang.CharSequence);
+ }
+
+ public static abstract class NotificationCompat.Style {
+ ctor public NotificationCompat.Style();
+ method public android.app.Notification build();
+ method public void setBuilder(android.support.v4.app.NotificationCompat.Builder);
+ }
+
+ public static final class NotificationCompat.WearableExtender implements android.support.v4.app.NotificationCompat.Extender {
+ ctor public NotificationCompat.WearableExtender();
+ ctor public NotificationCompat.WearableExtender(android.app.Notification);
+ method public android.support.v4.app.NotificationCompat.WearableExtender addAction(android.support.v4.app.NotificationCompat.Action);
+ method public android.support.v4.app.NotificationCompat.WearableExtender addActions(java.util.List<android.support.v4.app.NotificationCompat.Action>);
+ method public android.support.v4.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+ method public android.support.v4.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification>);
+ method public android.support.v4.app.NotificationCompat.WearableExtender clearActions();
+ method public android.support.v4.app.NotificationCompat.WearableExtender clearPages();
+ method public android.support.v4.app.NotificationCompat.WearableExtender clone();
+ method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Builder);
+ method public java.util.List<android.support.v4.app.NotificationCompat.Action> getActions();
+ method public android.graphics.Bitmap getBackground();
+ method public int getContentAction();
+ method public int getContentIcon();
+ method public int getContentIconGravity();
+ method public boolean getContentIntentAvailableOffline();
+ method public int getCustomContentHeight();
+ method public int getCustomSizePreset();
+ method public android.app.PendingIntent getDisplayIntent();
+ method public int getGravity();
+ method public boolean getHintAvoidBackgroundClipping();
+ method public boolean getHintHideIcon();
+ method public int getHintScreenTimeout();
+ method public boolean getHintShowBackgroundOnly();
+ method public java.util.List<android.app.Notification> getPages();
+ method public boolean getStartScrollBottom();
+ method public android.support.v4.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setContentAction(int);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setContentIcon(int);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setGravity(int);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+ method public android.support.v4.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+ field public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+ field public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+ field public static final int SIZE_DEFAULT = 0; // 0x0
+ field public static final int SIZE_FULL_SCREEN = 5; // 0x5
+ field public static final int SIZE_LARGE = 4; // 0x4
+ field public static final int SIZE_MEDIUM = 3; // 0x3
+ field public static final int SIZE_SMALL = 2; // 0x2
+ field public static final int SIZE_XSMALL = 1; // 0x1
+ field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+ }
+
+ public class NotificationCompatBase {
+ ctor public NotificationCompatBase();
+ }
+
+ public static abstract class NotificationCompatBase.Action {
+ ctor public NotificationCompatBase.Action();
+ method public abstract android.app.PendingIntent getActionIntent();
+ method public abstract android.os.Bundle getExtras();
+ method public abstract int getIcon();
+ method public abstract android.support.v4.app.RemoteInputCompatBase.RemoteInput[] getRemoteInputs();
+ method public abstract java.lang.CharSequence getTitle();
+ }
+
+ public static abstract class NotificationCompatBase.UnreadConversation {
+ ctor public NotificationCompatBase.UnreadConversation();
+ }
+
+ public final class NotificationCompatExtras {
+ field public static final java.lang.String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+ field public static final java.lang.String EXTRA_GROUP_KEY = "android.support.groupKey";
+ field public static final java.lang.String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+ field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+ field public static final java.lang.String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+ field public static final java.lang.String EXTRA_SORT_KEY = "android.support.sortKey";
+ }
+
+ public abstract class NotificationCompatSideChannelService extends android.app.Service {
+ ctor public NotificationCompatSideChannelService();
+ method public abstract void cancel(java.lang.String, int, java.lang.String);
+ method public abstract void cancelAll(java.lang.String);
+ method public abstract void notify(java.lang.String, int, java.lang.String, android.app.Notification);
+ method public android.os.IBinder onBind(android.content.Intent);
+ }
+
+ public class NotificationManagerCompat {
+ method public void cancel(int);
+ method public void cancel(java.lang.String, int);
+ method public void cancelAll();
+ method public static android.support.v4.app.NotificationManagerCompat from(android.content.Context);
+ method public static java.util.Set<java.lang.String> getEnabledListenerPackages(android.content.Context);
+ method public void notify(int, android.app.Notification);
+ method public void notify(java.lang.String, int, android.app.Notification);
+ field public static final java.lang.String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+ field public static final java.lang.String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+ }
+
+ public class RemoteInput extends android.support.v4.app.RemoteInputCompatBase.RemoteInput {
+ method public static void addResultsToIntent(android.support.v4.app.RemoteInput[], android.content.Intent, android.os.Bundle);
+ method public boolean getAllowFreeFormInput();
+ method public java.lang.CharSequence[] getChoices();
+ method public android.os.Bundle getExtras();
+ method public java.lang.CharSequence getLabel();
+ method public java.lang.String getResultKey();
+ method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+ field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+ field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+ }
+
+ public static final class RemoteInput.Builder {
+ ctor public RemoteInput.Builder(java.lang.String);
+ method public android.support.v4.app.RemoteInput.Builder addExtras(android.os.Bundle);
+ method public android.support.v4.app.RemoteInput build();
+ method public android.os.Bundle getExtras();
+ method public android.support.v4.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+ method public android.support.v4.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
+ method public android.support.v4.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
+ }
+
+ class RemoteInputCompatBase {
+ }
+
+ public static abstract class RemoteInputCompatBase.RemoteInput {
+ ctor public RemoteInputCompatBase.RemoteInput();
+ method protected abstract boolean getAllowFreeFormInput();
+ method protected abstract java.lang.CharSequence[] getChoices();
+ method protected abstract android.os.Bundle getExtras();
+ method protected abstract java.lang.CharSequence getLabel();
+ method protected abstract java.lang.String getResultKey();
+ }
+
+ public class ServiceCompat {
+ field public static final int START_STICKY = 1; // 0x1
+ }
+
+ public class ShareCompat {
+ ctor public ShareCompat();
+ method public static void configureMenuItem(android.view.MenuItem, android.support.v4.app.ShareCompat.IntentBuilder);
+ method public static void configureMenuItem(android.view.Menu, int, android.support.v4.app.ShareCompat.IntentBuilder);
+ method public static android.content.ComponentName getCallingActivity(android.app.Activity);
+ method public static java.lang.String getCallingPackage(android.app.Activity);
+ field public static final java.lang.String EXTRA_CALLING_ACTIVITY = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+ field public static final java.lang.String EXTRA_CALLING_PACKAGE = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+ }
+
+ public static class ShareCompat.IntentBuilder {
+ method public android.support.v4.app.ShareCompat.IntentBuilder addEmailBcc(java.lang.String);
+ method public android.support.v4.app.ShareCompat.IntentBuilder addEmailBcc(java.lang.String[]);
+ method public android.support.v4.app.ShareCompat.IntentBuilder addEmailCc(java.lang.String);
+ method public android.support.v4.app.ShareCompat.IntentBuilder addEmailCc(java.lang.String[]);
+ method public android.support.v4.app.ShareCompat.IntentBuilder addEmailTo(java.lang.String);
+ method public android.support.v4.app.ShareCompat.IntentBuilder addEmailTo(java.lang.String[]);
+ method public android.support.v4.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+ method public android.content.Intent createChooserIntent();
+ method public static android.support.v4.app.ShareCompat.IntentBuilder from(android.app.Activity);
+ method public android.content.Intent getIntent();
+ method public android.support.v4.app.ShareCompat.IntentBuilder setChooserTitle(java.lang.CharSequence);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setChooserTitle(int);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setEmailBcc(java.lang.String[]);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setEmailCc(java.lang.String[]);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setEmailTo(java.lang.String[]);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setHtmlText(java.lang.String);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setStream(android.net.Uri);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setSubject(java.lang.String);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setText(java.lang.CharSequence);
+ method public android.support.v4.app.ShareCompat.IntentBuilder setType(java.lang.String);
+ method public void startChooser();
+ }
+
+ public static class ShareCompat.IntentReader {
+ method public static android.support.v4.app.ShareCompat.IntentReader from(android.app.Activity);
+ method public android.content.ComponentName getCallingActivity();
+ method public android.graphics.drawable.Drawable getCallingActivityIcon();
+ method public android.graphics.drawable.Drawable getCallingApplicationIcon();
+ method public java.lang.CharSequence getCallingApplicationLabel();
+ method public java.lang.String getCallingPackage();
+ method public java.lang.String[] getEmailBcc();
+ method public java.lang.String[] getEmailCc();
+ method public java.lang.String[] getEmailTo();
+ method public java.lang.String getHtmlText();
+ method public android.net.Uri getStream();
+ method public android.net.Uri getStream(int);
+ method public int getStreamCount();
+ method public java.lang.String getSubject();
+ method public java.lang.CharSequence getText();
+ method public java.lang.String getType();
+ method public boolean isMultipleShare();
+ method public boolean isShareIntent();
+ method public boolean isSingleShare();
+ }
+
+ public abstract class SharedElementCallback {
+ ctor public SharedElementCallback();
+ method public android.os.Parcelable onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, android.graphics.RectF);
+ method public android.view.View onCreateSnapshotView(android.content.Context, android.os.Parcelable);
+ method public void onMapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>);
+ method public void onRejectSharedElements(java.util.List<android.view.View>);
+ method public void onSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+ method public void onSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+ }
+
+ public class TaskStackBuilder implements java.lang.Iterable {
+ method public android.support.v4.app.TaskStackBuilder addNextIntent(android.content.Intent);
+ method public android.support.v4.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+ method public android.support.v4.app.TaskStackBuilder addParentStack(android.app.Activity);
+ method public android.support.v4.app.TaskStackBuilder addParentStack(java.lang.Class<?>);
+ method public android.support.v4.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+ method public static android.support.v4.app.TaskStackBuilder create(android.content.Context);
+ method public android.content.Intent editIntentAt(int);
+ method public static deprecated android.support.v4.app.TaskStackBuilder from(android.content.Context);
+ method public deprecated android.content.Intent getIntent(int);
+ method public int getIntentCount();
+ method public android.content.Intent[] getIntents();
+ method public android.app.PendingIntent getPendingIntent(int, int);
+ method public android.app.PendingIntent getPendingIntent(int, int, android.os.Bundle);
+ method public deprecated java.util.Iterator<android.content.Intent> iterator();
+ method public void startActivities();
+ method public void startActivities(android.os.Bundle);
+ }
+
+ public static abstract interface TaskStackBuilder.SupportParentable {
+ method public abstract android.content.Intent getSupportParentActivityIntent();
+ }
+
+}
+
+package android.support.v4.content {
+
+ public abstract class AsyncTaskLoader extends android.support.v4.content.Loader {
+ ctor public AsyncTaskLoader(android.content.Context);
+ method public void cancelLoadInBackground();
+ method public boolean isLoadInBackgroundCanceled();
+ method public abstract D loadInBackground();
+ method public void onCanceled(D);
+ method protected D onLoadInBackground();
+ method public void setUpdateThrottle(long);
+ }
+
+ public class ContentResolverCompat {
+ method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.support.v4.os.CancellationSignal);
+ }
+
+ public class ContextCompat {
+ ctor public ContextCompat();
+ method public static int checkSelfPermission(android.content.Context, java.lang.String);
+ method public final java.io.File getCodeCacheDir(android.content.Context);
+ method public static final int getColor(android.content.Context, int);
+ method public static final android.content.res.ColorStateList getColorStateList(android.content.Context, int);
+ method public static final android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
+ method public static java.io.File[] getExternalCacheDirs(android.content.Context);
+ method public static java.io.File[] getExternalFilesDirs(android.content.Context, java.lang.String);
+ method public final java.io.File getNoBackupFilesDir(android.content.Context);
+ method public static java.io.File[] getObbDirs(android.content.Context);
+ method public static boolean startActivities(android.content.Context, android.content.Intent[]);
+ method public static boolean startActivities(android.content.Context, android.content.Intent[], android.os.Bundle);
+ }
+
+ public class CursorLoader extends android.support.v4.content.AsyncTaskLoader {
+ ctor public CursorLoader(android.content.Context);
+ ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public void deliverResult(android.database.Cursor);
+ method public java.lang.String[] getProjection();
+ method public java.lang.String getSelection();
+ method public java.lang.String[] getSelectionArgs();
+ method public java.lang.String getSortOrder();
+ method public android.net.Uri getUri();
+ method public android.database.Cursor loadInBackground();
+ method public void onCanceled(android.database.Cursor);
+ method public void setProjection(java.lang.String[]);
+ method public void setSelection(java.lang.String);
+ method public void setSelectionArgs(java.lang.String[]);
+ method public void setSortOrder(java.lang.String);
+ method public void setUri(android.net.Uri);
+ }
+
+ public class FileProvider extends android.content.ContentProvider {
+ ctor public FileProvider();
+ method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+ method public java.lang.String getType(android.net.Uri);
+ method public static android.net.Uri getUriForFile(android.content.Context, java.lang.String, java.io.File);
+ method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+ method public boolean onCreate();
+ method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+ }
+
+ public class IntentCompat {
+ method public static android.content.Intent makeMainActivity(android.content.ComponentName);
+ method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
+ method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName);
+ field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
+ field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
+ field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
+ field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+ field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+ field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
+ field public static final int FLAG_ACTIVITY_TASK_ON_HOME = 16384; // 0x4000
+ }
+
+ public class Loader {
+ ctor public Loader(android.content.Context);
+ method public void abandon();
+ method public boolean cancelLoad();
+ method public void commitContentChanged();
+ method public java.lang.String dataToString(D);
+ method public void deliverCancellation();
+ method public void deliverResult(D);
+ method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public void forceLoad();
+ method public android.content.Context getContext();
+ method public int getId();
+ method public boolean isAbandoned();
+ method public boolean isReset();
+ method public boolean isStarted();
+ method protected void onAbandon();
+ method protected boolean onCancelLoad();
+ method public void onContentChanged();
+ method protected void onForceLoad();
+ method protected void onReset();
+ method protected void onStartLoading();
+ method protected void onStopLoading();
+ method public void registerListener(int, android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+ method public void registerOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+ method public void reset();
+ method public void rollbackContentChanged();
+ method public final void startLoading();
+ method public void stopLoading();
+ method public boolean takeContentChanged();
+ method public void unregisterListener(android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+ method public void unregisterOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+ }
+
+ public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+ ctor public Loader.ForceLoadContentObserver();
+ }
+
+ public static abstract interface Loader.OnLoadCanceledListener {
+ method public abstract void onLoadCanceled(android.support.v4.content.Loader<D>);
+ }
+
+ public static abstract interface Loader.OnLoadCompleteListener {
+ method public abstract void onLoadComplete(android.support.v4.content.Loader<D>, D);
+ }
+
+ public class LocalBroadcastManager {
+ method public static android.support.v4.content.LocalBroadcastManager getInstance(android.content.Context);
+ method public void registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
+ method public boolean sendBroadcast(android.content.Intent);
+ method public void sendBroadcastSync(android.content.Intent);
+ method public void unregisterReceiver(android.content.BroadcastReceiver);
+ }
+
+ public class ParallelExecutorCompat {
+ ctor public ParallelExecutorCompat();
+ method public static java.util.concurrent.Executor getParallelExecutor();
+ }
+
+ public final class PermissionChecker {
+ method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
+ method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
+ method public static int checkPermission(android.content.Context, java.lang.String, int, int, java.lang.String);
+ method public static int checkSelfPermission(android.content.Context, java.lang.String);
+ field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+ field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+ field public static final int PERMISSION_GRANTED = 0; // 0x0
+ }
+
+ public static abstract class PermissionChecker.PermissionResult implements java.lang.annotation.Annotation {
+ }
+
+ public class SharedPreferencesCompat {
+ ctor public SharedPreferencesCompat();
+ }
+
+ public static class SharedPreferencesCompat.EditorCompat {
+ method public void apply(android.content.SharedPreferences.Editor);
+ method public static android.support.v4.content.SharedPreferencesCompat.EditorCompat getInstance();
+ }
+
+ public abstract class WakefulBroadcastReceiver extends android.content.BroadcastReceiver {
+ ctor public WakefulBroadcastReceiver();
+ method public static boolean completeWakefulIntent(android.content.Intent);
+ method public static android.content.ComponentName startWakefulService(android.content.Context, android.content.Intent);
+ }
+
+}
+
+package android.support.v4.content.pm {
+
+ public class ActivityInfoCompat {
+ field public static final int CONFIG_UI_MODE = 512; // 0x200
+ }
+
+}
+
+package android.support.v4.content.res {
+
+ public class ResourcesCompat {
+ ctor public ResourcesCompat();
+ method public int getColor(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+ method public android.content.res.ColorStateList getColorStateList(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable getDrawable(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+ method public static android.graphics.drawable.Drawable getDrawableForDensity(android.content.res.Resources, int, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+ }
+
+}
+
+package android.support.v4.database {
+
+ public class DatabaseUtilsCompat {
+ method public static java.lang.String[] appendSelectionArgs(java.lang.String[], java.lang.String[]);
+ method public static java.lang.String concatenateWhere(java.lang.String, java.lang.String);
+ }
+
+}
+
+package android.support.v4.graphics {
+
+ public class BitmapCompat {
+ ctor public BitmapCompat();
+ method public static int getAllocationByteCount(android.graphics.Bitmap);
+ method public static boolean hasMipMap(android.graphics.Bitmap);
+ method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+ }
+
+ public class ColorUtils {
+ method public static int HSLToColor(float[]);
+ method public static void RGBToHSL(int, int, int, float[]);
+ method public static double calculateContrast(int, int);
+ method public static double calculateLuminance(int);
+ method public static int calculateMinimumAlpha(int, int, float);
+ method public static void colorToHSL(int, float[]);
+ method public static int compositeColors(int, int);
+ method public static int setAlphaComponent(int, int);
+ }
+
+}
+
+package android.support.v4.graphics.drawable {
+
+ public class DrawableCompat {
+ ctor public DrawableCompat();
+ method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+ method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+ method public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+ method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+ method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+ method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+ method public static void setLayoutDirection(android.graphics.drawable.Drawable, int);
+ method public static void setTint(android.graphics.drawable.Drawable, int);
+ method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList);
+ method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+ method public static T unwrap(android.graphics.drawable.Drawable);
+ method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
+ }
+
+ public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+ method public void draw(android.graphics.Canvas);
+ method public final android.graphics.Bitmap getBitmap();
+ method public float getCornerRadius();
+ method public int getGravity();
+ method public int getOpacity();
+ method public final android.graphics.Paint getPaint();
+ method public boolean hasAntiAlias();
+ method public boolean hasMipMap();
+ method public boolean isCircular();
+ method public void setAlpha(int);
+ method public void setAntiAlias(boolean);
+ method public void setCircular(boolean);
+ method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setCornerRadius(float);
+ method public void setGravity(int);
+ method public void setMipMap(boolean);
+ method public void setTargetDensity(android.graphics.Canvas);
+ method public void setTargetDensity(android.util.DisplayMetrics);
+ method public void setTargetDensity(int);
+ }
+
+ public class RoundedBitmapDrawableFactory {
+ ctor public RoundedBitmapDrawableFactory();
+ method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap);
+ method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.lang.String);
+ method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+ }
+
+}
+
+package android.support.v4.hardware.display {
+
+ public abstract class DisplayManagerCompat {
+ method public abstract android.view.Display getDisplay(int);
+ method public abstract android.view.Display[] getDisplays();
+ method public abstract android.view.Display[] getDisplays(java.lang.String);
+ method public static android.support.v4.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+ field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+ }
+
+}
+
+package android.support.v4.hardware.fingerprint {
+
+ public class FingerprintManagerCompat {
+ method public void authenticate(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject, int, android.support.v4.os.CancellationSignal, android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler);
+ method public static android.support.v4.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+ method public boolean hasEnrolledFingerprints();
+ method public boolean isHardwareDetected();
+ }
+
+ public static abstract class FingerprintManagerCompat.AuthenticationCallback {
+ ctor public FingerprintManagerCompat.AuthenticationCallback();
+ method public void onAuthenticationError(int, java.lang.CharSequence);
+ method public void onAuthenticationFailed();
+ method public void onAuthenticationHelp(int, java.lang.CharSequence);
+ method public void onAuthenticationSucceeded(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult);
+ }
+
+ public static final class FingerprintManagerCompat.AuthenticationResult {
+ ctor public FingerprintManagerCompat.AuthenticationResult(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject);
+ method public android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject getCryptoObject();
+ }
+
+ public static class FingerprintManagerCompat.CryptoObject {
+ ctor public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+ ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+ ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+ method public javax.crypto.Cipher getCipher();
+ method public javax.crypto.Mac getMac();
+ method public java.security.Signature getSignature();
+ }
+
+}
+
+package android.support.v4.media {
+
+ public final class MediaDescriptionCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.MediaDescriptionCompat fromMediaDescription(java.lang.Object);
+ method public java.lang.CharSequence getDescription();
+ method public android.os.Bundle getExtras();
+ method public android.graphics.Bitmap getIconBitmap();
+ method public android.net.Uri getIconUri();
+ method public java.lang.Object getMediaDescription();
+ method public java.lang.String getMediaId();
+ method public android.net.Uri getMediaUri();
+ method public java.lang.CharSequence getSubtitle();
+ method public java.lang.CharSequence getTitle();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat> CREATOR;
+ }
+
+ public static final class MediaDescriptionCompat.Builder {
+ ctor public MediaDescriptionCompat.Builder();
+ method public android.support.v4.media.MediaDescriptionCompat build();
+ method public android.support.v4.media.MediaDescriptionCompat.Builder setDescription(java.lang.CharSequence);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder setExtras(android.os.Bundle);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder setIconBitmap(android.graphics.Bitmap);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder setIconUri(android.net.Uri);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaId(java.lang.String);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaUri(android.net.Uri);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder setSubtitle(java.lang.CharSequence);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder setTitle(java.lang.CharSequence);
+ }
+
+ public final class MediaMetadataCompat implements android.os.Parcelable {
+ method public boolean containsKey(java.lang.String);
+ method public int describeContents();
+ method public static android.support.v4.media.MediaMetadataCompat fromMediaMetadata(java.lang.Object);
+ method public android.graphics.Bitmap getBitmap(java.lang.String);
+ method public android.os.Bundle getBundle();
+ method public android.support.v4.media.MediaDescriptionCompat getDescription();
+ method public long getLong(java.lang.String);
+ method public java.lang.Object getMediaMetadata();
+ method public android.support.v4.media.RatingCompat getRating(java.lang.String);
+ method public java.lang.String getString(java.lang.String);
+ method public java.lang.CharSequence getText(java.lang.String);
+ method public java.util.Set<java.lang.String> keySet();
+ method public int size();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat> CREATOR;
+ field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+ field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
+ field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+ field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+ field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+ field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+ field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+ field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
+ field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+ field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+ field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+ field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+ field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+ field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+ field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
+ field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+ field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+ field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+ field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+ field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+ }
+
+ public static final class MediaMetadataCompat.Builder {
+ ctor public MediaMetadataCompat.Builder();
+ ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat);
+ method public android.support.v4.media.MediaMetadataCompat build();
+ method public android.support.v4.media.MediaMetadataCompat.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
+ method public android.support.v4.media.MediaMetadataCompat.Builder putLong(java.lang.String, long);
+ method public android.support.v4.media.MediaMetadataCompat.Builder putRating(java.lang.String, android.support.v4.media.RatingCompat);
+ method public android.support.v4.media.MediaMetadataCompat.Builder putString(java.lang.String, java.lang.String);
+ method public android.support.v4.media.MediaMetadataCompat.Builder putText(java.lang.String, java.lang.CharSequence);
+ }
+
+ public final class RatingCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.RatingCompat fromRating(java.lang.Object);
+ method public float getPercentRating();
+ method public java.lang.Object getRating();
+ method public int getRatingStyle();
+ method public float getStarRating();
+ method public boolean hasHeart();
+ method public boolean isRated();
+ method public boolean isThumbUp();
+ method public static android.support.v4.media.RatingCompat newHeartRating(boolean);
+ method public static android.support.v4.media.RatingCompat newPercentageRating(float);
+ method public static android.support.v4.media.RatingCompat newStarRating(int, float);
+ method public static android.support.v4.media.RatingCompat newThumbRating(boolean);
+ method public static android.support.v4.media.RatingCompat newUnratedRating(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat> CREATOR;
+ field public static final int RATING_3_STARS = 3; // 0x3
+ field public static final int RATING_4_STARS = 4; // 0x4
+ field public static final int RATING_5_STARS = 5; // 0x5
+ field public static final int RATING_HEART = 1; // 0x1
+ field public static final int RATING_NONE = 0; // 0x0
+ field public static final int RATING_PERCENTAGE = 6; // 0x6
+ field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+ }
+
+ public abstract class TransportController {
+ ctor public TransportController();
+ method public abstract int getBufferPercentage();
+ method public abstract long getCurrentPosition();
+ method public abstract long getDuration();
+ method public abstract int getTransportControlFlags();
+ method public abstract boolean isPlaying();
+ method public abstract void pausePlaying();
+ method public abstract void registerStateListener(android.support.v4.media.TransportStateListener);
+ method public abstract void seekTo(long);
+ method public abstract void startPlaying();
+ method public abstract void stopPlaying();
+ method public abstract void unregisterStateListener(android.support.v4.media.TransportStateListener);
+ }
+
+ public class TransportMediator extends android.support.v4.media.TransportController {
+ ctor public TransportMediator(android.app.Activity, android.support.v4.media.TransportPerformer);
+ ctor public TransportMediator(android.view.View, android.support.v4.media.TransportPerformer);
+ method public void destroy();
+ method public boolean dispatchKeyEvent(android.view.KeyEvent);
+ method public int getBufferPercentage();
+ method public long getCurrentPosition();
+ method public long getDuration();
+ method public java.lang.Object getRemoteControlClient();
+ method public int getTransportControlFlags();
+ method public boolean isPlaying();
+ method public void pausePlaying();
+ method public void refreshState();
+ method public void registerStateListener(android.support.v4.media.TransportStateListener);
+ method public void seekTo(long);
+ method public void startPlaying();
+ method public void stopPlaying();
+ method public void unregisterStateListener(android.support.v4.media.TransportStateListener);
+ field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
+ field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
+ field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
+ field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
+ field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+ field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+ field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
+ field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
+ field public static final int KEYCODE_MEDIA_PAUSE = 127; // 0x7f
+ field public static final int KEYCODE_MEDIA_PLAY = 126; // 0x7e
+ field public static final int KEYCODE_MEDIA_RECORD = 130; // 0x82
+ }
+
+ public abstract class TransportPerformer {
+ ctor public TransportPerformer();
+ method public void onAudioFocusChange(int);
+ method public int onGetBufferPercentage();
+ method public abstract long onGetCurrentPosition();
+ method public abstract long onGetDuration();
+ method public int onGetTransportControlFlags();
+ method public abstract boolean onIsPlaying();
+ method public boolean onMediaButtonDown(int, android.view.KeyEvent);
+ method public boolean onMediaButtonUp(int, android.view.KeyEvent);
+ method public abstract void onPause();
+ method public abstract void onSeekTo(long);
+ method public abstract void onStart();
+ method public abstract void onStop();
+ }
+
+ public class TransportStateListener {
+ ctor public TransportStateListener();
+ method public void onPlayingChanged(android.support.v4.media.TransportController);
+ method public void onTransportControlsChanged(android.support.v4.media.TransportController);
+ }
+
+ public abstract class VolumeProviderCompat {
+ ctor public VolumeProviderCompat(int, int, int);
+ method public final int getCurrentVolume();
+ method public final int getMaxVolume();
+ method public final int getVolumeControl();
+ method public java.lang.Object getVolumeProvider();
+ method public void onAdjustVolume(int);
+ method public void onSetVolumeTo(int);
+ method public void setCallback(android.support.v4.media.VolumeProviderCompat.Callback);
+ method public final void setCurrentVolume(int);
+ field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+ field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+ field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+ }
+
+ public static abstract class VolumeProviderCompat.Callback {
+ ctor public VolumeProviderCompat.Callback();
+ method public abstract void onVolumeChanged(android.support.v4.media.VolumeProviderCompat);
+ }
+
+}
+
+package android.support.v4.media.session {
+
+ public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+ ctor public MediaButtonReceiver();
+ method public static android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
+ method public void onReceive(android.content.Context, android.content.Intent);
+ }
+
+ public final class MediaControllerCompat {
+ ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
+ ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
+ method public void adjustVolume(int, int);
+ method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
+ method public android.os.Bundle getExtras();
+ method public long getFlags();
+ method public java.lang.Object getMediaController();
+ method public android.support.v4.media.MediaMetadataCompat getMetadata();
+ method public java.lang.String getPackageName();
+ method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo getPlaybackInfo();
+ method public android.support.v4.media.session.PlaybackStateCompat getPlaybackState();
+ method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> getQueue();
+ method public java.lang.CharSequence getQueueTitle();
+ method public int getRatingType();
+ method public android.app.PendingIntent getSessionActivity();
+ method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+ method public android.support.v4.media.session.MediaControllerCompat.TransportControls getTransportControls();
+ method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+ method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
+ method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ method public void setVolumeTo(int, int);
+ method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+ }
+
+ public static abstract class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+ ctor public MediaControllerCompat.Callback();
+ method public void binderDied();
+ method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo);
+ method public void onExtrasChanged(android.os.Bundle);
+ method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat);
+ method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat);
+ method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
+ method public void onQueueTitleChanged(java.lang.CharSequence);
+ method public void onSessionDestroyed();
+ method public void onSessionEvent(java.lang.String, android.os.Bundle);
+ }
+
+ public static final class MediaControllerCompat.PlaybackInfo {
+ method public int getAudioStream();
+ method public int getCurrentVolume();
+ method public int getMaxVolume();
+ method public int getPlaybackType();
+ method public int getVolumeControl();
+ field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+ field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+ }
+
+ public static abstract class MediaControllerCompat.TransportControls {
+ method public abstract void fastForward();
+ method public abstract void pause();
+ method public abstract void play();
+ method public abstract void playFromMediaId(java.lang.String, android.os.Bundle);
+ method public abstract void playFromSearch(java.lang.String, android.os.Bundle);
+ method public abstract void playFromUri(android.net.Uri, android.os.Bundle);
+ method public abstract void rewind();
+ method public abstract void seekTo(long);
+ method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction, android.os.Bundle);
+ method public abstract void sendCustomAction(java.lang.String, android.os.Bundle);
+ method public abstract void setRating(android.support.v4.media.RatingCompat);
+ method public abstract void skipToNext();
+ method public abstract void skipToPrevious();
+ method public abstract void skipToQueueItem(long);
+ method public abstract void stop();
+ }
+
+ public class MediaSessionCompat {
+ ctor public MediaSessionCompat(android.content.Context, java.lang.String);
+ ctor public MediaSessionCompat(android.content.Context, java.lang.String, android.content.ComponentName, android.app.PendingIntent);
+ method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
+ method public android.support.v4.media.session.MediaControllerCompat getController();
+ method public java.lang.Object getMediaSession();
+ method public java.lang.Object getRemoteControlClient();
+ method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+ method public boolean isActive();
+ method public static android.support.v4.media.session.MediaSessionCompat obtain(android.content.Context, java.lang.Object);
+ method public void release();
+ method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
+ method public void sendSessionEvent(java.lang.String, android.os.Bundle);
+ method public void setActive(boolean);
+ method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback);
+ method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback, android.os.Handler);
+ method public void setExtras(android.os.Bundle);
+ method public void setFlags(int);
+ method public void setMediaButtonReceiver(android.app.PendingIntent);
+ method public void setMetadata(android.support.v4.media.MediaMetadataCompat);
+ method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat);
+ method public void setPlaybackToLocal(int);
+ method public void setPlaybackToRemote(android.support.v4.media.VolumeProviderCompat);
+ method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
+ method public void setQueueTitle(java.lang.CharSequence);
+ method public void setRatingType(int);
+ method public void setSessionActivity(android.app.PendingIntent);
+ field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+ }
+
+ public static abstract class MediaSessionCompat.Callback {
+ ctor public MediaSessionCompat.Callback();
+ method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ method public void onCustomAction(java.lang.String, android.os.Bundle);
+ method public void onFastForward();
+ method public boolean onMediaButtonEvent(android.content.Intent);
+ method public void onPause();
+ method public void onPlay();
+ method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
+ method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+ method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+ method public void onRewind();
+ method public void onSeekTo(long);
+ method public void onSetRating(android.support.v4.media.RatingCompat);
+ method public void onSkipToNext();
+ method public void onSkipToPrevious();
+ method public void onSkipToQueueItem(long);
+ method public void onStop();
+ }
+
+ public static abstract interface MediaSessionCompat.OnActiveChangeListener {
+ method public abstract void onActiveChanged();
+ }
+
+ public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+ ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat, long);
+ method public int describeContents();
+ method public android.support.v4.media.MediaDescriptionCompat getDescription();
+ method public long getQueueId();
+ method public java.lang.Object getQueueItem();
+ method public static android.support.v4.media.session.MediaSessionCompat.QueueItem obtain(java.lang.Object);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem> CREATOR;
+ field public static final int UNKNOWN_ID = -1; // 0xffffffff
+ }
+
+ public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.session.MediaSessionCompat.Token fromToken(java.lang.Object);
+ method public java.lang.Object getToken();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token> CREATOR;
+ }
+
+ public class ParcelableVolumeInfo implements android.os.Parcelable {
+ ctor public ParcelableVolumeInfo(int, int, int, int, int);
+ ctor public ParcelableVolumeInfo(android.os.Parcel);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo> CREATOR;
+ field public int audioStream;
+ field public int controlType;
+ field public int currentVolume;
+ field public int maxVolume;
+ field public int volumeType;
+ }
+
+ public final class PlaybackStateCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.session.PlaybackStateCompat fromPlaybackState(java.lang.Object);
+ method public long getActions();
+ method public long getActiveQueueItemId();
+ method public long getBufferedPosition();
+ method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction> getCustomActions();
+ method public java.lang.CharSequence getErrorMessage();
+ method public android.os.Bundle getExtras();
+ method public long getLastPositionUpdateTime();
+ method public float getPlaybackSpeed();
+ method public java.lang.Object getPlaybackState();
+ method public long getPosition();
+ method public int getState();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+ field public static final long ACTION_PAUSE = 2L; // 0x2L
+ field public static final long ACTION_PLAY = 4L; // 0x4L
+ field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+ field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+ field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+ field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_REWIND = 8L; // 0x8L
+ field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+ field public static final long ACTION_SET_RATING = 128L; // 0x80L
+ field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+ field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+ field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+ field public static final long ACTION_STOP = 1L; // 0x1L
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat> CREATOR;
+ field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+ field public static final int STATE_BUFFERING = 6; // 0x6
+ field public static final int STATE_CONNECTING = 8; // 0x8
+ field public static final int STATE_ERROR = 7; // 0x7
+ field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+ field public static final int STATE_NONE = 0; // 0x0
+ field public static final int STATE_PAUSED = 2; // 0x2
+ field public static final int STATE_PLAYING = 3; // 0x3
+ field public static final int STATE_REWINDING = 5; // 0x5
+ field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+ field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+ field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+ field public static final int STATE_STOPPED = 1; // 0x1
+ }
+
+ public static final class PlaybackStateCompat.Builder {
+ ctor public PlaybackStateCompat.Builder();
+ ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(java.lang.String, java.lang.String, int);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction);
+ method public android.support.v4.media.session.PlaybackStateCompat build();
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder setActions(long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder setActiveQueueItemId(long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder setBufferedPosition(long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder setErrorMessage(java.lang.CharSequence);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder setExtras(android.os.Bundle);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float, long);
+ }
+
+ public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction fromCustomAction(java.lang.Object);
+ method public java.lang.String getAction();
+ method public java.lang.Object getCustomAction();
+ method public android.os.Bundle getExtras();
+ method public int getIcon();
+ method public java.lang.CharSequence getName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction> CREATOR;
+ }
+
+ public static final class PlaybackStateCompat.CustomAction.Builder {
+ ctor public PlaybackStateCompat.CustomAction.Builder(java.lang.String, java.lang.CharSequence, int);
+ method public android.support.v4.media.session.PlaybackStateCompat.CustomAction build();
+ method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder setExtras(android.os.Bundle);
+ }
+
+}
+
+package android.support.v4.net {
+
+ public class ConnectivityManagerCompat {
+ ctor public ConnectivityManagerCompat();
+ method public static android.net.NetworkInfo getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+ method public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+ }
+
+ public class TrafficStatsCompat {
+ ctor public TrafficStatsCompat();
+ method public static void clearThreadStatsTag();
+ method public static int getThreadStatsTag();
+ method public static void incrementOperationCount(int);
+ method public static void incrementOperationCount(int, int);
+ method public static void setThreadStatsTag(int);
+ method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
+ method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
+ }
+
+}
+
+package android.support.v4.os {
+
+ public class AsyncTaskCompat {
+ ctor public AsyncTaskCompat();
+ method public static android.os.AsyncTask<Params, Progress, Result> executeParallel(android.os.AsyncTask<Params, Progress, Result>, Params...);
+ }
+
+ public final class CancellationSignal {
+ ctor public CancellationSignal();
+ method public void cancel();
+ method public java.lang.Object getCancellationSignalObject();
+ method public boolean isCanceled();
+ method public void setOnCancelListener(android.support.v4.os.CancellationSignal.OnCancelListener);
+ method public void throwIfCanceled();
+ }
+
+ public static abstract interface CancellationSignal.OnCancelListener {
+ method public abstract void onCancel();
+ }
+
+ public class EnvironmentCompat {
+ ctor public EnvironmentCompat();
+ method public static java.lang.String getStorageState(java.io.File);
+ field public static final java.lang.String MEDIA_UNKNOWN = "unknown";
+ }
+
+ public class OperationCanceledException extends java.lang.RuntimeException {
+ ctor public OperationCanceledException();
+ ctor public OperationCanceledException(java.lang.String);
+ }
+
+ public class ParcelableCompat {
+ ctor public ParcelableCompat();
+ method public static android.os.Parcelable.Creator<T> newCreator(android.support.v4.os.ParcelableCompatCreatorCallbacks<T>);
+ }
+
+ public abstract interface ParcelableCompatCreatorCallbacks {
+ method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
+ method public abstract T[] newArray(int);
+ }
+
+ public class TraceCompat {
+ ctor public TraceCompat();
+ method public static void beginSection(java.lang.String);
+ method public static void endSection();
+ }
+
+}
+
+package android.support.v4.print {
+
+ public final class PrintHelper {
+ ctor public PrintHelper(android.content.Context);
+ method public int getColorMode();
+ method public int getOrientation();
+ method public int getScaleMode();
+ method public void printBitmap(java.lang.String, android.graphics.Bitmap);
+ method public void printBitmap(java.lang.String, android.graphics.Bitmap, android.support.v4.print.PrintHelper.OnPrintFinishCallback);
+ method public void printBitmap(java.lang.String, android.net.Uri) throws java.io.FileNotFoundException;
+ method public void printBitmap(java.lang.String, android.net.Uri, android.support.v4.print.PrintHelper.OnPrintFinishCallback) throws java.io.FileNotFoundException;
+ method public void setColorMode(int);
+ method public void setOrientation(int);
+ method public void setScaleMode(int);
+ method public static boolean systemSupportsPrint();
+ field public static final int COLOR_MODE_COLOR = 2; // 0x2
+ field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
+ field public static final int ORIENTATION_LANDSCAPE = 1; // 0x1
+ field public static final int ORIENTATION_PORTRAIT = 2; // 0x2
+ field public static final int SCALE_MODE_FILL = 2; // 0x2
+ field public static final int SCALE_MODE_FIT = 1; // 0x1
+ }
+
+ public static abstract interface PrintHelper.OnPrintFinishCallback {
+ method public abstract void onFinish();
+ }
+
+}
+
+package android.support.v4.provider {
+
+ public abstract class DocumentFile {
+ method public abstract boolean canRead();
+ method public abstract boolean canWrite();
+ method public abstract android.support.v4.provider.DocumentFile createDirectory(java.lang.String);
+ method public abstract android.support.v4.provider.DocumentFile createFile(java.lang.String, java.lang.String);
+ method public abstract boolean delete();
+ method public abstract boolean exists();
+ method public android.support.v4.provider.DocumentFile findFile(java.lang.String);
+ method public static android.support.v4.provider.DocumentFile fromFile(java.io.File);
+ method public static android.support.v4.provider.DocumentFile fromSingleUri(android.content.Context, android.net.Uri);
+ method public static android.support.v4.provider.DocumentFile fromTreeUri(android.content.Context, android.net.Uri);
+ method public abstract java.lang.String getName();
+ method public android.support.v4.provider.DocumentFile getParentFile();
+ method public abstract java.lang.String getType();
+ method public abstract android.net.Uri getUri();
+ method public abstract boolean isDirectory();
+ method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+ method public abstract boolean isFile();
+ method public abstract long lastModified();
+ method public abstract long length();
+ method public abstract android.support.v4.provider.DocumentFile[] listFiles();
+ method public abstract boolean renameTo(java.lang.String);
+ }
+
+}
+
+package android.support.v4.text {
+
+ public final class BidiFormatter {
+ method public static android.support.v4.text.BidiFormatter getInstance();
+ method public static android.support.v4.text.BidiFormatter getInstance(boolean);
+ method public static android.support.v4.text.BidiFormatter getInstance(java.util.Locale);
+ method public boolean getStereoReset();
+ method public boolean isRtl(java.lang.String);
+ method public boolean isRtlContext();
+ method public java.lang.String unicodeWrap(java.lang.String, android.support.v4.text.TextDirectionHeuristicCompat, boolean);
+ method public java.lang.String unicodeWrap(java.lang.String, android.support.v4.text.TextDirectionHeuristicCompat);
+ method public java.lang.String unicodeWrap(java.lang.String, boolean);
+ method public java.lang.String unicodeWrap(java.lang.String);
+ }
+
+ public static final class BidiFormatter.Builder {
+ ctor public BidiFormatter.Builder();
+ ctor public BidiFormatter.Builder(boolean);
+ ctor public BidiFormatter.Builder(java.util.Locale);
+ method public android.support.v4.text.BidiFormatter build();
+ method public android.support.v4.text.BidiFormatter.Builder setTextDirectionHeuristic(android.support.v4.text.TextDirectionHeuristicCompat);
+ method public android.support.v4.text.BidiFormatter.Builder stereoReset(boolean);
+ }
+
+ public class ICUCompat {
+ ctor public ICUCompat();
+ method public static java.lang.String maximizeAndGetScript(java.util.Locale);
+ }
+
+ public abstract interface TextDirectionHeuristicCompat {
+ method public abstract boolean isRtl(char[], int, int);
+ method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+ }
+
+ public class TextDirectionHeuristicsCompat {
+ ctor public TextDirectionHeuristicsCompat();
+ field public static final android.support.v4.text.TextDirectionHeuristicCompat ANYRTL_LTR;
+ field public static final android.support.v4.text.TextDirectionHeuristicCompat FIRSTSTRONG_LTR;
+ field public static final android.support.v4.text.TextDirectionHeuristicCompat FIRSTSTRONG_RTL;
+ field public static final android.support.v4.text.TextDirectionHeuristicCompat LOCALE;
+ field public static final android.support.v4.text.TextDirectionHeuristicCompat LTR;
+ field public static final android.support.v4.text.TextDirectionHeuristicCompat RTL;
+ }
+
+ public class TextUtilsCompat {
+ ctor public TextUtilsCompat();
+ method public static int getLayoutDirectionFromLocale(java.util.Locale);
+ method public static java.lang.String htmlEncode(java.lang.String);
+ field public static final java.util.Locale ROOT;
+ }
+
+}
+
+package android.support.v4.util {
+
+ public class ArrayMap extends android.support.v4.util.SimpleArrayMap implements java.util.Map {
+ ctor public ArrayMap();
+ ctor public ArrayMap(int);
+ ctor public ArrayMap(android.support.v4.util.SimpleArrayMap);
+ method public boolean containsAll(java.util.Collection<?>);
+ method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+ method public java.util.Set<K> keySet();
+ method public void putAll(java.util.Map<? extends K, ? extends V>);
+ method public boolean removeAll(java.util.Collection<?>);
+ method public boolean retainAll(java.util.Collection<?>);
+ method public java.util.Collection<V> values();
+ }
+
+ public class AtomicFile {
+ ctor public AtomicFile(java.io.File);
+ method public void delete();
+ method public void failWrite(java.io.FileOutputStream);
+ method public void finishWrite(java.io.FileOutputStream);
+ method public java.io.File getBaseFile();
+ method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+ method public byte[] readFully() throws java.io.IOException;
+ method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+ }
+
+ public final class CircularArray {
+ ctor public CircularArray();
+ ctor public CircularArray(int);
+ method public void addFirst(E);
+ method public void addLast(E);
+ method public void clear();
+ method public E get(int);
+ method public E getFirst();
+ method public E getLast();
+ method public boolean isEmpty();
+ method public E popFirst();
+ method public E popLast();
+ method public void removeFromEnd(int);
+ method public void removeFromStart(int);
+ method public int size();
+ }
+
+ public final class CircularIntArray {
+ ctor public CircularIntArray();
+ ctor public CircularIntArray(int);
+ method public void addFirst(int);
+ method public void addLast(int);
+ method public void clear();
+ method public int get(int);
+ method public int getFirst();
+ method public int getLast();
+ method public boolean isEmpty();
+ method public int popFirst();
+ method public int popLast();
+ method public void removeFromEnd(int);
+ method public void removeFromStart(int);
+ method public int size();
+ }
+
+ public class LongSparseArray {
+ ctor public LongSparseArray();
+ ctor public LongSparseArray(int);
+ method public void append(long, E);
+ method public void clear();
+ method public android.support.v4.util.LongSparseArray<E> clone();
+ method public void delete(long);
+ method public E get(long);
+ method public E get(long, E);
+ method public int indexOfKey(long);
+ method public int indexOfValue(E);
+ method public long keyAt(int);
+ method public void put(long, E);
+ method public void remove(long);
+ method public void removeAt(int);
+ method public void setValueAt(int, E);
+ method public int size();
+ method public E valueAt(int);
+ }
+
+ public class LruCache {
+ ctor public LruCache(int);
+ method protected V create(K);
+ method public final synchronized int createCount();
+ method protected void entryRemoved(boolean, K, V, V);
+ method public final void evictAll();
+ method public final synchronized int evictionCount();
+ method public final V get(K);
+ method public final synchronized int hitCount();
+ method public final synchronized int maxSize();
+ method public final synchronized int missCount();
+ method public final V put(K, V);
+ method public final synchronized int putCount();
+ method public final V remove(K);
+ method public void resize(int);
+ method public final synchronized int size();
+ method protected int sizeOf(K, V);
+ method public final synchronized java.util.Map<K, V> snapshot();
+ method public final synchronized java.lang.String toString();
+ method public void trimToSize(int);
+ }
+
+ public class Pair {
+ ctor public Pair(F, S);
+ method public static android.support.v4.util.Pair<A, B> create(A, B);
+ field public final F first;
+ field public final S second;
+ }
+
+ public final class Pools {
+ }
+
+ public static abstract interface Pools.Pool {
+ method public abstract T acquire();
+ method public abstract boolean release(T);
+ }
+
+ public static class Pools.SimplePool implements android.support.v4.util.Pools.Pool {
+ ctor public Pools.SimplePool(int);
+ method public T acquire();
+ method public boolean release(T);
+ }
+
+ public static class Pools.SynchronizedPool extends android.support.v4.util.Pools.SimplePool {
+ ctor public Pools.SynchronizedPool(int);
+ }
+
+ public class SimpleArrayMap {
+ ctor public SimpleArrayMap();
+ ctor public SimpleArrayMap(int);
+ ctor public SimpleArrayMap(android.support.v4.util.SimpleArrayMap);
+ method public void clear();
+ method public boolean containsKey(java.lang.Object);
+ method public boolean containsValue(java.lang.Object);
+ method public void ensureCapacity(int);
+ method public V get(java.lang.Object);
+ method public int indexOfKey(java.lang.Object);
+ method public boolean isEmpty();
+ method public K keyAt(int);
+ method public V put(K, V);
+ method public void putAll(android.support.v4.util.SimpleArrayMap<? extends K, ? extends V>);
+ method public V remove(java.lang.Object);
+ method public V removeAt(int);
+ method public V setValueAt(int, V);
+ method public int size();
+ method public V valueAt(int);
+ }
+
+ public class SparseArrayCompat {
+ ctor public SparseArrayCompat();
+ ctor public SparseArrayCompat(int);
+ method public void append(int, E);
+ method public void clear();
+ method public android.support.v4.util.SparseArrayCompat<E> clone();
+ method public void delete(int);
+ method public E get(int);
+ method public E get(int, E);
+ method public int indexOfKey(int);
+ method public int indexOfValue(E);
+ method public int keyAt(int);
+ method public void put(int, E);
+ method public void remove(int);
+ method public void removeAt(int);
+ method public void removeAtRange(int, int);
+ method public void setValueAt(int, E);
+ method public int size();
+ method public E valueAt(int);
+ }
+
+}
+
+package android.support.v4.view {
+
+ public class AccessibilityDelegateCompat {
+ ctor public AccessibilityDelegateCompat();
+ method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
+ method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
+ method public void sendAccessibilityEvent(android.view.View, int);
+ method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+ }
+
+ public abstract class ActionProvider {
+ ctor public ActionProvider(android.content.Context);
+ method public android.content.Context getContext();
+ method public boolean hasSubMenu();
+ method public boolean isVisible();
+ method public abstract android.view.View onCreateActionView();
+ method public android.view.View onCreateActionView(android.view.MenuItem);
+ method public boolean onPerformDefaultAction();
+ method public void onPrepareSubMenu(android.view.SubMenu);
+ method public boolean overridesItemVisibility();
+ method public void refreshVisibility();
+ method public void setVisibilityListener(android.support.v4.view.ActionProvider.VisibilityListener);
+ }
+
+ public static abstract interface ActionProvider.VisibilityListener {
+ method public abstract void onActionProviderVisibilityChanged(boolean);
+ }
+
+ public class GestureDetectorCompat {
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener);
+ ctor public GestureDetectorCompat(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler);
+ method public boolean isLongpressEnabled();
+ method public boolean onTouchEvent(android.view.MotionEvent);
+ method public void setIsLongpressEnabled(boolean);
+ method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener);
+ }
+
+ public class GravityCompat {
+ ctor public GravityCompat();
+ method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
+ method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+ method public static int getAbsoluteGravity(int, int);
+ field public static final int END = 8388613; // 0x800005
+ field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+ field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+ field public static final int START = 8388611; // 0x800003
+ }
+
+ public class InputDeviceCompat {
+ ctor public InputDeviceCompat();
+ field public static final int SOURCE_ANY = -256; // 0xffffff00
+ field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+ field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+ field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+ field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+ field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+ field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+ field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+ field public static final int SOURCE_DPAD = 513; // 0x201
+ field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+ field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+ field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+ field public static final int SOURCE_KEYBOARD = 257; // 0x101
+ field public static final int SOURCE_MOUSE = 8194; // 0x2002
+ field public static final int SOURCE_STYLUS = 16386; // 0x4002
+ field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+ field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+ field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+ field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+ field public static final int SOURCE_UNKNOWN = 0; // 0x0
+ }
+
+ public class KeyEventCompat {
+ ctor public KeyEventCompat();
+ method public static boolean dispatch(android.view.KeyEvent, android.view.KeyEvent.Callback, java.lang.Object, java.lang.Object);
+ method public static java.lang.Object getKeyDispatcherState(android.view.View);
+ method public static boolean hasModifiers(android.view.KeyEvent, int);
+ method public static boolean hasNoModifiers(android.view.KeyEvent);
+ method public static boolean isTracking(android.view.KeyEvent);
+ method public static boolean metaStateHasModifiers(int, int);
+ method public static boolean metaStateHasNoModifiers(int);
+ method public static int normalizeMetaState(int);
+ method public static void startTracking(android.view.KeyEvent);
+ }
+
+ public class LayoutInflaterCompat {
+ method public static void setFactory(android.view.LayoutInflater, android.support.v4.view.LayoutInflaterFactory);
+ }
+
+ public abstract interface LayoutInflaterFactory {
+ method public abstract android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+ }
+
+ public class MarginLayoutParamsCompat {
+ ctor public MarginLayoutParamsCompat();
+ method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams);
+ method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams);
+ method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams);
+ method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams, int);
+ method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams, int);
+ }
+
+ public class MenuCompat {
+ ctor public MenuCompat();
+ method public static deprecated void setShowAsAction(android.view.MenuItem, int);
+ }
+
+ public class MenuItemCompat {
+ ctor public MenuItemCompat();
+ method public static boolean collapseActionView(android.view.MenuItem);
+ method public static boolean expandActionView(android.view.MenuItem);
+ method public static android.support.v4.view.ActionProvider getActionProvider(android.view.MenuItem);
+ method public static android.view.View getActionView(android.view.MenuItem);
+ method public static boolean isActionViewExpanded(android.view.MenuItem);
+ method public static android.view.MenuItem setActionProvider(android.view.MenuItem, android.support.v4.view.ActionProvider);
+ method public static android.view.MenuItem setActionView(android.view.MenuItem, android.view.View);
+ method public static android.view.MenuItem setActionView(android.view.MenuItem, int);
+ method public static android.view.MenuItem setOnActionExpandListener(android.view.MenuItem, android.support.v4.view.MenuItemCompat.OnActionExpandListener);
+ method public static void setShowAsAction(android.view.MenuItem, int);
+ field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+ field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+ field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+ field public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+ field public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+ }
+
+ public static abstract interface MenuItemCompat.OnActionExpandListener {
+ method public abstract boolean onMenuItemActionCollapse(android.view.MenuItem);
+ method public abstract boolean onMenuItemActionExpand(android.view.MenuItem);
+ }
+
+ public class MotionEventCompat {
+ ctor public MotionEventCompat();
+ method public static int findPointerIndex(android.view.MotionEvent, int);
+ method public static int getActionIndex(android.view.MotionEvent);
+ method public static int getActionMasked(android.view.MotionEvent);
+ method public static float getAxisValue(android.view.MotionEvent, int);
+ method public static float getAxisValue(android.view.MotionEvent, int, int);
+ method public static int getPointerCount(android.view.MotionEvent);
+ method public static int getPointerId(android.view.MotionEvent, int);
+ method public static int getSource(android.view.MotionEvent);
+ method public static float getX(android.view.MotionEvent, int);
+ method public static float getY(android.view.MotionEvent, int);
+ field public static final int ACTION_HOVER_ENTER = 9; // 0x9
+ field public static final int ACTION_HOVER_EXIT = 10; // 0xa
+ field public static final int ACTION_HOVER_MOVE = 7; // 0x7
+ field public static final int ACTION_MASK = 255; // 0xff
+ field public static final int ACTION_POINTER_DOWN = 5; // 0x5
+ field public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+ field public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+ field public static final int ACTION_POINTER_UP = 6; // 0x6
+ field public static final int ACTION_SCROLL = 8; // 0x8
+ field public static final int AXIS_BRAKE = 23; // 0x17
+ field public static final int AXIS_DISTANCE = 24; // 0x18
+ field public static final int AXIS_GAS = 22; // 0x16
+ field public static final int AXIS_GENERIC_1 = 32; // 0x20
+ field public static final int AXIS_GENERIC_10 = 41; // 0x29
+ field public static final int AXIS_GENERIC_11 = 42; // 0x2a
+ field public static final int AXIS_GENERIC_12 = 43; // 0x2b
+ field public static final int AXIS_GENERIC_13 = 44; // 0x2c
+ field public static final int AXIS_GENERIC_14 = 45; // 0x2d
+ field public static final int AXIS_GENERIC_15 = 46; // 0x2e
+ field public static final int AXIS_GENERIC_16 = 47; // 0x2f
+ field public static final int AXIS_GENERIC_2 = 33; // 0x21
+ field public static final int AXIS_GENERIC_3 = 34; // 0x22
+ field public static final int AXIS_GENERIC_4 = 35; // 0x23
+ field public static final int AXIS_GENERIC_5 = 36; // 0x24
+ field public static final int AXIS_GENERIC_6 = 37; // 0x25
+ field public static final int AXIS_GENERIC_7 = 38; // 0x26
+ field public static final int AXIS_GENERIC_8 = 39; // 0x27
+ field public static final int AXIS_GENERIC_9 = 40; // 0x28
+ field public static final int AXIS_HAT_X = 15; // 0xf
+ field public static final int AXIS_HAT_Y = 16; // 0x10
+ field public static final int AXIS_HSCROLL = 10; // 0xa
+ field public static final int AXIS_LTRIGGER = 17; // 0x11
+ field public static final int AXIS_ORIENTATION = 8; // 0x8
+ field public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RTRIGGER = 18; // 0x12
+ field public static final int AXIS_RUDDER = 20; // 0x14
+ field public static final int AXIS_RX = 12; // 0xc
+ field public static final int AXIS_RY = 13; // 0xd
+ field public static final int AXIS_RZ = 14; // 0xe
+ field public static final int AXIS_SIZE = 3; // 0x3
+ field public static final int AXIS_THROTTLE = 19; // 0x13
+ field public static final int AXIS_TILT = 25; // 0x19
+ field public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+ field public static final int AXIS_TOOL_MINOR = 7; // 0x7
+ field public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+ field public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+ field public static final int AXIS_VSCROLL = 9; // 0x9
+ field public static final int AXIS_WHEEL = 21; // 0x15
+ field public static final int AXIS_X = 0; // 0x0
+ field public static final int AXIS_Y = 1; // 0x1
+ field public static final int AXIS_Z = 11; // 0xb
+ }
+
+ public abstract interface NestedScrollingChild {
+ method public abstract boolean dispatchNestedFling(float, float, boolean);
+ method public abstract boolean dispatchNestedPreFling(float, float);
+ method public abstract boolean dispatchNestedPreScroll(int, int, int[], int[]);
+ method public abstract boolean dispatchNestedScroll(int, int, int, int, int[]);
+ method public abstract boolean hasNestedScrollingParent();
+ method public abstract boolean isNestedScrollingEnabled();
+ method public abstract void setNestedScrollingEnabled(boolean);
+ method public abstract boolean startNestedScroll(int);
+ method public abstract void stopNestedScroll();
+ }
+
+ public class NestedScrollingChildHelper {
+ ctor public NestedScrollingChildHelper(android.view.View);
+ method public boolean dispatchNestedFling(float, float, boolean);
+ method public boolean dispatchNestedPreFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+ method public boolean hasNestedScrollingParent();
+ method public boolean isNestedScrollingEnabled();
+ method public void onDetachedFromWindow();
+ method public void onStopNestedScroll(android.view.View);
+ method public void setNestedScrollingEnabled(boolean);
+ method public boolean startNestedScroll(int);
+ method public void stopNestedScroll();
+ }
+
+ public abstract interface NestedScrollingParent {
+ method public abstract int getNestedScrollAxes();
+ method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
+ method public abstract boolean onNestedPreFling(android.view.View, float, float);
+ method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public abstract void onNestedScroll(android.view.View, int, int, int, int);
+ method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public abstract boolean onStartNestedScroll(android.view.View, android.view.View, int);
+ method public abstract void onStopNestedScroll(android.view.View);
+ }
+
+ public class NestedScrollingParentHelper {
+ ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+ method public int getNestedScrollAxes();
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public void onStopNestedScroll(android.view.View);
+ }
+
+ public abstract interface OnApplyWindowInsetsListener {
+ method public abstract android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+ }
+
+ public abstract class PagerAdapter {
+ ctor public PagerAdapter();
+ method public void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+ method public deprecated void destroyItem(android.view.View, int, java.lang.Object);
+ method public void finishUpdate(android.view.ViewGroup);
+ method public deprecated void finishUpdate(android.view.View);
+ method public abstract int getCount();
+ method public int getItemPosition(java.lang.Object);
+ method public java.lang.CharSequence getPageTitle(int);
+ method public float getPageWidth(int);
+ method public java.lang.Object instantiateItem(android.view.ViewGroup, int);
+ method public deprecated java.lang.Object instantiateItem(android.view.View, int);
+ method public abstract boolean isViewFromObject(android.view.View, java.lang.Object);
+ method public void notifyDataSetChanged();
+ method public void registerDataSetObserver(android.database.DataSetObserver);
+ method public void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+ method public android.os.Parcelable saveState();
+ method public void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+ method public deprecated void setPrimaryItem(android.view.View, int, java.lang.Object);
+ method public void startUpdate(android.view.ViewGroup);
+ method public deprecated void startUpdate(android.view.View);
+ method public void unregisterDataSetObserver(android.database.DataSetObserver);
+ field public static final int POSITION_NONE = -2; // 0xfffffffe
+ field public static final int POSITION_UNCHANGED = -1; // 0xffffffff
+ }
+
+ public class PagerTabStrip extends android.support.v4.view.PagerTitleStrip {
+ ctor public PagerTabStrip(android.content.Context);
+ ctor public PagerTabStrip(android.content.Context, android.util.AttributeSet);
+ method public boolean getDrawFullUnderline();
+ method public int getTabIndicatorColor();
+ method public void setDrawFullUnderline(boolean);
+ method public void setTabIndicatorColor(int);
+ method public void setTabIndicatorColorResource(int);
+ }
+
+ public class PagerTitleStrip extends android.view.ViewGroup {
+ ctor public PagerTitleStrip(android.content.Context);
+ ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
+ method public int getTextSpacing();
+ method protected void onLayout(boolean, int, int, int, int);
+ method public void setGravity(int);
+ method public void setNonPrimaryAlpha(float);
+ method public void setTextColor(int);
+ method public void setTextSize(int, float);
+ method public void setTextSpacing(int);
+ }
+
+ public class ScaleGestureDetectorCompat {
+ method public static boolean isQuickScaleEnabled(java.lang.Object);
+ method public static void setQuickScaleEnabled(java.lang.Object, boolean);
+ }
+
+ public abstract interface ScrollingView {
+ method public abstract int computeHorizontalScrollExtent();
+ method public abstract int computeHorizontalScrollOffset();
+ method public abstract int computeHorizontalScrollRange();
+ method public abstract int computeVerticalScrollExtent();
+ method public abstract int computeVerticalScrollOffset();
+ method public abstract int computeVerticalScrollRange();
+ }
+
+ public class VelocityTrackerCompat {
+ ctor public VelocityTrackerCompat();
+ method public static float getXVelocity(android.view.VelocityTracker, int);
+ method public static float getYVelocity(android.view.VelocityTracker, int);
+ }
+
+ public class ViewCompat {
+ ctor public ViewCompat();
+ method public static android.support.v4.view.ViewPropertyAnimatorCompat animate(android.view.View);
+ method public static boolean canScrollHorizontally(android.view.View, int);
+ method public static boolean canScrollVertically(android.view.View, int);
+ method public static int combineMeasuredStates(int, int);
+ method public static android.support.v4.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+ method public static void dispatchFinishTemporaryDetach(android.view.View);
+ method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+ method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+ method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[], int[]);
+ method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]);
+ method public static void dispatchStartTemporaryDetach(android.view.View);
+ method public static int getAccessibilityLiveRegion(android.view.View);
+ method public static android.support.v4.view.accessibility.AccessibilityNodeProviderCompat getAccessibilityNodeProvider(android.view.View);
+ method public static float getAlpha(android.view.View);
+ 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 float getElevation(android.view.View);
+ method public static boolean getFitsSystemWindows(android.view.View);
+ method public static int getImportantForAccessibility(android.view.View);
+ method public static int getLabelFor(android.view.View);
+ method public static int getLayerType(android.view.View);
+ method public static int getLayoutDirection(android.view.View);
+ method public static int getMeasuredHeightAndState(android.view.View);
+ method public static int getMeasuredState(android.view.View);
+ method public static int getMeasuredWidthAndState(android.view.View);
+ method public static int getMinimumHeight(android.view.View);
+ method public static int getMinimumWidth(android.view.View);
+ method public static int getOverScrollMode(android.view.View);
+ method public static int getPaddingEnd(android.view.View);
+ method public static int getPaddingStart(android.view.View);
+ method public static android.view.ViewParent getParentForAccessibility(android.view.View);
+ method public static float getPivotX(android.view.View);
+ method public static float getPivotY(android.view.View);
+ method public static float getRotation(android.view.View);
+ method public static float getRotationX(android.view.View);
+ method public static float getRotationY(android.view.View);
+ method public static float getScaleX(android.view.View);
+ method public static float getScaleY(android.view.View);
+ method public static int getScrollIndicators(android.view.View);
+ method public static java.lang.String getTransitionName(android.view.View);
+ method public static float getTranslationX(android.view.View);
+ method public static float getTranslationY(android.view.View);
+ method public static float getTranslationZ(android.view.View);
+ method public static int getWindowSystemUiVisibility(android.view.View);
+ method public static float getX(android.view.View);
+ method public static float getY(android.view.View);
+ method public static float getZ(android.view.View);
+ method public static boolean hasAccessibilityDelegate(android.view.View);
+ method public static boolean hasNestedScrollingParent(android.view.View);
+ method public static boolean hasOnClickListeners(android.view.View);
+ method public static boolean hasOverlappingRendering(android.view.View);
+ method public static boolean hasTransientState(android.view.View);
+ method public static boolean isAttachedToWindow(android.view.View);
+ method public static boolean isLaidOut(android.view.View);
+ method public static boolean isNestedScrollingEnabled(android.view.View);
+ method public static boolean isOpaque(android.view.View);
+ method public static boolean isPaddingRelative(android.view.View);
+ method public static void jumpDrawablesToCurrentState(android.view.View);
+ method public static void offsetLeftAndRight(android.view.View, int);
+ method public static void offsetTopAndBottom(android.view.View, int);
+ method public static android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
+ method public static void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public static void onInitializeAccessibilityNodeInfo(android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method public static void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
+ method public static void postInvalidateOnAnimation(android.view.View);
+ method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+ method public static void postOnAnimation(android.view.View, java.lang.Runnable);
+ method public static void postOnAnimationDelayed(android.view.View, java.lang.Runnable, long);
+ method public static void requestApplyInsets(android.view.View);
+ method public static int resolveSizeAndState(int, int, int);
+ method public static void setAccessibilityDelegate(android.view.View, android.support.v4.view.AccessibilityDelegateCompat);
+ 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 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);
+ method public static void setClipBounds(android.view.View, android.graphics.Rect);
+ method public static void setElevation(android.view.View, float);
+ method public static void setFitsSystemWindows(android.view.View, boolean);
+ method public static void setHasTransientState(android.view.View, boolean);
+ method public static void setImportantForAccessibility(android.view.View, int);
+ method public static void setLabelFor(android.view.View, int);
+ method public static void setLayerPaint(android.view.View, android.graphics.Paint);
+ method public static void setLayerType(android.view.View, int, android.graphics.Paint);
+ method public static void setLayoutDirection(android.view.View, int);
+ method public static void setNestedScrollingEnabled(android.view.View, boolean);
+ method public static void setOnApplyWindowInsetsListener(android.view.View, android.support.v4.view.OnApplyWindowInsetsListener);
+ method public static void setOverScrollMode(android.view.View, int);
+ method public static void setPaddingRelative(android.view.View, int, int, int, int);
+ method public static void setPivotX(android.view.View, float);
+ method public static void setPivotY(android.view.View, float);
+ method public static void setRotation(android.view.View, float);
+ method public static void setRotationX(android.view.View, float);
+ method public static void setRotationY(android.view.View, float);
+ method public static void setSaveFromParentEnabled(android.view.View, boolean);
+ method public static void setScaleX(android.view.View, float);
+ method public static void setScaleY(android.view.View, float);
+ method public static void setScrollIndicators(android.view.View, int);
+ method public static void setScrollIndicators(android.view.View, int, int);
+ method public static void setTransitionName(android.view.View, java.lang.String);
+ method public static void setTranslationX(android.view.View, float);
+ method public static void setTranslationY(android.view.View, float);
+ method public static void setTranslationZ(android.view.View, float);
+ method public static void setX(android.view.View, float);
+ method public static void setY(android.view.View, float);
+ method public static boolean startNestedScroll(android.view.View, int);
+ method public static void stopNestedScroll(android.view.View);
+ field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+ field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+ field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+ field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+ field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+ field public static final int LAYER_TYPE_NONE = 0; // 0x0
+ field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+ field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+ field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+ field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+ field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+ field public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+ field public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+ field public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+ field public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+ field public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+ field public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+ field public static final int OVER_SCROLL_NEVER = 2; // 0x2
+ field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+ field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+ field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+ field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+ field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+ field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+ field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+ }
+
+ public class ViewConfigurationCompat {
+ ctor public ViewConfigurationCompat();
+ method public static int getScaledPagingTouchSlop(android.view.ViewConfiguration);
+ method public static boolean hasPermanentMenuKey(android.view.ViewConfiguration);
+ }
+
+ public class ViewGroupCompat {
+ method public static int getLayoutMode(android.view.ViewGroup);
+ method public static int getNestedScrollAxes(android.view.ViewGroup);
+ method public static boolean isTransitionGroup(android.view.ViewGroup);
+ method public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public static void setLayoutMode(android.view.ViewGroup, int);
+ method public static void setMotionEventSplittingEnabled(android.view.ViewGroup, boolean);
+ method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+ field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+ field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+ }
+
+ public class ViewPager extends android.view.ViewGroup {
+ ctor public ViewPager(android.content.Context);
+ ctor public ViewPager(android.content.Context, android.util.AttributeSet);
+ method public void addOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+ method public boolean arrowScroll(int);
+ method public boolean beginFakeDrag();
+ method protected boolean canScroll(android.view.View, boolean, int, int, int);
+ method public void clearOnPageChangeListeners();
+ method public void endFakeDrag();
+ method public boolean executeKeyEvent(android.view.KeyEvent);
+ method public void fakeDragBy(float);
+ method public android.support.v4.view.PagerAdapter getAdapter();
+ method public int getCurrentItem();
+ method public int getOffscreenPageLimit();
+ method public int getPageMargin();
+ method public boolean isFakeDragging();
+ method protected void onLayout(boolean, int, int, int, int);
+ method protected void onPageScrolled(int, float, int);
+ method public void onRestoreInstanceState(android.os.Parcelable);
+ method public android.os.Parcelable onSaveInstanceState();
+ method public void removeOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+ method public void setAdapter(android.support.v4.view.PagerAdapter);
+ method public void setCurrentItem(int);
+ method public void setCurrentItem(int, boolean);
+ method public void setOffscreenPageLimit(int);
+ method public deprecated void setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+ method public void setPageMargin(int);
+ method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
+ method public void setPageMarginDrawable(int);
+ method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
+ 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
+ }
+
+ public static class ViewPager.LayoutParams extends android.view.ViewGroup.LayoutParams {
+ ctor public ViewPager.LayoutParams();
+ ctor public ViewPager.LayoutParams(android.content.Context, android.util.AttributeSet);
+ field public int gravity;
+ field public boolean isDecor;
+ }
+
+ public static abstract interface ViewPager.OnPageChangeListener {
+ method public abstract void onPageScrollStateChanged(int);
+ method public abstract void onPageScrolled(int, float, int);
+ method public abstract void onPageSelected(int);
+ }
+
+ public static abstract interface ViewPager.PageTransformer {
+ method public abstract void transformPage(android.view.View, float);
+ }
+
+ public static class ViewPager.SavedState extends android.view.View.BaseSavedState {
+ ctor public ViewPager.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.v4.view.ViewPager.SavedState> CREATOR;
+ }
+
+ public static class ViewPager.SimpleOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+ ctor public ViewPager.SimpleOnPageChangeListener();
+ method public void onPageScrollStateChanged(int);
+ method public void onPageScrolled(int, float, int);
+ method public void onPageSelected(int);
+ }
+
+ public class ViewParentCompat {
+ method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onNestedFling(android.view.ViewParent, android.view.View, float, float, boolean);
+ method public static boolean onNestedPreFling(android.view.ViewParent, android.view.View, float, float);
+ method public static void onNestedPreScroll(android.view.ViewParent, android.view.View, int, int, int[]);
+ method public static void onNestedScroll(android.view.ViewParent, android.view.View, int, int, int, int);
+ method public static void onNestedScrollAccepted(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static boolean onStartNestedScroll(android.view.ViewParent, android.view.View, android.view.View, int);
+ method public static void onStopNestedScroll(android.view.ViewParent, android.view.View);
+ method public static boolean requestSendAccessibilityEvent(android.view.ViewParent, android.view.View, android.view.accessibility.AccessibilityEvent);
+ }
+
+ public class ViewPropertyAnimatorCompat {
+ method public android.support.v4.view.ViewPropertyAnimatorCompat alpha(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat alphaBy(float);
+ method public void cancel();
+ method public long getDuration();
+ method public android.view.animation.Interpolator getInterpolator();
+ method public long getStartDelay();
+ method public android.support.v4.view.ViewPropertyAnimatorCompat rotation(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat rotationBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat rotationX(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat rotationXBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat rotationY(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat rotationYBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat scaleX(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat scaleXBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat scaleY(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat scaleYBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat setDuration(long);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat setInterpolator(android.view.animation.Interpolator);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat setListener(android.support.v4.view.ViewPropertyAnimatorListener);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat setStartDelay(long);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat setUpdateListener(android.support.v4.view.ViewPropertyAnimatorUpdateListener);
+ method public void start();
+ method public android.support.v4.view.ViewPropertyAnimatorCompat translationX(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat translationXBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat translationY(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat translationYBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat translationZ(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat translationZBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat withEndAction(java.lang.Runnable);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat withLayer();
+ method public android.support.v4.view.ViewPropertyAnimatorCompat withStartAction(java.lang.Runnable);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat x(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat xBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat y(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat yBy(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat z(float);
+ method public android.support.v4.view.ViewPropertyAnimatorCompat zBy(float);
+ }
+
+ public abstract interface ViewPropertyAnimatorListener {
+ method public abstract void onAnimationCancel(android.view.View);
+ method public abstract void onAnimationEnd(android.view.View);
+ method public abstract void onAnimationStart(android.view.View);
+ }
+
+ public class ViewPropertyAnimatorListenerAdapter implements android.support.v4.view.ViewPropertyAnimatorListener {
+ ctor public ViewPropertyAnimatorListenerAdapter();
+ method public void onAnimationCancel(android.view.View);
+ method public void onAnimationEnd(android.view.View);
+ method public void onAnimationStart(android.view.View);
+ }
+
+ public abstract interface ViewPropertyAnimatorUpdateListener {
+ method public abstract void onAnimationUpdate(android.view.View);
+ }
+
+ public class WindowCompat {
+ ctor public WindowCompat();
+ field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+ field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ }
+
+ public class WindowInsetsCompat {
+ method public android.support.v4.view.WindowInsetsCompat consumeStableInsets();
+ method public android.support.v4.view.WindowInsetsCompat consumeSystemWindowInsets();
+ method public int getStableInsetBottom();
+ method public int getStableInsetLeft();
+ method public int getStableInsetRight();
+ method public int getStableInsetTop();
+ method public int getSystemWindowInsetBottom();
+ method public int getSystemWindowInsetLeft();
+ method public int getSystemWindowInsetRight();
+ method public int getSystemWindowInsetTop();
+ method public boolean hasInsets();
+ method public boolean hasStableInsets();
+ method public boolean hasSystemWindowInsets();
+ method public boolean isConsumed();
+ method public boolean isRound();
+ method public android.support.v4.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+ method public android.support.v4.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+ }
+
+}
+
+package android.support.v4.view.accessibility {
+
+ public class AccessibilityEventCompat {
+ method public static void appendRecord(android.view.accessibility.AccessibilityEvent, android.support.v4.view.accessibility.AccessibilityRecordCompat);
+ method public static android.support.v4.view.accessibility.AccessibilityRecordCompat asRecord(android.view.accessibility.AccessibilityEvent);
+ method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent);
+ method public static android.support.v4.view.accessibility.AccessibilityRecordCompat getRecord(android.view.accessibility.AccessibilityEvent, int);
+ method public static int getRecordCount(android.view.accessibility.AccessibilityEvent);
+ method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent, int);
+ field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+ field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+ field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+ field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+ field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+ field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+ field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+ field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+ field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+ field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+ field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+ field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+ field public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+ field public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+ field public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+ field public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+ field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+ field public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+ }
+
+ public class AccessibilityManagerCompat {
+ ctor public AccessibilityManagerCompat();
+ method public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat);
+ method public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager, int);
+ method public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager);
+ method public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager);
+ method public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager, android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat);
+ }
+
+ public static abstract class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat {
+ ctor public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+ method public abstract void onAccessibilityStateChanged(boolean);
+ }
+
+ public class AccessibilityNodeInfoCompat {
+ ctor public AccessibilityNodeInfoCompat(java.lang.Object);
+ method public void addAction(int);
+ method public void addAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+ method public void addChild(android.view.View);
+ method public void addChild(android.view.View, int);
+ method public boolean canOpenPopup();
+ method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String);
+ method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(java.lang.String);
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat focusSearch(int);
+ method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat> getActionList();
+ method public int getActions();
+ method public void getBoundsInParent(android.graphics.Rect);
+ method public void getBoundsInScreen(android.graphics.Rect);
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getChild(int);
+ method public int getChildCount();
+ method public java.lang.CharSequence getClassName();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat getCollectionInfo();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat getCollectionItemInfo();
+ method public java.lang.CharSequence getContentDescription();
+ method public java.lang.CharSequence getError();
+ method public android.os.Bundle getExtras();
+ method public java.lang.Object getInfo();
+ method public int getInputType();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabelFor();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabeledBy();
+ method public int getLiveRegion();
+ method public int getMaxTextLength();
+ method public int getMovementGranularities();
+ method public java.lang.CharSequence getPackageName();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getParent();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat getRangeInfo();
+ method public java.lang.CharSequence getText();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalAfter();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalBefore();
+ method public java.lang.String getViewIdResourceName();
+ method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getWindow();
+ method public int getWindowId();
+ method public boolean isAccessibilityFocused();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isContentInvalid();
+ method public boolean isDismissable();
+ method public boolean isEditable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isLongClickable();
+ method public boolean isMultiLine();
+ method public boolean isPassword();
+ method public boolean isScrollable();
+ method public boolean isSelected();
+ method public boolean isVisibleToUser();
+ method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View);
+ method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.view.View, int);
+ method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain();
+ method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method public boolean performAction(int);
+ method public boolean performAction(int, android.os.Bundle);
+ method public void recycle();
+ method public boolean refresh();
+ method public boolean removeAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+ method public boolean removeChild(android.view.View);
+ method public boolean removeChild(android.view.View, int);
+ method public void setAccessibilityFocused(boolean);
+ method public void setBoundsInParent(android.graphics.Rect);
+ method public void setBoundsInScreen(android.graphics.Rect);
+ method public void setCanOpenPopup(boolean);
+ method public void setCheckable(boolean);
+ method public void setChecked(boolean);
+ method public void setClassName(java.lang.CharSequence);
+ method public void setClickable(boolean);
+ method public void setCollectionInfo(java.lang.Object);
+ method public void setCollectionItemInfo(java.lang.Object);
+ method public void setContentDescription(java.lang.CharSequence);
+ method public void setContentInvalid(boolean);
+ method public void setDismissable(boolean);
+ method public void setEditable(boolean);
+ method public void setEnabled(boolean);
+ method public void setError(java.lang.CharSequence);
+ method public void setFocusable(boolean);
+ method public void setFocused(boolean);
+ method public void setInputType(int);
+ method public void setLabelFor(android.view.View);
+ method public void setLabelFor(android.view.View, int);
+ method public void setLabeledBy(android.view.View);
+ method public void setLabeledBy(android.view.View, int);
+ method public void setLiveRegion(int);
+ method public void setLongClickable(boolean);
+ method public void setMaxTextLength(int);
+ method public void setMovementGranularities(int);
+ method public void setMultiLine(boolean);
+ method public void setPackageName(java.lang.CharSequence);
+ method public void setParent(android.view.View);
+ method public void setParent(android.view.View, int);
+ method public void setPassword(boolean);
+ method public void setRangeInfo(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat);
+ method public void setScrollable(boolean);
+ method public void setSelected(boolean);
+ method public void setSource(android.view.View);
+ method public void setSource(android.view.View, int);
+ method public void setText(java.lang.CharSequence);
+ method public void setTextSelection(int, int);
+ method public void setTraversalAfter(android.view.View);
+ method public void setTraversalAfter(android.view.View, int);
+ method public void setTraversalBefore(android.view.View);
+ method public void setTraversalBefore(android.view.View, int);
+ method public void setViewIdResourceName(java.lang.String);
+ method public void setVisibleToUser(boolean);
+ field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+ field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+ field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+ field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+ field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+ field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+ field public static final java.lang.String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+ field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+ field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+ field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+ field public static final int ACTION_CLICK = 16; // 0x10
+ field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+ field public static final int ACTION_COPY = 16384; // 0x4000
+ field public static final int ACTION_CUT = 65536; // 0x10000
+ field public static final int ACTION_DISMISS = 1048576; // 0x100000
+ field public static final int ACTION_EXPAND = 262144; // 0x40000
+ field public static final int ACTION_FOCUS = 1; // 0x1
+ field public static final int ACTION_LONG_CLICK = 32; // 0x20
+ field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+ field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+ field public static final int ACTION_PASTE = 32768; // 0x8000
+ field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+ field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+ field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+ field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+ field public static final int ACTION_SELECT = 4; // 0x4
+ field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+ field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+ field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+ field public static final int FOCUS_INPUT = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+ field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+ field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+ field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+ field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+ }
+
+ public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+ ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, java.lang.CharSequence);
+ method public int getId();
+ method public java.lang.CharSequence getLabel();
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_ACCESSIBILITY_FOCUS;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_FOCUS;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLEAR_SELECTION;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CLICK;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_COLLAPSE;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_COPY;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_CUT;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_DISMISS;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_EXPAND;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_FOCUS;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_LONG_CLICK;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_NEXT_HTML_ELEMENT;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PASTE;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PREVIOUS_HTML_ELEMENT;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_BACKWARD;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SCROLL_FORWARD;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SELECT;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_SELECTION;
+ field public static final android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_SET_TEXT;
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+ method public int getColumnCount();
+ method public int getRowCount();
+ method public boolean isHierarchical();
+ method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat obtain(int, int, boolean, int);
+ field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+ field public static final int SELECTION_MODE_NONE = 0; // 0x0
+ field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+ }
+
+ public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+ method public int getColumnIndex();
+ method public int getColumnSpan();
+ method public int getRowIndex();
+ method public int getRowSpan();
+ method public boolean isHeading();
+ method public boolean isSelected();
+ method public static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat obtain(int, int, int, int, boolean, boolean);
+ }
+
+ public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+ method public float getCurrent();
+ method public float getMax();
+ method public float getMin();
+ method public int getType();
+ field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+ field public static final int RANGE_TYPE_INT = 0; // 0x0
+ field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+ }
+
+ public class AccessibilityNodeProviderCompat {
+ ctor public AccessibilityNodeProviderCompat();
+ ctor public AccessibilityNodeProviderCompat(java.lang.Object);
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int);
+ method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String, int);
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
+ method public java.lang.Object getProvider();
+ method public boolean performAction(int, int, android.os.Bundle);
+ }
+
+ public class AccessibilityRecordCompat {
+ ctor public deprecated AccessibilityRecordCompat(java.lang.Object);
+ method public int getAddedCount();
+ method public java.lang.CharSequence getBeforeText();
+ method public java.lang.CharSequence getClassName();
+ method public java.lang.CharSequence getContentDescription();
+ method public int getCurrentItemIndex();
+ method public int getFromIndex();
+ method public deprecated java.lang.Object getImpl();
+ method public int getItemCount();
+ method public int getMaxScrollX();
+ method public int getMaxScrollY();
+ method public android.os.Parcelable getParcelableData();
+ method public int getRemovedCount();
+ method public int getScrollX();
+ method public int getScrollY();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getSource();
+ method public java.util.List<java.lang.CharSequence> getText();
+ method public int getToIndex();
+ method public int getWindowId();
+ method public boolean isChecked();
+ method public boolean isEnabled();
+ method public boolean isFullScreen();
+ method public boolean isPassword();
+ method public boolean isScrollable();
+ method public static android.support.v4.view.accessibility.AccessibilityRecordCompat obtain(android.support.v4.view.accessibility.AccessibilityRecordCompat);
+ method public static android.support.v4.view.accessibility.AccessibilityRecordCompat obtain();
+ method public void recycle();
+ method public void setAddedCount(int);
+ method public void setBeforeText(java.lang.CharSequence);
+ method public void setChecked(boolean);
+ method public void setClassName(java.lang.CharSequence);
+ method public void setContentDescription(java.lang.CharSequence);
+ method public void setCurrentItemIndex(int);
+ method public void setEnabled(boolean);
+ method public void setFromIndex(int);
+ method public void setFullScreen(boolean);
+ method public void setItemCount(int);
+ method public void setMaxScrollX(int);
+ method public void setMaxScrollY(int);
+ method public void setParcelableData(android.os.Parcelable);
+ method public void setPassword(boolean);
+ method public void setRemovedCount(int);
+ method public void setScrollX(int);
+ method public void setScrollY(int);
+ method public void setScrollable(boolean);
+ method public void setSource(android.view.View);
+ method public void setSource(android.view.View, int);
+ method public void setToIndex(int);
+ }
+
+ public class AccessibilityWindowInfoCompat {
+ method public void getBoundsInScreen(android.graphics.Rect);
+ method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getChild(int);
+ method public int getChildCount();
+ method public int getId();
+ method public int getLayer();
+ method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getParent();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getRoot();
+ method public int getType();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActive();
+ method public boolean isFocused();
+ method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain();
+ method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityWindowInfoCompat);
+ method public void recycle();
+ field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+ field public static final int TYPE_APPLICATION = 1; // 0x1
+ field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SYSTEM = 3; // 0x3
+ }
+
+}
+
+package android.support.v4.view.animation {
+
+ public class FastOutLinearInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+ ctor public FastOutLinearInInterpolator();
+ }
+
+ public class FastOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+ ctor public FastOutSlowInInterpolator();
+ }
+
+ public class LinearOutSlowInInterpolator extends android.support.v4.view.animation.LookupTableInterpolator {
+ ctor public LinearOutSlowInInterpolator();
+ }
+
+ abstract class LookupTableInterpolator implements android.view.animation.Interpolator {
+ ctor public LookupTableInterpolator(float[]);
+ method public float getInterpolation(float);
+ }
+
+ public class PathInterpolatorCompat {
+ method public static android.view.animation.Interpolator create(android.graphics.Path);
+ method public static android.view.animation.Interpolator create(float, float);
+ method public static android.view.animation.Interpolator create(float, float, float, float);
+ }
+
+}
+
+package android.support.v4.widget {
+
+ public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+ ctor public AutoScrollHelper(android.view.View);
+ method public abstract boolean canTargetScrollHorizontally(int);
+ method public abstract boolean canTargetScrollVertically(int);
+ method public boolean isEnabled();
+ method public boolean isExclusive();
+ method public boolean onTouch(android.view.View, android.view.MotionEvent);
+ method public abstract void scrollTargetBy(int, int);
+ method public android.support.v4.widget.AutoScrollHelper setActivationDelay(int);
+ method public android.support.v4.widget.AutoScrollHelper setEdgeType(int);
+ method public android.support.v4.widget.AutoScrollHelper setEnabled(boolean);
+ method public android.support.v4.widget.AutoScrollHelper setExclusive(boolean);
+ method public android.support.v4.widget.AutoScrollHelper setMaximumEdges(float, float);
+ method public android.support.v4.widget.AutoScrollHelper setMaximumVelocity(float, float);
+ method public android.support.v4.widget.AutoScrollHelper setMinimumVelocity(float, float);
+ method public android.support.v4.widget.AutoScrollHelper setRampDownDuration(int);
+ method public android.support.v4.widget.AutoScrollHelper setRampUpDuration(int);
+ method public android.support.v4.widget.AutoScrollHelper setRelativeEdges(float, float);
+ method public android.support.v4.widget.AutoScrollHelper setRelativeVelocity(float, float);
+ field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+ field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+ field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+ field public static final float NO_MAX = 3.4028235E38f;
+ field public static final float NO_MIN = 0.0f;
+ field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+ }
+
+ public final class CompoundButtonCompat {
+ method public static android.graphics.drawable.Drawable getButtonDrawable(android.widget.CompoundButton);
+ method public static android.content.res.ColorStateList getButtonTintList(android.widget.CompoundButton);
+ method public static android.graphics.PorterDuff.Mode getButtonTintMode(android.widget.CompoundButton);
+ method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList);
+ method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode);
+ }
+
+ public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+ ctor public ContentLoadingProgressBar(android.content.Context);
+ ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet);
+ method public void hide();
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void show();
+ }
+
+ public abstract class CursorAdapter extends android.widget.BaseAdapter {
+ ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
+ ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
+ ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
+ method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
+ method public void changeCursor(android.database.Cursor);
+ method public java.lang.CharSequence convertToString(android.database.Cursor);
+ method public int getCount();
+ method public android.database.Cursor getCursor();
+ method public android.widget.Filter getFilter();
+ method public android.widget.FilterQueryProvider getFilterQueryProvider();
+ method public java.lang.Object getItem(int);
+ method public long getItemId(int);
+ method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
+ method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
+ method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+ method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+ method protected void onContentChanged();
+ method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+ method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
+ method public android.database.Cursor swapCursor(android.database.Cursor);
+ field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
+ field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
+ }
+
+ public class DrawerLayout extends android.view.ViewGroup {
+ ctor public DrawerLayout(android.content.Context);
+ ctor public DrawerLayout(android.content.Context, android.util.AttributeSet);
+ ctor public DrawerLayout(android.content.Context, android.util.AttributeSet, int);
+ method public void closeDrawer(android.view.View);
+ method public void closeDrawer(int);
+ method public void closeDrawers();
+ method public float getDrawerElevation();
+ method public int getDrawerLockMode(int);
+ method public int getDrawerLockMode(android.view.View);
+ method public java.lang.CharSequence getDrawerTitle(int);
+ method public android.graphics.drawable.Drawable getStatusBarBackgroundDrawable();
+ method public boolean isDrawerOpen(android.view.View);
+ method public boolean isDrawerOpen(int);
+ method public boolean isDrawerVisible(android.view.View);
+ method public boolean isDrawerVisible(int);
+ method public void onDraw(android.graphics.Canvas);
+ method protected void onLayout(boolean, int, int, int, int);
+ method public void openDrawer(android.view.View);
+ method public void openDrawer(int);
+ method public void setDrawerElevation(float);
+ method public void setDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+ method public void setDrawerLockMode(int);
+ method public void setDrawerLockMode(int, int);
+ method public void setDrawerLockMode(int, android.view.View);
+ method public void setDrawerShadow(android.graphics.drawable.Drawable, int);
+ method public void setDrawerShadow(int, int);
+ method public void setDrawerTitle(int, java.lang.CharSequence);
+ method public void setScrimColor(int);
+ method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+ method public void setStatusBarBackground(int);
+ method public void setStatusBarBackgroundColor(int);
+ field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
+ field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
+ field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public static abstract interface DrawerLayout.DrawerListener {
+ method public abstract void onDrawerClosed(android.view.View);
+ method public abstract void onDrawerOpened(android.view.View);
+ method public abstract void onDrawerSlide(android.view.View, float);
+ method public abstract void onDrawerStateChanged(int);
+ }
+
+ public static class DrawerLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public DrawerLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public DrawerLayout.LayoutParams(int, int);
+ ctor public DrawerLayout.LayoutParams(int, int, int);
+ ctor public DrawerLayout.LayoutParams(android.support.v4.widget.DrawerLayout.LayoutParams);
+ ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ field public int gravity;
+ }
+
+ protected static class DrawerLayout.SavedState extends android.view.View.BaseSavedState {
+ ctor public DrawerLayout.SavedState(android.os.Parcel);
+ ctor public DrawerLayout.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.v4.widget.DrawerLayout.SavedState> CREATOR;
+ }
+
+ public static abstract class DrawerLayout.SimpleDrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {
+ ctor public DrawerLayout.SimpleDrawerListener();
+ method public void onDrawerClosed(android.view.View);
+ method public void onDrawerOpened(android.view.View);
+ method public void onDrawerSlide(android.view.View, float);
+ method public void onDrawerStateChanged(int);
+ }
+
+ public class EdgeEffectCompat {
+ ctor public EdgeEffectCompat(android.content.Context);
+ method public boolean draw(android.graphics.Canvas);
+ method public void finish();
+ method public boolean isFinished();
+ method public boolean onAbsorb(int);
+ method public deprecated boolean onPull(float);
+ method public boolean onPull(float, float);
+ method public boolean onRelease();
+ method public void setSize(int, int);
+ }
+
+ public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
+ ctor public ExploreByTouchHelper(android.view.View);
+ method public boolean dispatchHoverEvent(android.view.MotionEvent);
+ method public int getFocusedVirtualView();
+ method protected abstract int getVirtualViewAt(float, float);
+ method protected abstract void getVisibleVirtualViews(java.util.List<java.lang.Integer>);
+ method public void invalidateRoot();
+ method public void invalidateVirtualView(int);
+ method protected abstract boolean onPerformActionForVirtualView(int, int, android.os.Bundle);
+ method protected abstract void onPopulateEventForVirtualView(int, android.view.accessibility.AccessibilityEvent);
+ method public void onPopulateNodeForHost(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method protected abstract void onPopulateNodeForVirtualView(int, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method public boolean sendEventForVirtualView(int, int);
+ field public static final int HOST_ID = -1; // 0xffffffff
+ field public static final int INVALID_ID = -2147483648; // 0x80000000
+ }
+
+ public class ListPopupWindowCompat {
+ method public static android.view.View.OnTouchListener createDragToOpenListener(java.lang.Object, android.view.View);
+ }
+
+ public class ListViewAutoScrollHelper extends android.support.v4.widget.AutoScrollHelper {
+ ctor public ListViewAutoScrollHelper(android.widget.ListView);
+ method public boolean canTargetScrollHorizontally(int);
+ method public boolean canTargetScrollVertically(int);
+ method public void scrollTargetBy(int, int);
+ }
+
+ public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
+ ctor public NestedScrollView(android.content.Context);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
+ ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
+ method public boolean arrowScroll(int);
+ method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect);
+ method public boolean executeKeyEvent(android.view.KeyEvent);
+ method public void fling(int);
+ method public boolean fullScroll(int);
+ method public int getMaxScrollAmount();
+ method public boolean isFillViewport();
+ method public boolean isSmoothScrollingEnabled();
+ method public void onAttachedToWindow();
+ method public boolean pageScroll(int);
+ method public void setFillViewport(boolean);
+ method public void setOnScrollChangeListener(android.support.v4.widget.NestedScrollView.OnScrollChangeListener);
+ method public void setSmoothScrollingEnabled(boolean);
+ method public final void smoothScrollBy(int, int);
+ method public final void smoothScrollTo(int, int);
+ }
+
+ public static abstract interface NestedScrollView.OnScrollChangeListener {
+ method public abstract void onScrollChange(android.support.v4.widget.NestedScrollView, int, int, int, int);
+ }
+
+ public class PopupMenuCompat {
+ method public static android.view.View.OnTouchListener getDragToOpenListener(java.lang.Object);
+ }
+
+ public class PopupWindowCompat {
+ method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+ method public static int getWindowLayoutType(android.widget.PopupWindow);
+ method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+ method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+ method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+ }
+
+ public abstract class ResourceCursorAdapter extends android.support.v4.widget.CursorAdapter {
+ ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
+ ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, boolean);
+ ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, int);
+ method public android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+ method public void setDropDownViewResource(int);
+ method public void setViewResource(int);
+ }
+
+ public class ScrollerCompat {
+ method public void abortAnimation();
+ method public boolean computeScrollOffset();
+ method public static android.support.v4.widget.ScrollerCompat create(android.content.Context);
+ method public static android.support.v4.widget.ScrollerCompat create(android.content.Context, android.view.animation.Interpolator);
+ method public void fling(int, int, int, int, int, int, int, int);
+ method public void fling(int, int, int, int, int, int, int, int, int, int);
+ method public float getCurrVelocity();
+ method public int getCurrX();
+ method public int getCurrY();
+ method public int getFinalX();
+ method public int getFinalY();
+ method public boolean isFinished();
+ method public boolean isOverScrolled();
+ method public void notifyHorizontalEdgeReached(int, int, int);
+ method public void notifyVerticalEdgeReached(int, int, int);
+ method public boolean springBack(int, int, int, int, int, int);
+ method public void startScroll(int, int, int, int);
+ method public void startScroll(int, int, int, int, int);
+ }
+
+ public class SearchViewCompat {
+ method public static java.lang.CharSequence getQuery(android.view.View);
+ method public static boolean isIconified(android.view.View);
+ method public static boolean isQueryRefinementEnabled(android.view.View);
+ method public static boolean isSubmitButtonEnabled(android.view.View);
+ method public static android.view.View newSearchView(android.content.Context);
+ method public static void setIconified(android.view.View, boolean);
+ method public static void setImeOptions(android.view.View, int);
+ method public static void setInputType(android.view.View, int);
+ method public static void setMaxWidth(android.view.View, int);
+ method public static void setOnCloseListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat);
+ method public static void setOnQueryTextListener(android.view.View, android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat);
+ method public static void setQuery(android.view.View, java.lang.CharSequence, boolean);
+ method public static void setQueryHint(android.view.View, java.lang.CharSequence);
+ method public static void setQueryRefinementEnabled(android.view.View, boolean);
+ method public static void setSearchableInfo(android.view.View, android.content.ComponentName);
+ method public static void setSubmitButtonEnabled(android.view.View, boolean);
+ }
+
+ public static abstract class SearchViewCompat.OnCloseListenerCompat {
+ ctor public SearchViewCompat.OnCloseListenerCompat();
+ method public boolean onClose();
+ }
+
+ public static abstract class SearchViewCompat.OnQueryTextListenerCompat {
+ ctor public SearchViewCompat.OnQueryTextListenerCompat();
+ method public boolean onQueryTextChange(java.lang.String);
+ method public boolean onQueryTextSubmit(java.lang.String);
+ }
+
+ public class SimpleCursorAdapter extends android.support.v4.widget.ResourceCursorAdapter {
+ ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
+ ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
+ method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
+ method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
+ method public android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
+ method public int getStringConversionColumn();
+ method public android.support.v4.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
+ method public void setCursorToStringConverter(android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter);
+ method public void setStringConversionColumn(int);
+ method public void setViewBinder(android.support.v4.widget.SimpleCursorAdapter.ViewBinder);
+ method public void setViewImage(android.widget.ImageView, java.lang.String);
+ method public void setViewText(android.widget.TextView, java.lang.String);
+ }
+
+ public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
+ method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
+ }
+
+ public static abstract interface SimpleCursorAdapter.ViewBinder {
+ method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+ }
+
+ public class SlidingPaneLayout extends android.view.ViewGroup {
+ ctor public SlidingPaneLayout(android.content.Context);
+ ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet);
+ ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet, int);
+ method protected boolean canScroll(android.view.View, boolean, int, int, int);
+ method public deprecated boolean canSlide();
+ method public boolean closePane();
+ method public int getCoveredFadeColor();
+ method public int getParallaxDistance();
+ method public int getSliderFadeColor();
+ method public boolean isOpen();
+ method public boolean isSlideable();
+ method protected void onLayout(boolean, int, int, int, int);
+ method public boolean openPane();
+ method public void setCoveredFadeColor(int);
+ method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
+ method public void setParallaxDistance(int);
+ method public deprecated void setShadowDrawable(android.graphics.drawable.Drawable);
+ method public void setShadowDrawableLeft(android.graphics.drawable.Drawable);
+ method public void setShadowDrawableRight(android.graphics.drawable.Drawable);
+ method public deprecated void setShadowResource(int);
+ method public void setShadowResourceLeft(int);
+ method public void setShadowResourceRight(int);
+ method public void setSliderFadeColor(int);
+ method public deprecated void smoothSlideClosed();
+ method public deprecated void smoothSlideOpen();
+ }
+
+ public static class SlidingPaneLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public SlidingPaneLayout.LayoutParams();
+ ctor public SlidingPaneLayout.LayoutParams(int, int);
+ ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public SlidingPaneLayout.LayoutParams(android.support.v4.widget.SlidingPaneLayout.LayoutParams);
+ ctor public SlidingPaneLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+ field public float weight;
+ }
+
+ public static abstract interface SlidingPaneLayout.PanelSlideListener {
+ method public abstract void onPanelClosed(android.view.View);
+ method public abstract void onPanelOpened(android.view.View);
+ method public abstract void onPanelSlide(android.view.View, float);
+ }
+
+ public static class SlidingPaneLayout.SimplePanelSlideListener implements android.support.v4.widget.SlidingPaneLayout.PanelSlideListener {
+ ctor public SlidingPaneLayout.SimplePanelSlideListener();
+ method public void onPanelClosed(android.view.View);
+ method public void onPanelOpened(android.view.View);
+ method public void onPanelSlide(android.view.View, float);
+ }
+
+ public class Space extends android.view.View {
+ ctor public Space(android.content.Context, android.util.AttributeSet, int);
+ ctor public Space(android.content.Context, android.util.AttributeSet);
+ ctor public Space(android.content.Context);
+ }
+
+ public class SwipeRefreshLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
+ ctor public SwipeRefreshLayout(android.content.Context);
+ ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
+ method public boolean canChildScrollUp();
+ method public int getProgressCircleDiameter();
+ method public boolean isRefreshing();
+ method protected void onLayout(boolean, int, int, int, int);
+ method public void onMeasure(int, int);
+ method public deprecated void setColorScheme(int...);
+ method public void setColorSchemeColors(int...);
+ method public void setColorSchemeResources(int...);
+ method public void setDistanceToTriggerSync(int);
+ method public void setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener);
+ method public deprecated void setProgressBackgroundColor(int);
+ method public void setProgressBackgroundColorSchemeColor(int);
+ method public void setProgressBackgroundColorSchemeResource(int);
+ method public void setProgressViewEndTarget(boolean, int);
+ method public void setProgressViewOffset(boolean, int, int);
+ method public void setRefreshing(boolean);
+ method public void setSize(int);
+ field public static final int DEFAULT = 1; // 0x1
+ field public static final int LARGE = 0; // 0x0
+ field protected int mFrom;
+ field protected int mOriginalOffsetTop;
+ }
+
+ public static abstract interface SwipeRefreshLayout.OnRefreshListener {
+ method public abstract void onRefresh();
+ }
+
+ public class TextViewCompat {
+ method public static int getMaxLines(android.widget.TextView);
+ method public static int getMinLines(android.widget.TextView);
+ method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+ method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, int, int, int, int);
+ }
+
+ public class ViewDragHelper {
+ method public void abort();
+ method protected boolean canScroll(android.view.View, boolean, int, int, int, int);
+ method public void cancel();
+ method public void captureChildView(android.view.View, int);
+ method public boolean checkTouchSlop(int);
+ method public boolean checkTouchSlop(int, int);
+ method public boolean continueSettling(boolean);
+ method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, android.support.v4.widget.ViewDragHelper.Callback);
+ method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, float, android.support.v4.widget.ViewDragHelper.Callback);
+ method public android.view.View findTopChildUnder(int, int);
+ method public void flingCapturedView(int, int, int, int);
+ method public int getActivePointerId();
+ method public android.view.View getCapturedView();
+ method public int getEdgeSize();
+ method public float getMinVelocity();
+ method public int getTouchSlop();
+ method public int getViewDragState();
+ method public boolean isCapturedViewUnder(int, int);
+ method public boolean isEdgeTouched(int);
+ method public boolean isEdgeTouched(int, int);
+ method public boolean isPointerDown(int);
+ method public boolean isViewUnder(android.view.View, int, int);
+ method public void processTouchEvent(android.view.MotionEvent);
+ method public void setEdgeTrackingEnabled(int);
+ method public void setMinVelocity(float);
+ method public boolean settleCapturedViewAt(int, int);
+ method public boolean shouldInterceptTouchEvent(android.view.MotionEvent);
+ method public boolean smoothSlideViewTo(android.view.View, int, int);
+ field public static final int DIRECTION_ALL = 3; // 0x3
+ field public static final int DIRECTION_HORIZONTAL = 1; // 0x1
+ field public static final int DIRECTION_VERTICAL = 2; // 0x2
+ field public static final int EDGE_ALL = 15; // 0xf
+ field public static final int EDGE_BOTTOM = 8; // 0x8
+ field public static final int EDGE_LEFT = 1; // 0x1
+ field public static final int EDGE_RIGHT = 2; // 0x2
+ field public static final int EDGE_TOP = 4; // 0x4
+ field public static final int INVALID_POINTER = -1; // 0xffffffff
+ field public static final int STATE_DRAGGING = 1; // 0x1
+ field public static final int STATE_IDLE = 0; // 0x0
+ field public static final int STATE_SETTLING = 2; // 0x2
+ }
+
+ public static abstract class ViewDragHelper.Callback {
+ ctor public ViewDragHelper.Callback();
+ method public int clampViewPositionHorizontal(android.view.View, int, int);
+ method public int clampViewPositionVertical(android.view.View, int, int);
+ method public int getOrderedChildIndex(int);
+ method public int getViewHorizontalDragRange(android.view.View);
+ method public int getViewVerticalDragRange(android.view.View);
+ method public void onEdgeDragStarted(int, int);
+ method public boolean onEdgeLock(int);
+ method public void onEdgeTouched(int, int);
+ method public void onViewCaptured(android.view.View, int);
+ method public void onViewDragStateChanged(int);
+ method public void onViewPositionChanged(android.view.View, int, int, int, int);
+ method public void onViewReleased(android.view.View, float, float);
+ method public abstract boolean tryCaptureView(android.view.View, int);
+ }
+
+}
+
diff --git a/v4/api/current.txt b/v4/api/current.txt
index 3c4290e..9f50a24 100644
--- a/v4/api/current.txt
+++ b/v4/api/current.txt
@@ -26,36 +26,6 @@
}
-package android.support.v4.animation {
-
- public abstract class AnimatorCompatHelper {
- method public static void clearInterpolator(android.view.View);
- method public static android.support.v4.animation.ValueAnimatorCompat emptyValueAnimator();
- }
-
- public abstract interface AnimatorListenerCompat {
- method public abstract void onAnimationCancel(android.support.v4.animation.ValueAnimatorCompat);
- method public abstract void onAnimationEnd(android.support.v4.animation.ValueAnimatorCompat);
- method public abstract void onAnimationRepeat(android.support.v4.animation.ValueAnimatorCompat);
- method public abstract void onAnimationStart(android.support.v4.animation.ValueAnimatorCompat);
- }
-
- public abstract interface AnimatorUpdateListenerCompat {
- method public abstract void onAnimationUpdate(android.support.v4.animation.ValueAnimatorCompat);
- }
-
- public abstract interface ValueAnimatorCompat {
- method public abstract void addListener(android.support.v4.animation.AnimatorListenerCompat);
- method public abstract void addUpdateListener(android.support.v4.animation.AnimatorUpdateListenerCompat);
- method public abstract void cancel();
- method public abstract float getAnimatedFraction();
- method public abstract void setDuration(long);
- method public abstract void setTarget(android.view.View);
- method public abstract void start();
- }
-
-}
-
package android.support.v4.app {
public deprecated class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
@@ -274,12 +244,14 @@
method public java.lang.Object getLastCustomNonConfigurationInstance();
method public android.support.v4.app.FragmentManager getSupportFragmentManager();
method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+ method public final android.support.v4.media.session.MediaControllerCompat getSupportMediaController();
method public void onAttachFragment(android.support.v4.app.Fragment);
method protected void onResumeFragments();
method public java.lang.Object onRetainCustomNonConfigurationInstance();
method public final java.lang.Object onRetainNonConfigurationInstance();
method public void setEnterSharedElementCallback(android.support.v4.app.SharedElementCallback);
method public void setExitSharedElementCallback(android.support.v4.app.SharedElementCallback);
+ method public final void setSupportMediaController(android.support.v4.media.session.MediaControllerCompat);
method public void startActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
method public void supportFinishAfterTransition();
method public void supportInvalidateOptionsMenu();
@@ -560,7 +532,7 @@
field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
}
- public static class NotificationCompat.Action extends android.support.v4.app.NotificationCompatBase.Action {
+ public static class NotificationCompat.Action {
ctor public NotificationCompat.Action(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.PendingIntent getActionIntent();
method public android.os.Bundle getExtras();
@@ -681,7 +653,7 @@
method public android.support.v4.app.NotificationCompat.CarExtender setUnreadConversation(android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation);
}
- public static class NotificationCompat.CarExtender.UnreadConversation extends android.support.v4.app.NotificationCompatBase.UnreadConversation {
+ public static class NotificationCompat.CarExtender.UnreadConversation {
method public long getLatestTimestamp();
method public java.lang.String[] getMessages();
method public java.lang.String getParticipant();
@@ -770,23 +742,6 @@
field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
}
- public class NotificationCompatBase {
- ctor public NotificationCompatBase();
- }
-
- public static abstract class NotificationCompatBase.Action {
- ctor public NotificationCompatBase.Action();
- method public abstract android.app.PendingIntent getActionIntent();
- method public abstract android.os.Bundle getExtras();
- method public abstract int getIcon();
- method public abstract android.support.v4.app.RemoteInputCompatBase.RemoteInput[] getRemoteInputs();
- method public abstract java.lang.CharSequence getTitle();
- }
-
- public static abstract class NotificationCompatBase.UnreadConversation {
- ctor public NotificationCompatBase.UnreadConversation();
- }
-
public final class NotificationCompatExtras {
field public static final java.lang.String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
field public static final java.lang.String EXTRA_GROUP_KEY = "android.support.groupKey";
@@ -964,13 +919,13 @@
public class ContextCompat {
ctor public ContextCompat();
method public static int checkSelfPermission(android.content.Context, java.lang.String);
- method public final java.io.File getCodeCacheDir(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
method public static final int getColor(android.content.Context, int);
method public static final android.content.res.ColorStateList getColorStateList(android.content.Context, int);
method public static final android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
method public static java.io.File[] getExternalCacheDirs(android.content.Context);
method public static java.io.File[] getExternalFilesDirs(android.content.Context, java.lang.String);
- method public final java.io.File getNoBackupFilesDir(android.content.Context);
+ method public static java.io.File getNoBackupFilesDir(android.content.Context);
method public static java.io.File[] getObbDirs(android.content.Context);
method public static boolean startActivities(android.content.Context, android.content.Intent[]);
method public static boolean startActivities(android.content.Context, android.content.Intent[], android.os.Bundle);
@@ -1071,6 +1026,11 @@
method public void unregisterReceiver(android.content.BroadcastReceiver);
}
+ public class ParallelExecutorCompat {
+ ctor public ParallelExecutorCompat();
+ method public static java.util.concurrent.Executor getParallelExecutor();
+ }
+
public final class PermissionChecker {
method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
@@ -1113,6 +1073,8 @@
public class ResourcesCompat {
ctor public ResourcesCompat();
+ method public static int getColor(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+ method public static android.content.res.ColorStateList getColorStateList(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
method public static android.graphics.drawable.Drawable getDrawable(android.content.res.Resources, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
method public static android.graphics.drawable.Drawable getDrawableForDensity(android.content.res.Resources, int, int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
}
@@ -1246,6 +1208,77 @@
package android.support.v4.media {
+ public final class MediaBrowserCompat {
+ ctor public MediaBrowserCompat(android.content.Context, android.content.ComponentName, android.support.v4.media.MediaBrowserCompat.ConnectionCallback, android.os.Bundle);
+ method public void connect();
+ method public void disconnect();
+ method public android.os.Bundle getExtras();
+ method public void getItem(java.lang.String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+ method public java.lang.String getRoot();
+ method public android.content.ComponentName getServiceComponent();
+ method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+ method public boolean isConnected();
+ method public void subscribe(java.lang.String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+ method public void unsubscribe(java.lang.String);
+ }
+
+ public static class MediaBrowserCompat.ConnectionCallback {
+ ctor public MediaBrowserCompat.ConnectionCallback();
+ method public void onConnected();
+ method public void onConnectionFailed();
+ method public void onConnectionSuspended();
+ }
+
+ public static abstract class MediaBrowserCompat.ItemCallback {
+ ctor public MediaBrowserCompat.ItemCallback();
+ method public void onError(java.lang.String);
+ method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem);
+ }
+
+ public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+ ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+ method public int describeContents();
+ method public android.support.v4.media.MediaDescriptionCompat getDescription();
+ method public int getFlags();
+ method public java.lang.String getMediaId();
+ method public boolean isBrowsable();
+ method public boolean isPlayable();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem> CREATOR;
+ field public static final int FLAG_BROWSABLE = 1; // 0x1
+ field public static final int FLAG_PLAYABLE = 2; // 0x2
+ }
+
+ public static abstract class MediaBrowserCompat.SubscriptionCallback {
+ ctor public MediaBrowserCompat.SubscriptionCallback();
+ method public void onChildrenLoaded(java.lang.String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+ method public void onError(java.lang.String);
+ }
+
+ public abstract class MediaBrowserServiceCompat extends android.app.Service {
+ ctor public MediaBrowserServiceCompat();
+ method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+ method public void notifyChildrenChanged(java.lang.String);
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
+ method public abstract void onLoadChildren(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>);
+ method public void onLoadItem(java.lang.String, android.support.v4.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem>);
+ method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+ }
+
+ public static final class MediaBrowserServiceCompat.BrowserRoot {
+ ctor public MediaBrowserServiceCompat.BrowserRoot(java.lang.String, android.os.Bundle);
+ method public android.os.Bundle getExtras();
+ method public java.lang.String getRootId();
+ }
+
+ public static class MediaBrowserServiceCompat.Result {
+ method public void detach();
+ method public void sendResult(T);
+ }
+
public final class MediaDescriptionCompat implements android.os.Parcelable {
method public int describeContents();
method public static android.support.v4.media.MediaDescriptionCompat fromMediaDescription(java.lang.Object);
@@ -1449,6 +1482,12 @@
package android.support.v4.media.session {
+ public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+ ctor public MediaButtonReceiver();
+ method public static android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
+ method public void onReceive(android.content.Context, android.content.Intent);
+ }
+
public final class MediaControllerCompat {
ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
@@ -1516,6 +1555,7 @@
}
public class MediaSessionCompat {
+ ctor public MediaSessionCompat(android.content.Context, java.lang.String);
ctor public MediaSessionCompat(android.content.Context, java.lang.String, android.content.ComponentName, android.app.PendingIntent);
method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
method public android.support.v4.media.session.MediaControllerCompat getController();
@@ -2349,6 +2389,13 @@
method public abstract int computeVerticalScrollRange();
}
+ public abstract interface TintableBackgroundView {
+ method public abstract android.content.res.ColorStateList getSupportBackgroundTintList();
+ method public abstract android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
+ method public abstract void setSupportBackgroundTintList(android.content.res.ColorStateList);
+ method public abstract void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
+ }
+
public class VelocityTrackerCompat {
ctor public VelocityTrackerCompat();
method public static float getXVelocity(android.view.VelocityTracker, int);
@@ -2396,6 +2443,7 @@
method public static float getRotationY(android.view.View);
method public static float getScaleX(android.view.View);
method public static float getScaleY(android.view.View);
+ method public static int getScrollIndicators(android.view.View);
method public static java.lang.String getTransitionName(android.view.View);
method public static float getTranslationX(android.view.View);
method public static float getTranslationY(android.view.View);
@@ -2406,6 +2454,7 @@
method public static float getZ(android.view.View);
method public static boolean hasAccessibilityDelegate(android.view.View);
method public static boolean hasNestedScrollingParent(android.view.View);
+ method public static boolean hasOnClickListeners(android.view.View);
method public static boolean hasOverlappingRendering(android.view.View);
method public static boolean hasTransientState(android.view.View);
method public static boolean isAttachedToWindow(android.view.View);
@@ -2455,6 +2504,8 @@
method public static void setSaveFromParentEnabled(android.view.View, boolean);
method public static void setScaleX(android.view.View, float);
method public static void setScaleY(android.view.View, float);
+ method public static void setScrollIndicators(android.view.View, int);
+ method public static void setScrollIndicators(android.view.View, int, int);
method public static void setTransitionName(android.view.View, java.lang.String);
method public static void setTranslationX(android.view.View, float);
method public static void setTranslationY(android.view.View, float);
@@ -2487,6 +2538,12 @@
field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
field public static final int SCROLL_AXIS_NONE = 0; // 0x0
field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+ field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+ field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+ field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+ field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+ field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
}
public class ViewConfigurationCompat {
@@ -3138,6 +3195,7 @@
method public void setStatusBarBackgroundColor(int);
field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
+ field public static final int LOCK_MODE_UNDEFINED = 3; // 0x3
field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
field public static final int STATE_DRAGGING = 1; // 0x1
field public static final int STATE_IDLE = 0; // 0x0
@@ -3215,7 +3273,7 @@
method public void scrollTargetBy(int, int);
}
- public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
+ public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
ctor public NestedScrollView(android.content.Context);
ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
@@ -3230,11 +3288,16 @@
method public void onAttachedToWindow();
method public boolean pageScroll(int);
method public void setFillViewport(boolean);
+ method public void setOnScrollChangeListener(android.support.v4.widget.NestedScrollView.OnScrollChangeListener);
method public void setSmoothScrollingEnabled(boolean);
method public final void smoothScrollBy(int, int);
method public final void smoothScrollTo(int, int);
}
+ public static abstract interface NestedScrollView.OnScrollChangeListener {
+ method public abstract void onScrollChange(android.support.v4.widget.NestedScrollView, int, int, int, int);
+ }
+
public class PopupMenuCompat {
method public static android.view.View.OnTouchListener getDragToOpenListener(java.lang.Object);
}
@@ -3272,6 +3335,7 @@
method public boolean isOverScrolled();
method public void notifyHorizontalEdgeReached(int, int, int);
method public void notifyVerticalEdgeReached(int, int, int);
+ method public boolean springBack(int, int, int, int, int, int);
method public void startScroll(int, int, int, int);
method public void startScroll(int, int, int, int, int);
}
@@ -3417,9 +3481,19 @@
}
public class TextViewCompat {
+ method public static int getMaxLines(android.widget.TextView);
+ method public static int getMinLines(android.widget.TextView);
method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, int, int, int, int);
+ method public static void setTextAppearance(android.widget.TextView, int);
+ }
+
+ public abstract interface TintableCompoundButton {
+ method public abstract android.content.res.ColorStateList getSupportButtonTintList();
+ method public abstract android.graphics.PorterDuff.Mode getSupportButtonTintMode();
+ method public abstract void setSupportButtonTintList(android.content.res.ColorStateList);
+ method public abstract void setSupportButtonTintMode(android.graphics.PorterDuff.Mode);
}
public class ViewDragHelper {
diff --git a/v4/api21/android/content/pm/ParceledListSlice.java b/v4/api21/android/content/pm/ParceledListSlice.java
new file mode 100644
index 0000000..b5183c0
--- /dev/null
+++ b/v4/api21/android/content/pm/ParceledListSlice.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * A dummy implementation for overriding a hidden framework class, ParceledListSlice.
+ * When there are duplicated signatures between app and framework code, the framework code will be
+ * run.
+ * @hide
+ */
+public class ParceledListSlice<T extends Parcelable> implements Parcelable {
+ public ParceledListSlice(List<T> list) {
+ }
+
+ @SuppressWarnings("unchecked")
+ private ParceledListSlice(Parcel p, ClassLoader loader) {
+ }
+
+ private static void verifySameType(final Class<?> expected, final Class<?> actual) {
+ }
+
+ public List<T> getList() {
+ return null;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final Parcelable.ClassLoaderCreator<ParceledListSlice> CREATOR =
+ new Parcelable.ClassLoaderCreator<ParceledListSlice>() {
+ public ParceledListSlice createFromParcel(Parcel in) {
+ return null;
+ }
+
+ @Override
+ public ParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
+ return null;
+ }
+
+ public ParceledListSlice[] newArray(int size) {
+ return null;
+ }
+ };
+}
diff --git a/v4/api21/android/service/media/IMediaBrowserService.java b/v4/api21/android/service/media/IMediaBrowserService.java
new file mode 100644
index 0000000..086dc9cc
--- /dev/null
+++ b/v4/api21/android/service/media/IMediaBrowserService.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package android.service.media;
+
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+
+/**
+ * A dummy implementation for overriding a hidden framework class, IMediaBrowserService.
+ * When there are duplicated signatures between app and framework code, the framework code will be
+ * run.
+ * TODO: Consider using aidl instead of this.
+ * @hide
+ */
+public interface IMediaBrowserService extends IInterface {
+
+ public static abstract class Stub extends Binder
+ implements IMediaBrowserService {
+ public Stub() {
+ }
+
+ public static IMediaBrowserService asInterface(IBinder obj) {
+ return null;
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws android.os.RemoteException {
+ return false;
+ }
+ }
+
+ public void connect(String pkg, Bundle rootHints, IMediaBrowserServiceCallbacks callbacks)
+ throws android.os.RemoteException;
+ public void disconnect(IMediaBrowserServiceCallbacks callbacks) throws RemoteException;
+ public void addSubscription(String uri, IMediaBrowserServiceCallbacks callbacks)
+ throws RemoteException;
+ public void removeSubscription(String uri, IMediaBrowserServiceCallbacks callbacks)
+ throws RemoteException;
+ public void getMediaItem(String uri, ResultReceiver cb) throws android.os.RemoteException;
+}
diff --git a/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java b/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java
new file mode 100644
index 0000000..fe988fe
--- /dev/null
+++ b/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+package android.service.media;
+
+import android.content.pm.ParceledListSlice;
+import android.media.session.MediaSession;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * A dummy implementation for overriding a hidden framework class, IMediaBrowserServiceCallbacks.
+ * When there are duplicated signatures between app and framework code, the framework code will be
+ * run.
+ * TODO: Consider using aidl instead of this.
+ * @hide
+ */
+public interface IMediaBrowserServiceCallbacks extends IInterface {
+ public static abstract class Stub extends Binder implements IMediaBrowserServiceCallbacks
+ {
+ public Stub() {
+ }
+
+ public static IMediaBrowserServiceCallbacks asInterface(IBinder obj) {
+ return null;
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ return false;
+ }
+
+ private static class Proxy implements IMediaBrowserServiceCallbacks
+ {
+ Proxy(IBinder remote) {
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ public String getInterfaceDescriptor() {
+ return null;
+ }
+
+ @Override
+ public void onConnect(String root, MediaSession.Token session, Bundle extras)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onConnectFailed() throws RemoteException {
+ }
+
+ @Override
+ public void onLoadChildren(String mediaId, ParceledListSlice list)
+ throws RemoteException {
+ }
+ }
+ }
+
+ public void onConnect(String root, MediaSession.Token session, Bundle extras)
+ throws RemoteException;
+ public void onConnectFailed() throws RemoteException;
+ public void onLoadChildren(String mediaId, ParceledListSlice list) throws RemoteException;
+}
+
diff --git a/v4/api21/android/support/v4/app/ActivityCompat21.java b/v4/api21/android/support/v4/app/ActivityCompat21.java
index f690fff..2e6de1e 100644
--- a/v4/api21/android/support/v4/app/ActivityCompat21.java
+++ b/v4/api21/android/support/v4/app/ActivityCompat21.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
+import android.media.session.MediaController;
import android.os.Parcelable;
import android.view.View;
@@ -31,6 +32,10 @@
class ActivityCompat21 {
+ public static void setMediaController(Activity activity, Object mediaControllerObj) {
+ activity.setMediaController((MediaController) mediaControllerObj);
+ }
+
public static void finishAfterTransition(Activity activity) {
activity.finishAfterTransition();
}
diff --git a/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java b/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
index 93990b4..2f3b45a 100644
--- a/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
+++ b/v4/api21/android/support/v4/graphics/drawable/DrawableCompatLollipop.java
@@ -37,46 +37,28 @@
}
public static void setTint(Drawable drawable, int tint) {
- if (drawable instanceof DrawableWrapperLollipop) {
- // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
- // functionality instead
- DrawableCompatBase.setTint(drawable, tint);
- } else {
- // Else, we'll use the framework API
- drawable.setTint(tint);
- }
+ drawable.setTint(tint);
}
public static void setTintList(Drawable drawable, ColorStateList tint) {
- if (drawable instanceof DrawableWrapperLollipop) {
- // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
- // functionality instead
- DrawableCompatBase.setTintList(drawable, tint);
- } else {
- // Else, we'll use the framework API
- drawable.setTintList(tint);
- }
+ drawable.setTintList(tint);
}
public static void setTintMode(Drawable drawable, PorterDuff.Mode tintMode) {
- if (drawable instanceof DrawableWrapperLollipop) {
- // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
- // functionality instead
- DrawableCompatBase.setTintMode(drawable, tintMode);
- } else {
- // Else, we'll use the framework API
- drawable.setTintMode(tintMode);
- }
+ drawable.setTintMode(tintMode);
}
- public static Drawable wrapForTinting(Drawable drawable) {
- if (drawable instanceof GradientDrawable || drawable instanceof DrawableContainer) {
- // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
- // functionality instead. We also do the same for DrawableContainers since they may
- // contain GradientDrawable instances.
- return new DrawableWrapperLollipop(drawable);
+ public static Drawable wrapForTinting(final Drawable drawable) {
+ if (!(drawable instanceof DrawableWrapperLollipop)) {
+ return new DrawableWrapperLollipop(drawable, shouldForceCompatTinting(drawable));
}
return drawable;
}
+ private static boolean shouldForceCompatTinting(Drawable drawable) {
+ // GradientDrawable on Lollipop does not support tinting, so we'll use our compatible
+ // functionality instead. We also do the same for DrawableContainers since they may
+ // contain GradientDrawable instances.
+ return drawable instanceof GradientDrawable || drawable instanceof DrawableContainer;
+ }
}
diff --git a/v4/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java b/v4/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java
index 1f15040..9533afd 100644
--- a/v4/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java
+++ b/v4/api21/android/support/v4/graphics/drawable/DrawableWrapperLollipop.java
@@ -16,15 +16,24 @@
package android.support.v4.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Outline;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
class DrawableWrapperLollipop extends DrawableWrapperKitKat {
+ private final boolean mUseCompatTinting;
+
DrawableWrapperLollipop(Drawable drawable) {
+ this(drawable, false);
+ }
+
+ DrawableWrapperLollipop(Drawable drawable, boolean useCompatTinting) {
super(drawable);
+ mUseCompatTinting = useCompatTinting;
}
@Override
@@ -56,4 +65,47 @@
public Rect getDirtyBounds() {
return mDrawable.getDirtyBounds();
}
+
+ @Override
+ public void setTintList(ColorStateList tint) {
+ if (mUseCompatTinting) {
+ setCompatTintList(tint);
+ } else {
+ mDrawable.setTintList(tint);
+ }
+ }
+
+ @Override
+ public void setTint(int tintColor) {
+ if (mUseCompatTinting) {
+ setCompatTint(tintColor);
+ } else {
+ mDrawable.setTint(tintColor);
+ }
+ }
+
+ @Override
+ public void setTintMode(PorterDuff.Mode tintMode) {
+ if (mUseCompatTinting) {
+ setCompatTintMode(tintMode);
+ } else {
+ mDrawable.setTintMode(tintMode);
+ }
+ }
+
+ @Override
+ public boolean setState(int[] stateSet) {
+ if (super.setState(stateSet)) {
+ // Manually invalidate because the framework doesn't currently force an invalidation
+ // on a state change
+ invalidateSelf();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean isCompatTintEnabled() {
+ return mUseCompatTinting;
+ }
}
diff --git a/v4/api21/android/support/v4/media/MediaBrowserCompatApi21.java b/v4/api21/android/support/v4/media/MediaBrowserCompatApi21.java
new file mode 100644
index 0000000..c6ccb14
--- /dev/null
+++ b/v4/api21/android/support/v4/media/MediaBrowserCompatApi21.java
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.media.browse.MediaBrowser;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.support.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class MediaBrowserCompatApi21 {
+ static final String NULL_MEDIA_ITEM_ID =
+ "android.support.v4.media.MediaBrowserCompat.NULL_MEDIA_ITEM";
+
+ public static Object createConnectionCallback(ConnectionCallback callback) {
+ return new ConnectionCallbackProxy<>(callback);
+ }
+
+ public static Object createBrowser(Context context, ComponentName serviceComponent,
+ Object callback, Bundle rootHints) {
+ return new MediaBrowser(context, serviceComponent,
+ (MediaBrowser.ConnectionCallback) callback, rootHints);
+ }
+
+ public static void connect(Object browserObj) {
+ ((MediaBrowser)browserObj).connect();
+ }
+
+ public static void disconnect(Object browserObj) {
+ ((MediaBrowser)browserObj).disconnect();
+
+ }
+
+ public static boolean isConnected(Object browserObj) {
+ return ((MediaBrowser)browserObj).isConnected();
+ }
+
+ public static ComponentName getServiceComponent(Object browserObj) {
+ return ((MediaBrowser)browserObj).getServiceComponent();
+ }
+
+ public static String getRoot(Object browserObj) {
+ return ((MediaBrowser)browserObj).getRoot();
+ }
+
+ public static Bundle getExtras(Object browserObj) {
+ return ((MediaBrowser)browserObj).getExtras();
+ }
+
+ public static Object getSessionToken(Object browserObj) {
+ return ((MediaBrowser)browserObj).getSessionToken();
+ }
+
+ public static Object createSubscriptionCallback(SubscriptionCallback callback) {
+ return new SubscriptionCallbackProxy<>(callback);
+ }
+
+ public static void subscribe(
+ Object browserObj, String parentId, Object subscriptionCallbackObj) {
+ ((MediaBrowser)browserObj).subscribe(parentId,
+ (MediaBrowser.SubscriptionCallback) subscriptionCallbackObj);
+ }
+
+ public static void unsubscribe(Object browserObj, String parentId) {
+ ((MediaBrowser)browserObj).unsubscribe(parentId);
+ }
+
+ interface ConnectionCallback {
+ void onConnected();
+ void onConnectionSuspended();
+ void onConnectionFailed();
+ }
+
+ static class ConnectionCallbackProxy<T extends ConnectionCallback>
+ extends MediaBrowser.ConnectionCallback {
+ protected final T mConnectionCallback;
+
+ public ConnectionCallbackProxy(T connectionCallback) {
+ mConnectionCallback = connectionCallback;
+ }
+
+ @Override
+ public void onConnected() {
+ mConnectionCallback.onConnected();
+ }
+
+ @Override
+ public void onConnectionSuspended() {
+ mConnectionCallback.onConnectionSuspended();
+ }
+
+ @Override
+ public void onConnectionFailed() {
+ mConnectionCallback.onConnectionFailed();
+ }
+ }
+
+ interface SubscriptionCallback {
+ void onChildrenLoaded(@NonNull String parentId, List<Parcel> children);
+ void onError(@NonNull String parentId);
+ }
+
+ static class SubscriptionCallbackProxy<T extends SubscriptionCallback>
+ extends MediaBrowser.SubscriptionCallback {
+ protected final T mSubscriptionCallback;
+
+ public SubscriptionCallbackProxy(T callback) {
+ mSubscriptionCallback = callback;
+ }
+
+ @Override
+ public void onChildrenLoaded(@NonNull String parentId,
+ List<MediaBrowser.MediaItem> children) {
+ List<Parcel> parcelList = null;
+ if (children != null && children.size() == 1
+ && children.get(0).getMediaId().equals(NULL_MEDIA_ITEM_ID)) {
+ children = null;
+ }
+ if (children != null) {
+ parcelList = new ArrayList<>();
+ for (MediaBrowser.MediaItem item : children) {
+ Parcel parcel = Parcel.obtain();
+ item.writeToParcel(parcel, 0);
+ parcelList.add(parcel);
+ }
+ }
+ mSubscriptionCallback.onChildrenLoaded(parentId, parcelList);
+ }
+
+ @Override
+ public void onError(@NonNull String parentId) {
+ mSubscriptionCallback.onError(parentId);
+ }
+ }
+}
diff --git a/v4/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java b/v4/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java
new file mode 100644
index 0000000..a1506d3
--- /dev/null
+++ b/v4/api21/android/support/v4/media/MediaBrowserServiceCompatApi21.java
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.media.MediaDescription;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaSession;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.service.media.IMediaBrowserService;
+import android.service.media.IMediaBrowserServiceCallbacks;
+import android.service.media.MediaBrowserService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class MediaBrowserServiceCompatApi21 {
+
+ public static Object createService() {
+ return new MediaBrowserServiceAdaptorApi21();
+ }
+
+ public static void onCreate(Object serviceObj, ServiceImplApi21 serviceImpl) {
+ ((MediaBrowserServiceAdaptorApi21) serviceObj).onCreate(serviceImpl);
+ }
+
+ public static IBinder onBind(Object serviceObj, Intent intent) {
+ return ((MediaBrowserServiceAdaptorApi21) serviceObj).onBind(intent);
+ }
+
+ public interface ServiceImplApi21 {
+ void connect(final String pkg, final Bundle rootHints, final ServiceCallbacks callbacks);
+ void disconnect(final ServiceCallbacks callbacks);
+ void addSubscription(final String id, final ServiceCallbacks callbacks);
+ void removeSubscription(final String id, final ServiceCallbacks callbacks);
+ }
+
+ public interface ServiceCallbacks {
+ IBinder asBinder();
+ void onConnect(String root, Object session, Bundle extras) throws RemoteException;
+ void onConnectFailed() throws RemoteException;
+ void onLoadChildren(String mediaId, List<Parcel> list) throws RemoteException;
+ }
+
+ public static class ServiceCallbacksApi21 implements ServiceCallbacks {
+ private static final ParceledListSlice sNullParceledListSlice;
+ static {
+ MediaDescription nullDescription = new MediaDescription.Builder().setMediaId(
+ MediaBrowserCompatApi21.NULL_MEDIA_ITEM_ID).build();
+ MediaBrowser.MediaItem nullMediaItem = new MediaBrowser.MediaItem(nullDescription, 0);
+ List<MediaBrowser.MediaItem> nullMediaItemList = new ArrayList<>();
+ nullMediaItemList.add(nullMediaItem);
+ sNullParceledListSlice = new ParceledListSlice(nullMediaItemList);
+ }
+
+ private final IMediaBrowserServiceCallbacks mCallbacks;
+
+ ServiceCallbacksApi21(IMediaBrowserServiceCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ public IBinder asBinder() {
+ return mCallbacks.asBinder();
+ }
+
+ public void onConnect(String root, Object session, Bundle extras) throws RemoteException {
+ mCallbacks.onConnect(root, (MediaSession.Token) session, extras);
+ }
+
+ public void onConnectFailed() throws RemoteException {
+ mCallbacks.onConnectFailed();
+ }
+
+ public void onLoadChildren(String mediaId, List<Parcel> list) throws RemoteException {
+ List<MediaBrowser.MediaItem> itemList = null;
+ if (list != null) {
+ itemList = new ArrayList<>();
+ for (Parcel parcel : list) {
+ parcel.setDataPosition(0);
+ itemList.add(MediaBrowser.MediaItem.CREATOR.createFromParcel(parcel));
+ parcel.recycle();
+ }
+ }
+ ParceledListSlice<MediaBrowser.MediaItem> pls;
+ if (Build.VERSION.SDK_INT > 23) {
+ pls = itemList == null ? null : new ParceledListSlice(itemList);
+ } else {
+ pls = itemList == null ? sNullParceledListSlice : new ParceledListSlice(itemList);
+ }
+ mCallbacks.onLoadChildren(mediaId, pls);
+ }
+ }
+
+ static class MediaBrowserServiceAdaptorApi21 {
+ ServiceBinderProxyApi21 mBinder;
+
+ public void onCreate(ServiceImplApi21 serviceImpl) {
+ mBinder = new ServiceBinderProxyApi21(serviceImpl);
+ }
+
+ public IBinder onBind(Intent intent) {
+ if (MediaBrowserService.SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mBinder;
+ }
+ return null;
+ }
+
+ static class ServiceBinderProxyApi21 extends IMediaBrowserService.Stub {
+ final ServiceImplApi21 mServiceImpl;
+
+ ServiceBinderProxyApi21(ServiceImplApi21 serviceImpl) {
+ mServiceImpl = serviceImpl;
+ }
+
+ @Override
+ public void connect(final String pkg, final Bundle rootHints,
+ final IMediaBrowserServiceCallbacks callbacks) {
+ mServiceImpl.connect(pkg, rootHints, new ServiceCallbacksApi21(callbacks));
+ }
+
+ @Override
+ public void disconnect(final IMediaBrowserServiceCallbacks callbacks) {
+ mServiceImpl.disconnect(new ServiceCallbacksApi21(callbacks));
+ }
+
+
+ @Override
+ public void addSubscription(final String id,
+ final IMediaBrowserServiceCallbacks callbacks) {
+ mServiceImpl.addSubscription(id, new ServiceCallbacksApi21(callbacks));
+ }
+
+ @Override
+ public void removeSubscription(final String id,
+ final IMediaBrowserServiceCallbacks callbacks) {
+ mServiceImpl.removeSubscription(id, new ServiceCallbacksApi21(callbacks));
+ }
+
+ @Override
+ public void getMediaItem(final String mediaId, final ResultReceiver receiver) {
+ // No operation since this method is added in API 23.
+ }
+ }
+ }
+}
diff --git a/v4/api21/android/support/v4/media/MediaDescriptionCompatApi21.java b/v4/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
index 991515a..234a77a 100644
--- a/v4/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
+++ b/v4/api21/android/support/v4/media/MediaDescriptionCompatApi21.java
@@ -21,7 +21,7 @@
import android.os.Bundle;
import android.os.Parcel;
-public class MediaDescriptionCompatApi21 {
+class MediaDescriptionCompatApi21 {
public static String getMediaId(Object descriptionObj) {
return ((MediaDescription) descriptionObj).getMediaId();
@@ -59,7 +59,7 @@
return MediaDescription.CREATOR.createFromParcel(in);
}
- public static class Builder {
+ static class Builder {
public static Object newInstance() {
return new MediaDescription.Builder();
}
diff --git a/v4/api21/android/support/v4/media/MediaMetadataCompatApi21.java b/v4/api21/android/support/v4/media/MediaMetadataCompatApi21.java
index eddcf76..fd51f78 100644
--- a/v4/api21/android/support/v4/media/MediaMetadataCompatApi21.java
+++ b/v4/api21/android/support/v4/media/MediaMetadataCompatApi21.java
@@ -19,6 +19,7 @@
import android.graphics.Bitmap;
import android.media.MediaMetadata;
import android.media.Rating;
+import android.os.Parcel;
import java.util.Set;
@@ -43,6 +44,14 @@
return ((MediaMetadata) metadataObj).getText(key);
}
+ public static void writeToParcel(Object metadataObj, Parcel dest, int flags) {
+ ((MediaMetadata) metadataObj).writeToParcel(dest, flags);
+ }
+
+ public static Object createFromParcel(Parcel in) {
+ return MediaMetadata.CREATOR.createFromParcel(in);
+ }
+
public static class Builder {
public static Object newInstance() {
return new MediaMetadata.Builder();
diff --git a/v4/api21/android/support/v4/media/session/MediaSessionCompatApi21.java b/v4/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
index 8094391..b3e7fd1 100644
--- a/v4/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
+++ b/v4/api21/android/support/v4/media/session/MediaSessionCompatApi21.java
@@ -132,7 +132,7 @@
((MediaSession) sessionObj).setExtras(extras);
}
- public static interface Callback {
+ static interface Callback {
public void onCommand(String command, Bundle extras, ResultReceiver cb);
public boolean onMediaButtonEvent(Intent mediaButtonIntent);
public void onPlay();
diff --git a/v4/api22/android/support/v4/graphics/drawable/DrawableCompatApi22.java b/v4/api22/android/support/v4/graphics/drawable/DrawableCompatApi22.java
index bfd2bea..50f2657 100644
--- a/v4/api22/android/support/v4/graphics/drawable/DrawableCompatApi22.java
+++ b/v4/api22/android/support/v4/graphics/drawable/DrawableCompatApi22.java
@@ -24,8 +24,8 @@
class DrawableCompatApi22 {
public static Drawable wrapForTinting(Drawable drawable) {
- // We don't need to wrap anything in Lollipop-MR1
- return drawable;
+ // We need to wrap to force an invalidation on any state change
+ return new DrawableWrapperLollipop(drawable);
}
}
diff --git a/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java b/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java
index 64a1206..72e07bf 100644
--- a/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java
+++ b/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java
@@ -22,7 +22,7 @@
/**
* AppOpsManager implementations for API 23.
*/
-public class AppOpsManagerCompat23 {
+class AppOpsManagerCompat23 {
public static String permissionToOp(String permission) {
return AppOpsManager.permissionToOp(permission);
}
diff --git a/v4/api23/android/support/v4/content/ResourcesCompatApi23.java b/v4/api23/android/support/v4/content/ResourcesCompatApi23.java
new file mode 100644
index 0000000..c44f9ce
--- /dev/null
+++ b/v4/api23/android/support/v4/content/ResourcesCompatApi23.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.content.res;
+
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+
+class ResourcesCompatApi23 {
+ public static int getColor(Resources res, int id, Theme theme) throws NotFoundException {
+ return res.getColor(id, theme);
+ }
+
+ public static ColorStateList getColorStateList(Resources res, int id, Theme theme)
+ throws NotFoundException {
+ return res.getColorStateList(id, theme);
+ }
+}
diff --git a/v4/api23/android/support/v4/media/MediaBrowserCompatApi23.java b/v4/api23/android/support/v4/media/MediaBrowserCompatApi23.java
new file mode 100644
index 0000000..1e9df1a
--- /dev/null
+++ b/v4/api23/android/support/v4/media/MediaBrowserCompatApi23.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.media.browse.MediaBrowser;
+import android.os.Parcel;
+import android.support.annotation.NonNull;
+
+class MediaBrowserCompatApi23 {
+
+ public static Object createItemCallback(ItemCallback callback) {
+ return new ItemCallbackProxy<>(callback);
+ }
+
+ public static void getItem(Object browserObj, String mediaId, Object itemCallbackObj) {
+ ((MediaBrowser) browserObj).getItem(mediaId, ((MediaBrowser.ItemCallback) itemCallbackObj));
+ }
+
+ interface ItemCallback {
+ void onItemLoaded(Parcel itemParcel);
+ void onError(@NonNull String itemId);
+ }
+
+ static class ItemCallbackProxy<T extends ItemCallback> extends MediaBrowser.ItemCallback {
+ protected final T mItemCallback;
+
+ public ItemCallbackProxy(T callback) {
+ mItemCallback = callback;
+ }
+
+ @Override
+ public void onItemLoaded(MediaBrowser.MediaItem item) {
+ Parcel parcel = Parcel.obtain();
+ item.writeToParcel(parcel, 0);
+ mItemCallback.onItemLoaded(parcel);
+ }
+
+ @Override
+ public void onError(@NonNull String itemId) {
+ mItemCallback.onError(itemId);
+ }
+ }
+}
diff --git a/v4/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java b/v4/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java
new file mode 100644
index 0000000..fcaea40
--- /dev/null
+++ b/v4/api23/android/support/v4/media/MediaBrowserServiceCompatApi23.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.media.browse.MediaBrowser;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ResultReceiver;
+import android.service.media.MediaBrowserService;
+import android.util.Log;
+
+class MediaBrowserServiceCompatApi23 extends MediaBrowserServiceCompatApi21 {
+ private static final String TAG = "MediaBrowserServiceCompatApi21";
+
+ public static Object createService() {
+ return new MediaBrowserServiceAdaptorApi23();
+ }
+
+ public static void onCreate(Object serviceObj, ServiceImplApi23 serviceImpl) {
+ ((MediaBrowserServiceAdaptorApi23) serviceObj).onCreate(serviceImpl);
+ }
+
+ public interface ServiceImplApi23 extends ServiceImplApi21 {
+ void getMediaItem(final String mediaId, final ItemCallback cb);
+ }
+
+ public interface ItemCallback {
+ void onItemLoaded(int resultCode, Bundle resultData, Parcel itemParcel);
+ }
+
+ static class MediaBrowserServiceAdaptorApi23 extends MediaBrowserServiceAdaptorApi21 {
+
+ public void onCreate(ServiceImplApi23 serviceImpl) {
+ mBinder = new ServiceBinderProxyApi23(serviceImpl);
+ }
+
+ private static class ServiceBinderProxyApi23 extends ServiceBinderProxyApi21 {
+ ServiceImplApi23 mServiceImpl;
+
+ ServiceBinderProxyApi23(ServiceImplApi23 serviceImpl) {
+ super(serviceImpl);
+ mServiceImpl = serviceImpl;
+ }
+
+ @Override
+ public void getMediaItem(final String mediaId, final ResultReceiver receiver) {
+ final String KEY_MEDIA_ITEM;
+ try {
+ KEY_MEDIA_ITEM = (String) MediaBrowserService.class.getDeclaredField(
+ "KEY_MEDIA_ITEM").get(null);
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ Log.i(TAG, "Failed to get KEY_MEDIA_ITEM via reflection", e);
+ return;
+ }
+
+ mServiceImpl.getMediaItem(mediaId, new ItemCallback() {
+ @Override
+ public void onItemLoaded(int resultCode, Bundle resultData, Parcel itemParcel) {
+ if (itemParcel != null) {
+ itemParcel.setDataPosition(0);
+ MediaBrowser.MediaItem item =
+ MediaBrowser.MediaItem.CREATOR.createFromParcel(itemParcel);
+ resultData.putParcelable(KEY_MEDIA_ITEM, item);
+ itemParcel.recycle();
+ }
+ receiver.send(resultCode, resultData);
+ }
+ });
+ }
+ }
+ }
+}
diff --git a/v4/api23/android/support/v4/text/ICUCompatApi23.java b/v4/api23/android/support/v4/text/ICUCompatApi23.java
index f013522..1a3c54f 100644
--- a/v4/api23/android/support/v4/text/ICUCompatApi23.java
+++ b/v4/api23/android/support/v4/text/ICUCompatApi23.java
@@ -22,7 +22,7 @@
import java.lang.reflect.Method;
import java.util.Locale;
-public class ICUCompatApi23 {
+class ICUCompatApi23 {
private static final String TAG = "ICUCompatIcs";
diff --git a/v4/api23/android/support/v4/view/ViewCompatMarshmallow.java b/v4/api23/android/support/v4/view/ViewCompatMarshmallow.java
new file mode 100644
index 0000000..16d3ae8
--- /dev/null
+++ b/v4/api23/android/support/v4/view/ViewCompatMarshmallow.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.view;
+
+import android.view.View;
+
+class ViewCompatMarshmallow {
+ public static void setScrollIndicators(View view, int indicators) {
+ view.setScrollIndicators(indicators);
+ }
+
+ public static void setScrollIndicators(View view, int indicators, int mask) {
+ view.setScrollIndicators(indicators, mask);
+ }
+
+ public static int getScrollIndicators(View view) {
+ return view.getScrollIndicators();
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java b/v4/api23/android/support/v4/widget/TextViewCompatApi23.java
similarity index 60%
copy from v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
copy to v4/api23/android/support/v4/widget/TextViewCompatApi23.java
index 8eea38d..8370bfc 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
+++ b/v4/api23/android/support/v4/widget/TextViewCompatApi23.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,17 +14,14 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v4.widget;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
+import android.support.annotation.IdRes;
+import android.support.annotation.NonNull;
+import android.widget.TextView;
-/**
- * @hide
- */
-public class TintInfo {
- public ColorStateList mTintList;
- public PorterDuff.Mode mTintMode;
- public boolean mHasTintMode;
- public boolean mHasTintList;
+class TextViewCompatApi23 {
+ public static void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+ textView.setTextAppearance(resId);
+ }
}
diff --git a/v4/build.gradle b/v4/build.gradle
index a056973..ba65cab 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -64,6 +64,10 @@
// depend on the generation of this jar. This is done below
// when manipulating the libraryVariants.
compile files(internalJar.archivePath)
+
+ androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
+ androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
+ testCompile 'junit:junit:4.12'
}
android {
@@ -73,6 +77,8 @@
minSdkVersion 4
// TODO: get target from branch
//targetSdkVersion 19
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
sourceSets {
@@ -82,6 +88,8 @@
androidTest.setRoot('tests')
androidTest.java.srcDir 'tests/java'
+ androidTest.res.srcDir 'tests/res'
+ androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
}
lintOptions {
@@ -93,6 +101,10 @@
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
+
+ testOptions {
+ unitTests.returnDefaultValues = true
+ }
}
android.libraryVariants.all { variant ->
@@ -124,6 +136,8 @@
def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
+ exclude('android/content/pm/**')
+ exclude('android/service/media/**')
}
project.ext.allSS.each { ss ->
@@ -135,6 +149,17 @@
artifacts.add('archives', sourcesJarTask);
}
+// TODO make this generic for all projects
+afterEvaluate {
+ def originalTask = tasks['packageDebugAndroidTest']
+ tasks['assembleDebugAndroidTest'].doLast {
+ copy {
+ from(originalTask.outputFile)
+ into(rootProject.ext.testApkDistOut)
+ }
+ }
+}
+
uploadArchives {
repositories {
mavenDeployer {
diff --git a/v4/donut/android/support/v4/animation/ValueAnimatorCompat.java b/v4/donut/android/support/v4/animation/ValueAnimatorCompat.java
index 6d98c97..07cc602 100644
--- a/v4/donut/android/support/v4/animation/ValueAnimatorCompat.java
+++ b/v4/donut/android/support/v4/animation/ValueAnimatorCompat.java
@@ -19,7 +19,7 @@
import android.view.View;
/**
- * Compatibility implementation for {@link android.animation.Animator}.
+ * Compatibility implementation for {@code android.animation.ValueAnimator}.
*
* @hide
*/
diff --git a/v4/donut/android/support/v4/graphics/drawable/DrawableCompatBase.java b/v4/donut/android/support/v4/graphics/drawable/DrawableCompatBase.java
index 4809618..fe0163d 100644
--- a/v4/donut/android/support/v4/graphics/drawable/DrawableCompatBase.java
+++ b/v4/donut/android/support/v4/graphics/drawable/DrawableCompatBase.java
@@ -27,19 +27,19 @@
public static void setTint(Drawable drawable, int tint) {
if (drawable instanceof DrawableWrapper) {
- ((DrawableWrapper) drawable).setTint(tint);
+ ((DrawableWrapper) drawable).setCompatTint(tint);
}
}
public static void setTintList(Drawable drawable, ColorStateList tint) {
if (drawable instanceof DrawableWrapper) {
- ((DrawableWrapper) drawable).setTintList(tint);
+ ((DrawableWrapper) drawable).setCompatTintList(tint);
}
}
public static void setTintMode(Drawable drawable, PorterDuff.Mode tintMode) {
if (drawable instanceof DrawableWrapper) {
- ((DrawableWrapper) drawable).setTintMode(tintMode);
+ ((DrawableWrapper) drawable).setCompatTintMode(tintMode);
}
}
diff --git a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapper.java b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapper.java
index 1073f34..edbe5ad 100644
--- a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapper.java
+++ b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapper.java
@@ -28,11 +28,11 @@
*/
public interface DrawableWrapper {
- void setTint(int tint);
+ void setCompatTint(int tint);
- void setTintList(ColorStateList tint);
+ void setCompatTintList(ColorStateList tint);
- void setTintMode(PorterDuff.Mode tintMode);
+ void setCompatTintMode(PorterDuff.Mode tintMode);
Drawable getWrappedDrawable();
diff --git a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
index 9293520..300e2e8 100644
--- a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
+++ b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
@@ -89,7 +89,8 @@
@Override
public boolean isStateful() {
- return (mTintList != null && mTintList.isStateful()) || mDrawable.isStateful();
+ final ColorStateList tintList = isCompatTintEnabled() ? mTintList : null;
+ return (tintList != null && tintList.isStateful()) || mDrawable.isStateful();
}
@Override
@@ -188,30 +189,38 @@
}
@Override
- public void setTint(int tint) {
- setTintList(ColorStateList.valueOf(tint));
+ public void setCompatTint(int tint) {
+ setCompatTintList(ColorStateList.valueOf(tint));
}
@Override
- public void setTintList(ColorStateList tint) {
- mTintList = tint;
- updateTint(getState());
+ public void setCompatTintList(ColorStateList tint) {
+ if (mTintList != tint) {
+ mTintList = tint;
+ updateTint(getState());
+ }
}
@Override
- public void setTintMode(PorterDuff.Mode tintMode) {
- mTintMode = tintMode;
- updateTint(getState());
+ public void setCompatTintMode(PorterDuff.Mode tintMode) {
+ if (mTintMode != tintMode) {
+ mTintMode = tintMode;
+ updateTint(getState());
+ }
}
private boolean updateTint(int[] state) {
+ if (!isCompatTintEnabled()) {
+ // If compat tinting is not enabled, fail fast
+ return false;
+ }
+
if (mTintList != null && mTintMode != null) {
final int color = mTintList.getColorForState(state, mTintList.getDefaultColor());
- final PorterDuff.Mode mode = mTintMode;
- if (!mColorFilterSet || color != mCurrentColor || mode != mCurrentMode) {
- setColorFilter(color, mode);
+ if (!mColorFilterSet || color != mCurrentColor || mTintMode != mCurrentMode) {
+ setColorFilter(color, mTintMode);
mCurrentColor = color;
- mCurrentMode = mode;
+ mCurrentMode = mTintMode;
mColorFilterSet = true;
return true;
}
@@ -236,13 +245,26 @@
if (mDrawable != null) {
mDrawable.setCallback(null);
}
+ mDrawable = null;
+
+ if (drawable != null) {
+ // Copy over the bounds from the drawable
+ setBounds(drawable.getBounds());
+ // Set ourselves as the callback for invalidations
+ drawable.setCallback(this);
+ } else {
+ // Clear our bounds
+ setBounds(0, 0, 0, 0);
+ }
mDrawable = drawable;
- if (drawable != null) {
- drawable.setCallback(this);
- }
// Invalidate ourselves
invalidateSelf();
}
+
+ protected boolean isCompatTintEnabled() {
+ // It's enabled by default on Donut
+ return true;
+ }
}
diff --git a/v4/froyo/android/support/v4/media/session/MediaSessionCompatApi8.java b/v4/froyo/android/support/v4/media/session/MediaSessionCompatApi8.java
index f49eb2b..d03287fe 100644
--- a/v4/froyo/android/support/v4/media/session/MediaSessionCompatApi8.java
+++ b/v4/froyo/android/support/v4/media/session/MediaSessionCompatApi8.java
@@ -19,7 +19,7 @@
import android.content.Context;
import android.media.AudioManager;
-public class MediaSessionCompatApi8 {
+class MediaSessionCompatApi8 {
public static void registerMediaButtonEventReceiver(Context context, ComponentName mbr) {
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
am.registerMediaButtonEventReceiver(mbr);
diff --git a/v4/gingerbread/android/support/v4/widget/ScrollerCompatGingerbread.java b/v4/gingerbread/android/support/v4/widget/ScrollerCompatGingerbread.java
index 429e864..61c9a03 100644
--- a/v4/gingerbread/android/support/v4/widget/ScrollerCompatGingerbread.java
+++ b/v4/gingerbread/android/support/v4/widget/ScrollerCompatGingerbread.java
@@ -87,4 +87,9 @@
public static int getFinalY(Object scroller) {
return ((OverScroller) scroller).getFinalY();
}
+
+ public static boolean springBack(Object scroller, int startX, int startY, int minX, int maxX,
+ int minY, int maxY) {
+ return ((OverScroller) scroller).springBack(startX, startY, minX, maxX, minY, maxY);
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java b/v4/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java
similarity index 61%
copy from v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java
copy to v4/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java
index c84fda0..fa6af47 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java
+++ b/v4/honeycomb/android/support/v4/content/ExecutorCompatHoneycomb.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v4.content;
-import android.graphics.Rect;
+import android.os.AsyncTask;
+
+import java.util.concurrent.Executor;
/**
+ * Implementation of parallel executor compatibility that can call Honeycomb APIs.
* @hide
*/
-public interface FitWindowsViewGroup {
-
- public interface OnFitSystemWindowsListener {
- void onFitSystemWindows(Rect insets);
+class ExecutorCompatHoneycomb {
+ public static Executor getParallelExecutor() {
+ return AsyncTask.THREAD_POOL_EXECUTOR;
}
-
- public void setOnFitSystemWindowsListener(OnFitSystemWindowsListener listener);
-
}
diff --git a/v4/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java b/v4/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java
new file mode 100644
index 0000000..780345c
--- /dev/null
+++ b/v4/ics-mr1/android/support/v4/view/ViewCompatICSMr1.java
@@ -0,0 +1,32 @@
+/*
+ * 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.view;
+
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * Helper for accessing newer features in View introduced in ICS Mr1.
+ */
+class ViewCompatICSMr1 {
+ public static boolean hasOnClickListeners(View v) {
+ return v.hasOnClickListeners();
+ }
+}
diff --git a/v4/ics/android/support/v4/media/session/MediaSessionCompatApi14.java b/v4/ics/android/support/v4/media/session/MediaSessionCompatApi14.java
index de644e6..3378e1e 100644
--- a/v4/ics/android/support/v4/media/session/MediaSessionCompatApi14.java
+++ b/v4/ics/android/support/v4/media/session/MediaSessionCompatApi14.java
@@ -25,7 +25,7 @@
import android.os.Bundle;
import android.os.ResultReceiver;
-public class MediaSessionCompatApi14 {
+class MediaSessionCompatApi14 {
/***** RemoteControlClient States, we only need none as the others were public *******/
final static int RCC_PLAYSTATE_NONE = 0;
@@ -224,7 +224,7 @@
}
}
- public static interface Callback {
+ static interface Callback {
public void onCommand(String command, Bundle extras, ResultReceiver cb);
public boolean onMediaButtonEvent(Intent mediaButtonIntent);
diff --git a/v4/ics/android/support/v4/view/ViewParentCompatICS.java b/v4/ics/android/support/v4/view/ViewParentCompatICS.java
index 251de0e..f9fc5a5 100644
--- a/v4/ics/android/support/v4/view/ViewParentCompatICS.java
+++ b/v4/ics/android/support/v4/view/ViewParentCompatICS.java
@@ -23,7 +23,7 @@
/**
* ICS-specific ViewParent API implementation.
*/
-public class ViewParentCompatICS {
+class ViewParentCompatICS {
public static boolean requestSendAccessibilityEvent(
ViewParent parent, View child, AccessibilityEvent event) {
return parent.requestSendAccessibilityEvent(child, event);
diff --git a/v4/java/android/support/v4/animation/AnimatorCompatHelper.java b/v4/java/android/support/v4/animation/AnimatorCompatHelper.java
index 8fa3679..6ebe5c8 100644
--- a/v4/java/android/support/v4/animation/AnimatorCompatHelper.java
+++ b/v4/java/android/support/v4/animation/AnimatorCompatHelper.java
@@ -19,9 +19,12 @@
import android.os.Build;
import android.view.View;
-abstract public class AnimatorCompatHelper {
+/**
+ * @hide
+ */
+public final class AnimatorCompatHelper {
- static AnimatorProvider IMPL;
+ private final static AnimatorProvider IMPL;
static {
if (Build.VERSION.SDK_INT >= 12) {
@@ -35,9 +38,7 @@
return IMPL.emptyValueAnimator();
}
- AnimatorCompatHelper() {
-
- }
+ private AnimatorCompatHelper() {}
public static void clearInterpolator(View view) {
IMPL.clearInterpolator(view);
diff --git a/v4/java/android/support/v4/app/FragmentActivity.java b/v4/java/android/support/v4/app/FragmentActivity.java
index 1dd6d01..59881a2 100644
--- a/v4/java/android/support/v4/app/FragmentActivity.java
+++ b/v4/java/android/support/v4/app/FragmentActivity.java
@@ -27,6 +27,7 @@
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.util.SimpleArrayMap;
import android.util.AttributeSet;
import android.util.Log;
@@ -124,6 +125,8 @@
SimpleArrayMap<String, LoaderManager> loaders;
}
+ MediaControllerCompat mMediaController;
+
// ------------------------------------------------------------------------
// HOOKS INTO ACTIVITY
// ------------------------------------------------------------------------
@@ -169,6 +172,39 @@
}
/**
+ * Sets a {@link MediaControllerCompat} for later retrieval via
+ * {@link #getSupportMediaController()}.
+ *
+ * <p>On API 21 and later, this controller will be tied to the window of the activity and
+ * media key and volume events which are received while the Activity is in the foreground
+ * will be forwarded to the controller and used to invoke transport controls or adjust the
+ * volume. Prior to API 21, the global handling of media key and volume events through an
+ * active {@link android.support.v4.media.session.MediaSessionCompat} and media button receiver
+ * will still be respected.</p>
+ *
+ * @param mediaController The controller for the session which should receive
+ * media keys and volume changes on API 21 and later.
+ * @see #setMediaController(android.media.session.MediaController)
+ */
+ final public void setSupportMediaController(MediaControllerCompat mediaController) {
+ mMediaController = mediaController;
+ if (android.os.Build.VERSION.SDK_INT >= 21) {
+ ActivityCompat21.setMediaController(this, mediaController.getMediaController());
+ }
+ }
+
+ /**
+ * Retrieves the current {@link MediaControllerCompat} for sending media key and volume events.
+ *
+ * @return The controller which should receive events.
+ * @see #setSupportMediaController(android.support.v4.media.session.MediaController)
+ * @see #getMediaController()
+ */
+ final public MediaControllerCompat getSupportMediaController() {
+ return mMediaController;
+ }
+
+ /**
* Reverses the Activity Scene entry Transition and triggers the calling Activity
* to reverse its exit Transition. When the exit Transition completes,
* {@link #finish()} is called. If no entry Transition was used, finish() is called
diff --git a/v4/java/android/support/v4/app/FragmentManager.java b/v4/java/android/support/v4/app/FragmentManager.java
index adf8892..50bc88b 100644
--- a/v4/java/android/support/v4/app/FragmentManager.java
+++ b/v4/java/android/support/v4/app/FragmentManager.java
@@ -52,6 +52,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -414,8 +415,9 @@
static class AnimateOnHWLayerIfNeededListener implements AnimationListener {
+ private AnimationListener mOrignalListener = null;
private boolean mShouldRunOnHWLayer = false;
- private View mView;
+ private View mView = null;
public AnimateOnHWLayerIfNeededListener(final View v, Animation anim) {
if (v == null || anim == null) {
return;
@@ -423,24 +425,38 @@
mView = v;
}
+ public AnimateOnHWLayerIfNeededListener(final View v, Animation anim,
+ AnimationListener listener) {
+ if (v == null || anim == null) {
+ return;
+ }
+ mOrignalListener = listener;
+ mView = v;
+ }
+
@Override
@CallSuper
public void onAnimationStart(Animation animation) {
- mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
- if (mShouldRunOnHWLayer) {
- mView.post(new Runnable() {
- @Override
- public void run() {
- ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_HARDWARE, null);
- }
- });
+ if (mView != null) {
+ mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
+ if (mShouldRunOnHWLayer) {
+ mView.post(new Runnable() {
+ @Override
+ public void run() {
+ ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_HARDWARE, null);
+ }
+ });
+ }
+ }
+ if (mOrignalListener != null) {
+ mOrignalListener.onAnimationStart(animation);
}
}
@Override
@CallSuper
public void onAnimationEnd(Animation animation) {
- if (mShouldRunOnHWLayer) {
+ if (mView != null && mShouldRunOnHWLayer) {
mView.post(new Runnable() {
@Override
public void run() {
@@ -448,10 +464,16 @@
}
});
}
+ if (mOrignalListener != null) {
+ mOrignalListener.onAnimationEnd(animation);
+ }
}
@Override
public void onAnimationRepeat(Animation animation) {
+ if (mOrignalListener != null) {
+ mOrignalListener.onAnimationRepeat(animation);
+ }
}
}
@@ -476,6 +498,8 @@
FragmentController mController;
FragmentContainer mContainer;
Fragment mParent;
+
+ static Field sAnimationListenerField = null;
boolean mNeedMenuInvalidate;
boolean mStateSaved;
@@ -509,7 +533,8 @@
}
static boolean shouldRunOnHWLayer(View v, Animation anim) {
- return ViewCompat.getLayerType(v) == ViewCompat.LAYER_TYPE_NONE
+ return Build.VERSION.SDK_INT >= 19
+ && ViewCompat.getLayerType(v) == ViewCompat.LAYER_TYPE_NONE
&& ViewCompat.hasOverlappingRendering(v)
&& modifiesAlpha(anim);
}
@@ -914,7 +939,23 @@
return;
}
if (shouldRunOnHWLayer(v, anim)) {
- anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(v, anim));
+ AnimationListener originalListener = null;
+ try {
+ if (sAnimationListenerField == null) {
+ sAnimationListenerField = Animation.class.getDeclaredField("mListener");
+ sAnimationListenerField.setAccessible(true);
+ }
+ originalListener = (AnimationListener) sAnimationListenerField.get(anim);
+ } catch (NoSuchFieldException e) {
+ Log.e(TAG, "No field with the name mListener is found in Animation class", e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Cannot access Animation's mListener field", e);
+ }
+ // If there's already a listener set on the animation, we need wrap the new listener
+ // around the existing listener, so that they will both get animation listener
+ // callbacks.
+ anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(v, anim,
+ originalListener));
}
}
diff --git a/v4/java/android/support/v4/content/ContextCompat.java b/v4/java/android/support/v4/content/ContextCompat.java
index b8029d1..29629e7 100644
--- a/v4/java/android/support/v4/content/ContextCompat.java
+++ b/v4/java/android/support/v4/content/ContextCompat.java
@@ -403,7 +403,7 @@
*
* @see android.content.Context.getFilesDir
*/
- public final File getNoBackupFilesDir(Context context) {
+ public static File getNoBackupFilesDir(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 21) {
return ContextCompatApi21.getNoBackupFilesDir(context);
@@ -428,7 +428,7 @@
*
* @return The path of the directory holding application code cache files.
*/
- public final File getCodeCacheDir(Context context) {
+ public static File getCodeCacheDir(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 21) {
return ContextCompatApi21.getCodeCacheDir(context);
diff --git a/v4/java/android/support/v4/content/ParallelExecutorCompat.java b/v4/java/android/support/v4/content/ParallelExecutorCompat.java
new file mode 100644
index 0000000..c23470b
--- /dev/null
+++ b/v4/java/android/support/v4/content/ParallelExecutorCompat.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.content;
+
+import android.os.Build;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Helper for accessing a shared parallel Executor instance
+ * introduced after API level 4 in a backwards compatible fashion.
+ */
+public class ParallelExecutorCompat {
+ public static Executor getParallelExecutor() {
+ if (Build.VERSION.SDK_INT >= 11) {
+ // From API 11 onwards, return AsyncTask.THREAD_POOL_EXECUTOR
+ return ExecutorCompatHoneycomb.getParallelExecutor();
+ } else {
+ return ModernAsyncTask.THREAD_POOL_EXECUTOR;
+ }
+ }
+}
diff --git a/v4/java/android/support/v4/content/res/ResourcesCompat.java b/v4/java/android/support/v4/content/res/ResourcesCompat.java
index 252977b..ce5f658 100644
--- a/v4/java/android/support/v4/content/res/ResourcesCompat.java
+++ b/v4/java/android/support/v4/content/res/ResourcesCompat.java
@@ -16,11 +16,18 @@
package android.support.v4.content.res;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
import android.graphics.drawable.Drawable;
-import android.os.Build;
+import android.support.annotation.ColorInt;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import static android.os.Build.VERSION.SDK_INT;
/**
* Helper for accessing features in {@link android.content.res.Resources}
@@ -45,11 +52,11 @@
* @throws NotFoundException Throws NotFoundException if the given ID does
* not exist.
*/
+ @Nullable
@SuppressWarnings("deprecation")
- public static Drawable getDrawable(Resources res, int id, Theme theme)
- throws NotFoundException {
- final int version = Build.VERSION.SDK_INT;
- if (version >= 21) {
+ public static Drawable getDrawable(@NonNull Resources res, @DrawableRes int id,
+ @Nullable Theme theme) throws NotFoundException {
+ if (SDK_INT >= 21) {
return ResourcesCompatApi21.getDrawable(res, id, theme);
} else {
return res.getDrawable(id);
@@ -65,7 +72,7 @@
* this method simply calls through to {@link Resources#getDrawable(int)}.
* <p>
* Prior to API level 21, the theme will not be applied and this method
- * calls through to Resources.getDrawableForDensity(int, int).
+ * calls through to Resources#getDrawableForDensity(int, int).
*
* @param id The desired resource identifier, as generated by the aapt
* tool. This integer encodes the package, type, and resource
@@ -76,18 +83,76 @@
* {@code null}.
* @return Drawable An object that can be used to draw this resource.
* @throws NotFoundException Throws NotFoundException if the given ID does
- * not exist.
+ * not exist.
*/
+ @Nullable
@SuppressWarnings("deprecation")
- public static Drawable getDrawableForDensity(Resources res, int id, int density, Theme theme)
- throws NotFoundException {
- final int version = Build.VERSION.SDK_INT;
- if (version >= 21) {
+ public static Drawable getDrawableForDensity(@NonNull Resources res, @DrawableRes int id,
+ int density, @Nullable Theme theme) throws NotFoundException {
+ if (SDK_INT >= 21) {
return ResourcesCompatApi21.getDrawableForDensity(res, id, density, theme);
- } else if (version >= 15) {
+ } else if (SDK_INT >= 15) {
return ResourcesCompatIcsMr1.getDrawableForDensity(res, id, density);
} else {
return res.getDrawable(id);
}
}
+
+ /**
+ * Returns a themed color integer associated with a particular resource ID.
+ * If the resource holds a complex {@link ColorStateList}, then the default
+ * color from the set is returned.
+ * <p>
+ * Prior to API level 23, the theme will not be applied and this method
+ * calls through to {@link Resources#getColor(int)}.
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ * @param theme The theme used to style the color attributes, may be
+ * {@code null}.
+ * @return A single color value in the form {@code 0xAARRGGBB}.
+ * @throws NotFoundException Throws NotFoundException if the given ID does
+ * not exist.
+ */
+ @ColorInt
+ @SuppressWarnings("deprecation")
+ public static int getColor(@NonNull Resources res, @ColorRes int id, @Nullable Theme theme)
+ throws NotFoundException {
+ if (SDK_INT >= 23) {
+ return ResourcesCompatApi23.getColor(res, id, theme);
+ } else {
+ return res.getColor(id);
+ }
+ }
+
+ /**
+ * Returns a themed color state list associated with a particular resource
+ * ID. The resource may contain either a single raw color value or a
+ * complex {@link ColorStateList} holding multiple possible colors.
+ * <p>
+ * Prior to API level 23, the theme will not be applied and this method
+ * calls through to {@link Resources#getColorStateList(int)}.
+ *
+ * @param id The desired resource identifier of a {@link ColorStateList},
+ * as generated by the aapt tool. This integer encodes the
+ * package, type, and resource entry. The value 0 is an invalid
+ * identifier.
+ * @param theme The theme used to style the color attributes, may be
+ * {@code null}.
+ * @return A themed ColorStateList object containing either a single solid
+ * color or multiple colors that can be selected based on a state.
+ * @throws NotFoundException Throws NotFoundException if the given ID does
+ * not exist.
+ */
+ @Nullable
+ @SuppressWarnings("deprecation")
+ public static ColorStateList getColorStateList(@NonNull Resources res, @ColorRes int id,
+ @Nullable Theme theme) throws NotFoundException {
+ if (SDK_INT >= 23) {
+ return ResourcesCompatApi23.getColorStateList(res, id, theme);
+ } else {
+ return res.getColorStateList(id);
+ }
+ }
}
diff --git a/v4/java/android/support/v4/graphics/ColorUtils.java b/v4/java/android/support/v4/graphics/ColorUtils.java
index aac809b..4d9d9b2 100644
--- a/v4/java/android/support/v4/graphics/ColorUtils.java
+++ b/v4/java/android/support/v4/graphics/ColorUtils.java
@@ -17,6 +17,10 @@
package android.support.v4.graphics;
import android.graphics.Color;
+import android.support.annotation.ColorInt;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
/**
* A set of color-related utility methods, building upon those available in {@code Color}.
@@ -24,14 +28,14 @@
public class ColorUtils {
private static final int MIN_ALPHA_SEARCH_MAX_ITERATIONS = 10;
- private static final int MIN_ALPHA_SEARCH_PRECISION = 10;
+ private static final int MIN_ALPHA_SEARCH_PRECISION = 1;
private ColorUtils() {}
/**
* Composite two potentially translucent colors over each other and returns the result.
*/
- public static int compositeColors(int foreground, int background) {
+ public static int compositeColors(@ColorInt int foreground, @ColorInt int background) {
int bgAlpha = Color.alpha(background);
int fgAlpha = Color.alpha(foreground);
int a = compositeAlpha(fgAlpha, bgAlpha);
@@ -57,10 +61,13 @@
/**
* Returns the luminance of a color.
- *
- * Formula defined here: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+ * <p>
+ * Formula defined
+ * <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef">here</a>.
+ * </p>
*/
- public static double calculateLuminance(int color) {
+ @FloatRange(from = 0.0, to = 1.0)
+ public static double calculateLuminance(@ColorInt int color) {
double red = Color.red(color) / 255d;
red = red < 0.03928 ? red / 12.92 : Math.pow((red + 0.055) / 1.055, 2.4);
@@ -80,9 +87,10 @@
* Formula defined
* <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef">here</a>.
*/
- public static double calculateContrast(int foreground, int background) {
+ public static double calculateContrast(@ColorInt int foreground, @ColorInt int background) {
if (Color.alpha(background) != 255) {
- throw new IllegalArgumentException("background can not be translucent");
+ throw new IllegalArgumentException("background can not be translucent: #"
+ + Integer.toHexString(background));
}
if (Color.alpha(foreground) < 255) {
// If the foreground is translucent, composite the foreground over the background
@@ -106,10 +114,11 @@
* @param minContrastRatio the minimum contrast ratio.
* @return the alpha value in the range 0-255, or -1 if no value could be calculated.
*/
- public static int calculateMinimumAlpha(int foreground, int background,
+ public static int calculateMinimumAlpha(@ColorInt int foreground, @ColorInt int background,
float minContrastRatio) {
if (Color.alpha(background) != 255) {
- throw new IllegalArgumentException("background can not be translucent");
+ throw new IllegalArgumentException("background can not be translucent: #"
+ + Integer.toHexString(background));
}
// First lets check that a fully opaque foreground has sufficient contrast
@@ -158,7 +167,9 @@
* @param b blue component value [0..255]
* @param hsl 3 element array which holds the resulting HSL components.
*/
- public static void RGBToHSL(int r, int g, int b, float[] hsl) {
+ public static void RGBToHSL(@IntRange(from = 0x0, to = 0xFF) int r,
+ @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+ @NonNull float[] hsl) {
final float rf = r / 255f;
final float gf = g / 255f;
final float bf = b / 255f;
@@ -206,7 +217,7 @@
* @param color the ARGB color to convert. The alpha component is ignored.
* @param hsl 3 element array which holds the resulting HSL components.
*/
- public static void colorToHSL(int color, float[] hsl) {
+ public static void colorToHSL(@ColorInt int color, @NonNull float[] hsl) {
RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hsl);
}
@@ -222,7 +233,8 @@
* @param hsl 3 element array which holds the input HSL components.
* @return the resulting RGB color
*/
- public static int HSLToColor(float[] hsl) {
+ @ColorInt
+ public static int HSLToColor(@NonNull float[] hsl) {
final float h = hsl[0];
final float s = hsl[1];
final float l = hsl[2];
@@ -279,7 +291,9 @@
/**
* Set the alpha component of {@code color} to be {@code alpha}.
*/
- public static int setAlphaComponent(int color, int alpha) {
+ @ColorInt
+ public static int setAlphaComponent(@ColorInt int color,
+ @IntRange(from = 0x0, to = 0xFF) int alpha) {
if (alpha < 0 || alpha > 255) {
throw new IllegalArgumentException("alpha must be between 0 and 255.");
}
diff --git a/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java b/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
index 88b5f4a..64ae075 100644
--- a/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
+++ b/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
@@ -123,7 +123,7 @@
@Override
public int getLayoutDirection(Drawable drawable) {
final int dir = DrawableCompatJellybeanMr1.getLayoutDirection(drawable);
- return dir < 0 ? dir : ViewCompat.LAYOUT_DIRECTION_LTR;
+ return dir >= 0 ? dir : ViewCompat.LAYOUT_DIRECTION_LTR;
}
}
diff --git a/v4/java/android/support/v4/media/MediaBrowserCompat.java b/v4/java/android/support/v4/media/MediaBrowserCompat.java
new file mode 100644
index 0000000..dcce7f5
--- /dev/null
+++ b/v4/java/android/support/v4/media/MediaBrowserCompat.java
@@ -0,0 +1,1243 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.BundleCompat;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.os.ResultReceiver;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.support.v4.media.MediaBrowserProtocol.*;
+
+/**
+ * Browses media content offered by a {@link MediaBrowserServiceCompat}.
+ * <p>
+ * This object is not thread-safe. All calls should happen on the thread on which the browser
+ * was constructed.
+ * </p>
+ */
+public final class MediaBrowserCompat {
+ private static final String TAG = "MediaBrowserCompat";
+
+ private final MediaBrowserImpl mImpl;
+
+ /**
+ * Creates a media browser for the specified media browse service.
+ *
+ * @param context The context.
+ * @param serviceComponent The component name of the media browse service.
+ * @param callback The connection callback.
+ * @param rootHints An optional bundle of service-specific arguments to send
+ * to the media browse service when connecting and retrieving the root id
+ * for browsing, or null if none. The contents of this bundle may affect
+ * the information returned when browsing.
+ */
+ public MediaBrowserCompat(Context context, ComponentName serviceComponent,
+ ConnectionCallback callback, Bundle rootHints) {
+ if (android.os.Build.VERSION.SDK_INT >= 23) {
+ mImpl = new MediaBrowserImplApi23(context, serviceComponent, callback, rootHints);
+ } else if (android.os.Build.VERSION.SDK_INT >= 21) {
+ mImpl = new MediaBrowserImplApi21(context, serviceComponent, callback, rootHints);
+ } else {
+ mImpl = new MediaBrowserImplBase(context, serviceComponent, callback, rootHints);
+ }
+ }
+
+ /**
+ * Connects to the media browse service.
+ * <p>
+ * The connection callback specified in the constructor will be invoked
+ * when the connection completes or fails.
+ * </p>
+ */
+ public void connect() {
+ mImpl.connect();
+ }
+
+ /**
+ * Disconnects from the media browse service.
+ * After this, no more callbacks will be received.
+ */
+ public void disconnect() {
+ mImpl.disconnect();
+ }
+
+ /**
+ * Returns whether the browser is connected to the service.
+ */
+ public boolean isConnected() {
+ return mImpl.isConnected();
+ }
+
+ /**
+ * Gets the service component that the media browser is connected to.
+ */
+ public @NonNull
+ ComponentName getServiceComponent() {
+ return mImpl.getServiceComponent();
+ }
+
+ /**
+ * Gets the root id.
+ * <p>
+ * Note that the root id may become invalid or change when when the
+ * browser is disconnected.
+ * </p>
+ *
+ * @throws IllegalStateException if not connected.
+ */
+ public @NonNull String getRoot() {
+ return mImpl.getRoot();
+ }
+
+ /**
+ * Gets any extras for the media service.
+ *
+ * @throws IllegalStateException if not connected.
+ */
+ public @Nullable
+ Bundle getExtras() {
+ return mImpl.getExtras();
+ }
+
+ /**
+ * Gets the media session token associated with the media browser.
+ * <p>
+ * Note that the session token may become invalid or change when when the
+ * browser is disconnected.
+ * </p>
+ *
+ * @return The session token for the browser, never null.
+ *
+ * @throws IllegalStateException if not connected.
+ */
+ public @NonNull MediaSessionCompat.Token getSessionToken() {
+ return mImpl.getSessionToken();
+ }
+
+ /**
+ * Queries for information about the media items that are contained within
+ * the specified id and subscribes to receive updates when they change.
+ * <p>
+ * The list of subscriptions is maintained even when not connected and is
+ * restored after reconnection. It is ok to subscribe while not connected
+ * but the results will not be returned until the connection completes.
+ * </p>
+ * <p>
+ * If the id is already subscribed with a different callback then the new
+ * callback will replace the previous one and the child data will be
+ * reloaded.
+ * </p>
+ *
+ * @param parentId The id of the parent media item whose list of children
+ * will be subscribed.
+ * @param callback The callback to receive the list of children.
+ */
+ public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+ mImpl.subscribe(parentId, callback);
+ }
+
+ /**
+ * Unsubscribes for changes to the children of the specified media id.
+ * <p>
+ * The query callback will no longer be invoked for results associated with
+ * this id once this method returns.
+ * </p>
+ *
+ * @param parentId The id of the parent media item whose list of children
+ * will be unsubscribed.
+ */
+ public void unsubscribe(@NonNull String parentId) {
+ mImpl.unsubscribe(parentId);
+ }
+
+ /**
+ * Retrieves a specific {@link MediaItem} from the connected service. Not
+ * all services may support this, so falling back to subscribing to the
+ * parent's id should be used when unavailable.
+ *
+ * @param mediaId The id of the item to retrieve.
+ * @param cb The callback to receive the result on.
+ */
+ public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
+ mImpl.getItem(mediaId, cb);
+ }
+
+ public static class MediaItem implements Parcelable {
+ private final int mFlags;
+ private final MediaDescriptionCompat mDescription;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
+ public @interface Flags { }
+
+ /**
+ * Flag: Indicates that the item has children of its own.
+ */
+ public static final int FLAG_BROWSABLE = 1 << 0;
+
+ /**
+ * Flag: Indicates that the item is playable.
+ * <p>
+ * The id of this item may be passed to
+ * {@link MediaControllerCompat.TransportControls#playFromMediaId(String, Bundle)}
+ * to start playing it.
+ * </p>
+ */
+ public static final int FLAG_PLAYABLE = 1 << 1;
+
+ /**
+ * Create a new MediaItem for use in browsing media.
+ * @param description The description of the media, which must include a
+ * media id.
+ * @param flags The flags for this item.
+ */
+ public MediaItem(@NonNull MediaDescriptionCompat description, @Flags int flags) {
+ if (description == null) {
+ throw new IllegalArgumentException("description cannot be null");
+ }
+ if (TextUtils.isEmpty(description.getMediaId())) {
+ throw new IllegalArgumentException("description must have a non-empty media id");
+ }
+ mFlags = flags;
+ mDescription = description;
+ }
+
+ /**
+ * Private constructor.
+ */
+ private MediaItem(Parcel in) {
+ mFlags = in.readInt();
+ mDescription = MediaDescriptionCompat.CREATOR.createFromParcel(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mFlags);
+ mDescription.writeToParcel(out, flags);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("MediaItem{");
+ sb.append("mFlags=").append(mFlags);
+ sb.append(", mDescription=").append(mDescription);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public static final Parcelable.Creator<MediaItem> CREATOR =
+ new Parcelable.Creator<MediaItem>() {
+ @Override
+ public MediaItem createFromParcel(Parcel in) {
+ return new MediaItem(in);
+ }
+
+ @Override
+ public MediaItem[] newArray(int size) {
+ return new MediaItem[size];
+ }
+ };
+
+ /**
+ * Gets the flags of the item.
+ */
+ public @Flags int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Returns whether this item is browsable.
+ * @see #FLAG_BROWSABLE
+ */
+ public boolean isBrowsable() {
+ return (mFlags & FLAG_BROWSABLE) != 0;
+ }
+
+ /**
+ * Returns whether this item is playable.
+ * @see #FLAG_PLAYABLE
+ */
+ public boolean isPlayable() {
+ return (mFlags & FLAG_PLAYABLE) != 0;
+ }
+
+ /**
+ * Returns the description of the media.
+ */
+ public @NonNull MediaDescriptionCompat getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * Returns the media id for this item.
+ */
+ public @NonNull String getMediaId() {
+ return mDescription.getMediaId();
+ }
+ }
+
+
+ /**
+ * Callbacks for connection related events.
+ */
+ public static class ConnectionCallback {
+ final Object mConnectionCallbackObj;
+
+ public ConnectionCallback() {
+ if (android.os.Build.VERSION.SDK_INT >= 21) {
+ mConnectionCallbackObj =
+ MediaBrowserCompatApi21.createConnectionCallback(new StubApi21());
+ } else {
+ mConnectionCallbackObj = null;
+ }
+ }
+
+ /**
+ * Invoked after {@link MediaBrowserCompat#connect()} when the request has successfully
+ * completed.
+ */
+ public void onConnected() {
+ }
+
+ /**
+ * Invoked when the client is disconnected from the media browser.
+ */
+ public void onConnectionSuspended() {
+ }
+
+ /**
+ * Invoked when the connection to the media browser failed.
+ */
+ public void onConnectionFailed() {
+ }
+
+
+ private class StubApi21 implements MediaBrowserCompatApi21.ConnectionCallback {
+ @Override
+ public void onConnected() {
+ ConnectionCallback.this.onConnected();
+ }
+
+ @Override
+ public void onConnectionSuspended() {
+ ConnectionCallback.this.onConnectionSuspended();
+ }
+
+ @Override
+ public void onConnectionFailed() {
+ ConnectionCallback.this.onConnectionFailed();
+ }
+ }
+ }
+
+ /**
+ * Callbacks for subscription related events.
+ */
+ public static abstract class SubscriptionCallback {
+ final Object mSubscriptionCallbackObj;
+
+ public SubscriptionCallback() {
+ if (android.os.Build.VERSION.SDK_INT >= 21) {
+ mSubscriptionCallbackObj =
+ MediaBrowserCompatApi21.createSubscriptionCallback(new StubApi21());
+ } else {
+ mSubscriptionCallbackObj = null;
+ }
+ }
+
+ /**
+ * Called when the list of children is loaded or updated.
+ *
+ * @param parentId The media id of the parent media item.
+ * @param children The children which were loaded, or null if the id is invalid.
+ */
+ public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children) {
+ }
+
+ /**
+ * Called when the id doesn't exist or other errors in subscribing.
+ * <p>
+ * If this is called, the subscription remains until {@link MediaBrowserCompat#unsubscribe}
+ * called, because some errors may heal themselves.
+ * </p>
+ *
+ * @param parentId The media id of the parent media item whose children could
+ * not be loaded.
+ */
+ public void onError(@NonNull String parentId) {
+ }
+
+ private class StubApi21 implements MediaBrowserCompatApi21.SubscriptionCallback {
+ @Override
+ public void onChildrenLoaded(@NonNull String parentId, @NonNull List<Parcel> children) {
+ List<MediaBrowserCompat.MediaItem> mediaItems = null;
+ if (children != null) {
+ mediaItems = new ArrayList<>();
+ for (Parcel parcel : children) {
+ parcel.setDataPosition(0);
+ mediaItems.add(
+ MediaBrowserCompat.MediaItem.CREATOR.createFromParcel(parcel));
+ parcel.recycle();
+ }
+ }
+ SubscriptionCallback.this.onChildrenLoaded(parentId, mediaItems);
+ }
+
+ @Override
+ public void onError(@NonNull String parentId) {
+ SubscriptionCallback.this.onError(parentId);
+ }
+ }
+ }
+
+ /**
+ * Callback for receiving the result of {@link #getItem}.
+ */
+ public static abstract class ItemCallback {
+ final Object mItemCallbackObj;
+
+ public ItemCallback() {
+ if (android.os.Build.VERSION.SDK_INT >= 23) {
+ mItemCallbackObj = MediaBrowserCompatApi23.createItemCallback(new StubApi23());
+ } else {
+ mItemCallbackObj = null;
+ }
+ }
+
+ /**
+ * Called when the item has been returned by the browser service.
+ *
+ * @param item The item that was returned or null if it doesn't exist.
+ */
+ public void onItemLoaded(MediaItem item) {
+ }
+
+ /**
+ * Called when the item doesn't exist or there was an error retrieving it.
+ *
+ * @param itemId The media id of the media item which could not be loaded.
+ */
+ public void onError(@NonNull String itemId) {
+ }
+
+ private class StubApi23 implements MediaBrowserCompatApi23.ItemCallback {
+ @Override
+ public void onItemLoaded(Parcel itemParcel) {
+ itemParcel.setDataPosition(0);
+ MediaItem item = MediaBrowserCompat.MediaItem.CREATOR.createFromParcel(itemParcel);
+ itemParcel.recycle();
+ ItemCallback.this.onItemLoaded(item);
+ }
+
+ @Override
+ public void onError(@NonNull String itemId) {
+ ItemCallback.this.onError(itemId);
+ }
+ }
+ }
+
+ interface MediaBrowserImpl {
+ void connect();
+ void disconnect();
+ boolean isConnected();
+ ComponentName getServiceComponent();
+ @NonNull String getRoot();
+ @Nullable Bundle getExtras();
+ @NonNull MediaSessionCompat.Token getSessionToken();
+ void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback);
+ void unsubscribe(@NonNull String parentId);
+ void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb);
+ }
+
+ static class MediaBrowserImplBase implements MediaBrowserImpl {
+ private static final boolean DBG = false;
+
+ private static final int CONNECT_STATE_DISCONNECTED = 0;
+ private static final int CONNECT_STATE_CONNECTING = 1;
+ private static final int CONNECT_STATE_CONNECTED = 2;
+ private static final int CONNECT_STATE_SUSPENDED = 3;
+
+ private final Context mContext;
+ private final ComponentName mServiceComponent;
+ private final ConnectionCallback mCallback;
+ private final Bundle mRootHints;
+ private final CallbackHandler mHandler = new CallbackHandler();
+ private final ArrayMap<String,Subscription> mSubscriptions = new ArrayMap<>();
+
+ private int mState = CONNECT_STATE_DISCONNECTED;
+ private MediaServiceConnection mServiceConnection;
+ private ServiceBinderWrapper mServiceBinderWrapper;
+ private Messenger mCallbacksMessenger;
+ private String mRootId;
+ private MediaSessionCompat.Token mMediaSessionToken;
+ private Bundle mExtras;
+
+ public MediaBrowserImplBase(Context context, ComponentName serviceComponent,
+ ConnectionCallback callback, Bundle rootHints) {
+ if (context == null) {
+ throw new IllegalArgumentException("context must not be null");
+ }
+ if (serviceComponent == null) {
+ throw new IllegalArgumentException("service component must not be null");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("connection callback must not be null");
+ }
+ mContext = context;
+ mServiceComponent = serviceComponent;
+ mCallback = callback;
+ mRootHints = rootHints;
+ }
+
+ public void connect() {
+ if (mState != CONNECT_STATE_DISCONNECTED) {
+ throw new IllegalStateException("connect() called while not disconnected (state="
+ + getStateLabel(mState) + ")");
+ }
+ // TODO: remove this extra check.
+ if (DBG) {
+ if (mServiceConnection != null) {
+ throw new RuntimeException("mServiceConnection should be null. Instead it is "
+ + mServiceConnection);
+ }
+ }
+ if (mServiceBinderWrapper != null) {
+ throw new RuntimeException("mServiceBinderWrapper should be null. Instead it is "
+ + mServiceBinderWrapper);
+ }
+ if (mCallbacksMessenger != null) {
+ throw new RuntimeException("mCallbacksMessenger should be null. Instead it is "
+ + mCallbacksMessenger);
+ }
+
+ mState = CONNECT_STATE_CONNECTING;
+
+ final Intent intent = new Intent(MediaBrowserServiceCompat.SERVICE_INTERFACE);
+ intent.setComponent(mServiceComponent);
+
+ final ServiceConnection thisConnection = mServiceConnection =
+ new MediaServiceConnection();
+
+ boolean bound = false;
+ try {
+ bound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed binding to service " + mServiceComponent);
+ }
+
+ if (!bound) {
+ // Tell them that it didn't work. We are already on the main thread,
+ // but we don't want to do callbacks inside of connect(). So post it,
+ // and then check that we are on the same ServiceConnection. We know
+ // we won't also get an onServiceConnected or onServiceDisconnected,
+ // so we won't be doing double callbacks.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // Ensure that nobody else came in or tried to connect again.
+ if (thisConnection == mServiceConnection) {
+ forceCloseConnection();
+ mCallback.onConnectionFailed();
+ }
+ }
+ });
+ }
+
+ if (DBG) {
+ Log.d(TAG, "connect...");
+ dump();
+ }
+ }
+
+ public void disconnect() {
+ // It's ok to call this any state, because allowing this lets apps not have
+ // to check isConnected() unnecessarily. They won't appreciate the extra
+ // assertions for this. We do everything we can here to go back to a sane state.
+ if (mCallbacksMessenger != null) {
+ try {
+ mServiceBinderWrapper.disconnect();
+ } catch (RemoteException ex) {
+ // We are disconnecting anyway. Log, just for posterity but it's not
+ // a big problem.
+ Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
+ }
+ }
+ forceCloseConnection();
+
+ if (DBG) {
+ Log.d(TAG, "disconnect...");
+ dump();
+ }
+ }
+
+ /**
+ * Null out the variables and unbind from the service. This doesn't include
+ * calling disconnect on the service, because we only try to do that in the
+ * clean shutdown cases.
+ * <p>
+ * Everywhere that calls this EXCEPT for disconnect() should follow it with
+ * a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
+ * for a clean shutdown, but everywhere else is a dirty shutdown and should
+ * notify the app.
+ */
+ private void forceCloseConnection() {
+ if (mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ }
+ mState = CONNECT_STATE_DISCONNECTED;
+ mServiceConnection = null;
+ mServiceBinderWrapper = null;
+ mCallbacksMessenger = null;
+ mRootId = null;
+ mMediaSessionToken = null;
+ }
+
+ public boolean isConnected() {
+ return mState == CONNECT_STATE_CONNECTED;
+ }
+
+ public @NonNull
+ ComponentName getServiceComponent() {
+ if (!isConnected()) {
+ throw new IllegalStateException("getServiceComponent() called while not connected" +
+ " (state=" + mState + ")");
+ }
+ return mServiceComponent;
+ }
+
+ public @NonNull String getRoot() {
+ if (!isConnected()) {
+ throw new IllegalStateException("getRoot() called while not connected"
+ + "(state=" + getStateLabel(mState) + ")");
+ }
+ return mRootId;
+ }
+
+ public @Nullable
+ Bundle getExtras() {
+ if (!isConnected()) {
+ throw new IllegalStateException("getExtras() called while not connected (state="
+ + getStateLabel(mState) + ")");
+ }
+ return mExtras;
+ }
+
+ public @NonNull MediaSessionCompat.Token getSessionToken() {
+ if (!isConnected()) {
+ throw new IllegalStateException("getSessionToken() called while not connected"
+ + "(state=" + mState + ")");
+ }
+ return mMediaSessionToken;
+ }
+
+ public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+ // Check arguments.
+ if (parentId == null) {
+ throw new IllegalArgumentException("parentId is null");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("callback is null");
+ }
+
+ // Update or create the subscription.
+ Subscription sub = mSubscriptions.get(parentId);
+ boolean newSubscription = sub == null;
+ if (newSubscription) {
+ sub = new Subscription(parentId);
+ mSubscriptions.put(parentId, sub);
+ }
+ sub.callback = callback;
+
+ // If we are connected, tell the service that we are watching. If we aren't
+ // connected, the service will be told when we connect.
+ if (mState == CONNECT_STATE_CONNECTED) {
+ try {
+ mServiceBinderWrapper.addSubscription(parentId);
+ } catch (RemoteException ex) {
+ // Process is crashing. We will disconnect, and upon reconnect we will
+ // automatically reregister. So nothing to do here.
+ Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
+ }
+ }
+ }
+
+ public void unsubscribe(@NonNull String parentId) {
+ // Check arguments.
+ if (TextUtils.isEmpty(parentId)) {
+ throw new IllegalArgumentException("parentId is empty.");
+ }
+
+ // Remove from our list.
+ final Subscription sub = mSubscriptions.remove(parentId);
+
+ // Tell the service if necessary.
+ if (mState == CONNECT_STATE_CONNECTED && sub != null) {
+ try {
+ mServiceBinderWrapper.removeSubscription(parentId);
+ } catch (RemoteException ex) {
+ // Process is crashing. We will disconnect, and upon reconnect we will
+ // automatically reregister. So nothing to do here.
+ Log.d(TAG, "removeSubscription failed with RemoteException parentId="
+ + parentId);
+ }
+ }
+ }
+
+ public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
+ if (TextUtils.isEmpty(mediaId)) {
+ throw new IllegalArgumentException("mediaId is empty.");
+ }
+ if (cb == null) {
+ throw new IllegalArgumentException("cb is null.");
+ }
+ if (mState != CONNECT_STATE_CONNECTED) {
+ Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ cb.onError(mediaId);
+ }
+ });
+ return;
+ }
+ ResultReceiver receiver = new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode != 0 || resultData == null
+ || !resultData.containsKey(MediaBrowserServiceCompat.KEY_MEDIA_ITEM)) {
+ cb.onError(mediaId);
+ return;
+ }
+ Parcelable item =
+ resultData.getParcelable(MediaBrowserServiceCompat.KEY_MEDIA_ITEM);
+ if (!(item instanceof MediaItem)) {
+ cb.onError(mediaId);
+ return;
+ }
+ cb.onItemLoaded((MediaItem)item);
+ }
+ };
+ try {
+ mServiceBinderWrapper.getMediaItem(mediaId, receiver);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Remote error getting media item.");
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ cb.onError(mediaId);
+ }
+ });
+ }
+ }
+
+ /**
+ * For debugging.
+ */
+ private static String getStateLabel(int state) {
+ switch (state) {
+ case CONNECT_STATE_DISCONNECTED:
+ return "CONNECT_STATE_DISCONNECTED";
+ case CONNECT_STATE_CONNECTING:
+ return "CONNECT_STATE_CONNECTING";
+ case CONNECT_STATE_CONNECTED:
+ return "CONNECT_STATE_CONNECTED";
+ case CONNECT_STATE_SUSPENDED:
+ return "CONNECT_STATE_SUSPENDED";
+ default:
+ return "UNKNOWN/" + state;
+ }
+ }
+
+ private final void onServiceConnected(final Messenger callback, final String root,
+ final MediaSessionCompat.Token session, final Bundle extra) {
+ // Check to make sure there hasn't been a disconnect or a different ServiceConnection.
+ if (!isCurrent(callback, "onConnect")) {
+ return;
+ }
+ // Don't allow them to call us twice.
+ if (mState != CONNECT_STATE_CONNECTING) {
+ Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState)
+ + "... ignoring");
+ return;
+ }
+ mRootId = root;
+ mMediaSessionToken = session;
+ mExtras = extra;
+ mState = CONNECT_STATE_CONNECTED;
+
+ if (DBG) {
+ Log.d(TAG, "ServiceCallbacks.onConnect...");
+ dump();
+ }
+ mCallback.onConnected();
+
+ // we may receive some subscriptions before we are connected, so re-subscribe
+ // everything now
+ for (String id : mSubscriptions.keySet()) {
+ try {
+ mServiceBinderWrapper.addSubscription(id);
+ } catch (RemoteException ex) {
+ // Process is crashing. We will disconnect, and upon reconnect we will
+ // automatically reregister. So nothing to do here.
+ Log.d(TAG, "addSubscription failed with RemoteException parentId=" + id);
+ }
+ }
+ }
+
+ private final void onConnectionFailed(final Messenger callback) {
+ Log.e(TAG, "onConnectFailed for " + mServiceComponent);
+
+ // Check to make sure there hasn't been a disconnect or a different ServiceConnection.
+ if (!isCurrent(callback, "onConnectFailed")) {
+ return;
+ }
+ // Don't allow them to call us twice.
+ if (mState != CONNECT_STATE_CONNECTING) {
+ Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState)
+ + "... ignoring");
+ return;
+ }
+
+ // Clean up
+ forceCloseConnection();
+
+ // Tell the app.
+ mCallback.onConnectionFailed();
+ }
+
+ private final void onLoadChildren(final Messenger callback, final String parentId,
+ final List list) {
+ // Check that there hasn't been a disconnect or a different ServiceConnection.
+ if (!isCurrent(callback, "onLoadChildren")) {
+ return;
+ }
+
+ List<MediaItem> data = list;
+ if (DBG) {
+ Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
+ }
+
+ // Check that the subscription is still subscribed.
+ final Subscription subscription = mSubscriptions.get(parentId);
+ if (subscription == null) {
+ if (DBG) {
+ Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
+ }
+ return;
+ }
+
+ // Tell the app.
+ subscription.callback.onChildrenLoaded(parentId, data);
+ }
+
+ /**
+ * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
+ */
+ private boolean isCurrent(Messenger callback, String funcName) {
+ if (mCallbacksMessenger != callback) {
+ if (mState != CONNECT_STATE_DISCONNECTED) {
+ Log.i(TAG, funcName + " for " + mServiceComponent + " with mCallbacksMessenger="
+ + mCallbacksMessenger + " this=" + this);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Log internal state.
+ * @hide
+ */
+ void dump() {
+ Log.d(TAG, "MediaBrowserCompat...");
+ Log.d(TAG, " mServiceComponent=" + mServiceComponent);
+ Log.d(TAG, " mCallback=" + mCallback);
+ Log.d(TAG, " mRootHints=" + mRootHints);
+ Log.d(TAG, " mState=" + getStateLabel(mState));
+ Log.d(TAG, " mServiceConnection=" + mServiceConnection);
+ Log.d(TAG, " mServiceBinderWrapper=" + mServiceBinderWrapper);
+ Log.d(TAG, " mCallbacksMessenger=" + mCallbacksMessenger);
+ Log.d(TAG, " mRootId=" + mRootId);
+ Log.d(TAG, " mMediaSessionToken=" + mMediaSessionToken);
+ }
+
+ private class ServiceBinderWrapper {
+ private Messenger mMessenger;
+
+ public ServiceBinderWrapper(IBinder target) {
+ mMessenger = new Messenger(target);
+ }
+
+ void connect() throws RemoteException {
+ sendRequest(CLIENT_MSG_CONNECT, mContext.getPackageName(), mRootHints,
+ mCallbacksMessenger);
+ }
+
+ void disconnect() throws RemoteException {
+ sendRequest(CLIENT_MSG_DISCONNECT, null, null, mCallbacksMessenger);
+ }
+
+ void addSubscription(String parentId) throws RemoteException {
+ sendRequest(CLIENT_MSG_ADD_SUBSCRIPTION, parentId, null, mCallbacksMessenger);
+ }
+
+ void removeSubscription(String parentId) throws RemoteException {
+ sendRequest(CLIENT_MSG_REMOVE_SUBSCRIPTION, parentId, null, mCallbacksMessenger);
+ }
+
+ void getMediaItem(String mediaId, ResultReceiver receiver) throws RemoteException {
+ Bundle data = new Bundle();
+ data.putParcelable(SERVICE_DATA_RESULT_RECEIVER, receiver);
+ sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, mediaId, data, null);
+ }
+
+ private void sendRequest(int what, Object obj, Bundle data, Messenger cbMessenger)
+ throws RemoteException {
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg1 = CLIENT_VERSION_CURRENT;
+ msg.obj = obj;
+ msg.setData(data);
+ msg.replyTo = cbMessenger;
+ mMessenger.send(msg);
+ }
+ }
+
+ /**
+ * ServiceConnection to the other app.
+ */
+ private class MediaServiceConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(final ComponentName name, final IBinder binder) {
+ postOrRun(new Runnable() {
+ @Override
+ public void run() {
+ if (DBG) {
+ Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
+ + " binder=" + binder);
+ dump();
+ }
+
+ // Make sure we are still the current connection, and that they haven't
+ // called disconnect().
+ if (!isCurrent("onServiceConnected")) {
+ return;
+ }
+
+ // Save their binder
+ mServiceBinderWrapper = new ServiceBinderWrapper(binder);
+
+ // We make a new mServiceCallbacks each time we connect so that we can drop
+ // responses from previous connections.
+ mCallbacksMessenger = new Messenger(mHandler);
+
+ mState = CONNECT_STATE_CONNECTING;
+
+ // Call connect, which is async. When we get a response from that we will
+ // say that we're connected.
+ try {
+ if (DBG) {
+ Log.d(TAG, "ServiceCallbacks.onConnect...");
+ dump();
+ }
+ mServiceBinderWrapper.connect();
+ } catch (RemoteException ex) {
+ // Connect failed, which isn't good. But the auto-reconnect on the
+ // service will take over and we will come back. We will also get the
+ // onServiceDisconnected, which has all the cleanup code. So let that
+ // do it.
+ Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
+ if (DBG) {
+ Log.d(TAG, "ServiceCallbacks.onConnect...");
+ dump();
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onServiceDisconnected(final ComponentName name) {
+ postOrRun(new Runnable() {
+ @Override
+ public void run() {
+ if (DBG) {
+ Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
+ + " this=" + this + " mServiceConnection=" +
+ mServiceConnection);
+ dump();
+ }
+
+ // Make sure we are still the current connection, and that they haven't
+ // called disconnect().
+ if (!isCurrent("onServiceDisconnected")) {
+ return;
+ }
+
+ // Clear out what we set in onServiceConnected
+ mServiceBinderWrapper = null;
+ mCallbacksMessenger = null;
+
+ // And tell the app that it's suspended.
+ mState = CONNECT_STATE_SUSPENDED;
+ mCallback.onConnectionSuspended();
+ }
+ });
+ }
+
+ private void postOrRun(Runnable r) {
+ if (Thread.currentThread() == mHandler.getLooper().getThread()) {
+ r.run();
+ } else {
+ mHandler.post(r);
+ }
+ }
+
+ /**
+ * Return true if this is the current ServiceConnection. Also logs if it's not.
+ */
+ private boolean isCurrent(String funcName) {
+ if (mServiceConnection != this) {
+ if (mState != CONNECT_STATE_DISCONNECTED) {
+ // Check mState, because otherwise this log is noisy.
+ Log.i(TAG, funcName + " for " + mServiceComponent +
+ " with mServiceConnection=" + mServiceConnection + " this=" + this);
+ }
+ return false;
+ }
+ return true;
+ }
+ }
+
+ private class CallbackHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ Bundle data = msg.getData();
+ switch (msg.what) {
+ case SERVICE_MSG_ON_CONNECT:
+ onServiceConnected(mCallbacksMessenger, (String) msg.obj,
+ (MediaSessionCompat.Token) data.getParcelable(
+ SERVICE_DATA_MEDIA_SESSION_TOKEN),
+ data.getBundle(SERVICE_DATA_EXTRAS));
+ break;
+ case SERVICE_MSG_ON_CONNECT_FAILED:
+ onConnectionFailed(mCallbacksMessenger);
+ break;
+ case SERVICE_MSG_ON_LOAD_CHILDREN:
+ onLoadChildren(mCallbacksMessenger, (String) msg.obj,
+ data.getParcelableArrayList(SERVICE_DATA_MEDIA_ITEM_LIST));
+ break;
+ default:
+ Log.w(TAG, "Unhandled message: " + msg
+ + "\n Client version: " + CLIENT_VERSION_CURRENT
+ + "\n Service version: " + msg.arg1);
+ }
+ }
+ }
+
+ private static class Subscription {
+ final String id;
+ SubscriptionCallback callback;
+
+ Subscription(String id) {
+ this.id = id;
+ }
+ }
+ }
+
+ static class MediaBrowserImplApi21 implements MediaBrowserImpl {
+ protected Object mBrowserObj;
+ protected Messenger mMessenger;
+ protected Handler mHandler = new Handler();
+
+ public MediaBrowserImplApi21(Context context, ComponentName serviceComponent,
+ ConnectionCallback callback, Bundle rootHints) {
+ mBrowserObj = MediaBrowserCompatApi21.createBrowser(context, serviceComponent,
+ callback.mConnectionCallbackObj, rootHints);
+ }
+
+ @Override
+ public void connect() {
+ MediaBrowserCompatApi21.connect(mBrowserObj);
+ }
+
+ @Override
+ public void disconnect() {
+ MediaBrowserCompatApi21.disconnect(mBrowserObj);
+ }
+
+ @Override
+ public boolean isConnected() {
+ return MediaBrowserCompatApi21.isConnected(mBrowserObj);
+ }
+
+ @Override
+ public ComponentName getServiceComponent() {
+ return MediaBrowserCompatApi21.getServiceComponent(mBrowserObj);
+ }
+
+ @NonNull
+ @Override
+ public String getRoot() {
+ return MediaBrowserCompatApi21.getRoot(mBrowserObj);
+ }
+
+ @Nullable
+ @Override
+ public Bundle getExtras() {
+ return MediaBrowserCompatApi21.getExtras(mBrowserObj);
+ }
+
+ @NonNull
+ @Override
+ public MediaSessionCompat.Token getSessionToken() {
+ return MediaSessionCompat.Token.fromToken(
+ MediaBrowserCompatApi21.getSessionToken(mBrowserObj));
+ }
+
+ @Override
+ public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+ MediaBrowserCompatApi21.subscribe(
+ mBrowserObj, parentId, callback.mSubscriptionCallbackObj);
+ }
+
+ @Override
+ public void unsubscribe(@NonNull String parentId) {
+ MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
+ }
+
+ @Override
+ public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
+ if (TextUtils.isEmpty(mediaId)) {
+ throw new IllegalArgumentException("mediaId is empty.");
+ }
+ if (cb == null) {
+ throw new IllegalArgumentException("cb is null.");
+ }
+ if (!MediaBrowserCompatApi21.isConnected(mBrowserObj)) {
+ Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ cb.onError(mediaId);
+ }
+ });
+ return;
+ }
+ if (mMessenger == null) {
+ Bundle extras = MediaBrowserCompatApi21.getExtras(mBrowserObj);
+ IBinder serviceBinder = BundleCompat.getBinder(extras, EXTRA_MESSENGER_BINDER);
+ if (serviceBinder != null) {
+ mMessenger = new Messenger(serviceBinder);
+ }
+ }
+ if (mMessenger == null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ // Default framework implementation.
+ cb.onItemLoaded(null);
+ }
+ });
+ return;
+ }
+ ResultReceiver receiver = new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode != 0 || resultData == null
+ || !resultData.containsKey(MediaBrowserServiceCompat.KEY_MEDIA_ITEM)) {
+ cb.onError(mediaId);
+ return;
+ }
+ Parcelable item =
+ resultData.getParcelable(MediaBrowserServiceCompat.KEY_MEDIA_ITEM);
+ if (!(item instanceof MediaItem)) {
+ cb.onError(mediaId);
+ return;
+ }
+ cb.onItemLoaded((MediaItem)item);
+ }
+ };
+ try {
+ Bundle data = new Bundle();
+ data.putParcelable(SERVICE_DATA_RESULT_RECEIVER, receiver);
+ sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, mediaId, data, null);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Remote error getting media item.");
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ cb.onError(mediaId);
+ }
+ });
+ }
+ }
+
+ private void sendRequest(int what, Object obj, Bundle data, Messenger cbMessenger)
+ throws RemoteException {
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg1 = CLIENT_VERSION_CURRENT;
+ msg.obj = obj;
+ msg.setData(data);
+ msg.replyTo = cbMessenger;
+ mMessenger.send(msg);
+ }
+ }
+
+ static class MediaBrowserImplApi23 extends MediaBrowserImplApi21 {
+ public MediaBrowserImplApi23(Context context, ComponentName serviceComponent,
+ ConnectionCallback callback, Bundle rootHints) {
+ super(context, serviceComponent, callback, rootHints);
+ }
+
+ @Override
+ public void getItem(@NonNull String mediaId, @NonNull ItemCallback cb) {
+ MediaBrowserCompatApi23.getItem(mBrowserObj, mediaId, cb.mItemCallbackObj);
+ }
+ }
+}
diff --git a/v4/java/android/support/v4/media/MediaBrowserProtocol.java b/v4/java/android/support/v4/media/MediaBrowserProtocol.java
new file mode 100644
index 0000000..7c8feb3
--- /dev/null
+++ b/v4/java/android/support/v4/media/MediaBrowserProtocol.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+package android.support.v4.media;
+
+/***
+ * Defines the communication protocol for media browsers and media browser services.
+ * @hide
+ */
+class MediaBrowserProtocol {
+
+ /**
+ * MediaBrowserCompat will check the version of the connected MediaBrowserServiceCompat,
+ * and it will not send messages if they are introduced in the higher version of the
+ * MediaBrowserServiceCompat.
+ */
+ public static final int SERVICE_VERSION_1 = 1;
+ public static final int SERVICE_VERSION_CURRENT = SERVICE_VERSION_1;
+
+ /*
+ * Messages sent from the media browser service compat to the media browser compat.
+ * (Compat implementation for IMediaBrowserServiceCallbacks)
+ * DO NOT RENUMBER THESE!
+ */
+
+ /** (service v1)
+ * Sent after {@link MediaBrowserCompat#connect()} when the request has successfully
+ * completed.
+ * - arg1 : The service version
+ * - obj : The root media item id
+ * - data
+ * SERVICE_DATA_MEDIA_SESSION_TOKEN : Media session token
+ * SERVICE_DATA_EXTRAS : An extras bundle which contains EXTRA_SERVICE_VERSION
+ */
+ public static final int SERVICE_MSG_ON_CONNECT = 1;
+
+ /** (service v1)
+ * Sent after {@link MediaBrowserCompat#connect()} when the connection to the media browser
+ * failed.
+ * - arg1 : service version
+ */
+ public static final int SERVICE_MSG_ON_CONNECT_FAILED = 2;
+
+ /** (service v1)
+ * Sent when the list of children is loaded or updated.
+ * - arg1 : The service version
+ * - obj : The parent media item id
+ * - data
+ * SERVICE_DATA_MEDIA_ITEM_LIST : An array list for the media item children
+ */
+ public static final int SERVICE_MSG_ON_LOAD_CHILDREN = 3;
+
+ public static final String SERVICE_DATA_MEDIA_SESSION_TOKEN = "data_media_session_token";
+ public static final String SERVICE_DATA_EXTRAS = "data_extras";
+ public static final String SERVICE_DATA_MEDIA_ITEM_LIST = "data_media_item_list";
+ public static final String SERVICE_DATA_RESULT_RECEIVER = "data_result_receiver";
+
+ public static final String EXTRA_SERVICE_VERSION = "extra_service_version";
+ public static final String EXTRA_MESSENGER_BINDER = "extra_messenger";
+
+ /**
+ * MediaBrowserServiceCompat will check the version of the MediaBrowserCompat, and it will not
+ * send messages if they are introduced in the higher version of the MediaBrowserCompat.
+ */
+ public static final int CLIENT_VERSION_1 = 1;
+ public static final int CLIENT_VERSION_CURRENT = CLIENT_VERSION_1;
+
+ /*
+ * Messages sent from the media browser compat to the media browser service compat.
+ * (Compat implementation for IMediaBrowserService)
+ * DO NOT RENUMBER THESE!
+ */
+
+ /** (client v1)
+ * Sent to connect to the media browse service compat.
+ * - arg1 : The client version
+ * - obj : The package name
+ * - data : An optional root hints bundle of service-specific arguments
+ * - replayTo : Client messenger
+ */
+ public static final int CLIENT_MSG_CONNECT = 1;
+
+ /** (client v1)
+ * Sent to disconnect from the media browse service compat.
+ * - arg1 : The client version
+ * - replayTo : Client messenger
+ */
+ public static final int CLIENT_MSG_DISCONNECT = 2;
+
+ /** (client v1)
+ * Sent to subscribe for changes to the children of the specified media id.
+ * - arg1 : The client version
+ * - obj : The media item id
+ * - replayTo : Client messenger
+ */
+ public static final int CLIENT_MSG_ADD_SUBSCRIPTION = 3;
+
+ /** (client v1)
+ * Sent to unsubscribe for changes to the children of the specified media id.
+ * - arg1 : The client version
+ * - obj : The media item id
+ * - replayTo : Client messenger
+ */
+ public static final int CLIENT_MSG_REMOVE_SUBSCRIPTION = 4;
+
+ /** (client v1)
+ * Sent to retrieves a specific media item from the connected service.
+ * - arg1 : The client version
+ * - obj : The media item id
+ * - data
+ * SERVICE_DATA_RESULT_RECEIVER : Result receiver to get the result
+ */
+ public static final int CLIENT_MSG_GET_MEDIA_ITEM = 5;
+}
diff --git a/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java b/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java
new file mode 100644
index 0000000..205e789
--- /dev/null
+++ b/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java
@@ -0,0 +1,803 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.BundleCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.os.ResultReceiver;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import static android.support.v4.media.MediaBrowserProtocol.*;
+
+/**
+ * Base class for media browse services.
+ * <p>
+ * Media browse services enable applications to browse media content provided by an application
+ * and ask the application to start playing it. They may also be used to control content that
+ * is already playing by way of a {@link MediaSessionCompat}.
+ * </p>
+ *
+ * To extend this class, you must declare the service in your manifest file with
+ * an intent filter with the {@link #SERVICE_INTERFACE} action.
+ *
+ * For example:
+ * </p><pre>
+ * <service android:name=".MyMediaBrowserServiceCompat"
+ * android:label="@string/service_name" >
+ * <intent-filter>
+ * <action android:name="android.media.browse.MediaBrowserService" />
+ * </intent-filter>
+ * </service>
+ * </pre>
+ */
+public abstract class MediaBrowserServiceCompat extends Service {
+ private static final String TAG = "MediaBrowserServiceCompat";
+ private static final boolean DBG = false;
+
+ private MediaBrowserServiceImpl mImpl;
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+
+ /**
+ * A key for passing the MediaItem to the ResultReceiver in getItem.
+ *
+ * @hide
+ */
+ public static final String KEY_MEDIA_ITEM = "media_item";
+
+ private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap();
+ private final ServiceHandler mHandler = new ServiceHandler();
+ MediaSessionCompat.Token mSession;
+
+ interface MediaBrowserServiceImpl {
+ void onCreate();
+ IBinder onBind(Intent intent);
+ }
+
+ class MediaBrowserServiceImplBase implements MediaBrowserServiceImpl {
+ private Messenger mMessenger;
+
+ @Override
+ public void onCreate() {
+ mMessenger = new Messenger(mHandler);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mMessenger.getBinder();
+ }
+ return null;
+ }
+ }
+
+ class MediaBrowserServiceImplApi21 implements MediaBrowserServiceImpl {
+ private Object mServiceObj;
+
+ @Override
+ public void onCreate() {
+ mServiceObj = MediaBrowserServiceCompatApi21.createService();
+ MediaBrowserServiceCompatApi21.onCreate(mServiceObj, new ServiceImplApi21());
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return MediaBrowserServiceCompatApi21.onBind(mServiceObj, intent);
+ }
+ }
+
+ class MediaBrowserServiceImplApi23 implements MediaBrowserServiceImpl {
+ private Object mServiceObj;
+
+ @Override
+ public void onCreate() {
+ mServiceObj = MediaBrowserServiceCompatApi23.createService();
+ MediaBrowserServiceCompatApi23.onCreate(mServiceObj, new ServiceImplApi23());
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return MediaBrowserServiceCompatApi23.onBind(mServiceObj, intent);
+ }
+ }
+
+ private final class ServiceHandler extends Handler {
+ private final ServiceImpl mServiceImpl = new ServiceImpl();
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case CLIENT_MSG_CONNECT:
+ mServiceImpl.connect((String) msg.obj, msg.getData(),
+ new ServiceCallbacksCompat(msg.replyTo));
+ break;
+ case CLIENT_MSG_DISCONNECT:
+ mServiceImpl.disconnect(new ServiceCallbacksCompat(msg.replyTo));
+ break;
+ case CLIENT_MSG_ADD_SUBSCRIPTION:
+ mServiceImpl.addSubscription((String) msg.obj,
+ new ServiceCallbacksCompat(msg.replyTo));
+ break;
+ case CLIENT_MSG_REMOVE_SUBSCRIPTION:
+ mServiceImpl.removeSubscription((String) msg.obj,
+ new ServiceCallbacksCompat(msg.replyTo));
+ break;
+ case CLIENT_MSG_GET_MEDIA_ITEM:
+ mServiceImpl.getMediaItem((String) msg.obj, (ResultReceiver) msg.getData()
+ .getParcelable(SERVICE_DATA_RESULT_RECEIVER));
+ break;
+ default:
+ Log.w(TAG, "Unhandled message: " + msg
+ + "\n Service version: " + SERVICE_VERSION_CURRENT
+ + "\n Client version: " + msg.arg1);
+ }
+ }
+
+ public void postOrRun(Runnable r) {
+ if (Thread.currentThread() == getLooper().getThread()) {
+ r.run();
+ } else {
+ post(r);
+ }
+ }
+
+ public ServiceImpl getServiceImpl() {
+ return mServiceImpl;
+ }
+ }
+
+ /**
+ * All the info about a connection.
+ */
+ private class ConnectionRecord {
+ String pkg;
+ Bundle rootHints;
+ ServiceCallbacks callbacks;
+ BrowserRoot root;
+ HashSet<String> subscriptions = new HashSet();
+ }
+
+ /**
+ * Completion handler for asynchronous callback methods in {@link MediaBrowserServiceCompat}.
+ * <p>
+ * Each of the methods that takes one of these to send the result must call
+ * {@link #sendResult} to respond to the caller with the given results. If those
+ * functions return without calling {@link #sendResult}, they must instead call
+ * {@link #detach} before returning, and then may call {@link #sendResult} when
+ * they are done. If more than one of those methods is called, an exception will
+ * be thrown.
+ *
+ * @see MediaBrowserServiceCompat#onLoadChildren
+ * @see MediaBrowserServiceCompat#onLoadItem
+ */
+ public static class Result<T> {
+ private Object mDebug;
+ private boolean mDetachCalled;
+ private boolean mSendResultCalled;
+
+ Result(Object debug) {
+ mDebug = debug;
+ }
+
+ /**
+ * Send the result back to the caller.
+ */
+ public void sendResult(T result) {
+ if (mSendResultCalled) {
+ throw new IllegalStateException("sendResult() called twice for: " + mDebug);
+ }
+ mSendResultCalled = true;
+ onResultSent(result);
+ }
+
+ /**
+ * Detach this message from the current thread and allow the {@link #sendResult}
+ * call to happen later.
+ */
+ public void detach() {
+ if (mDetachCalled) {
+ throw new IllegalStateException("detach() called when detach() had already"
+ + " been called for: " + mDebug);
+ }
+ if (mSendResultCalled) {
+ throw new IllegalStateException("detach() called when sendResult() had already"
+ + " been called for: " + mDebug);
+ }
+ mDetachCalled = true;
+ }
+
+ boolean isDone() {
+ return mDetachCalled || mSendResultCalled;
+ }
+
+ /**
+ * Called when the result is sent, after assertions about not being called twice
+ * have happened.
+ */
+ void onResultSent(T result) {
+ }
+ }
+
+ private class ServiceImpl {
+ public void connect(final String pkg, final Bundle rootHints,
+ final ServiceCallbacks callbacks) {
+
+ final int uid = Binder.getCallingUid();
+ if (!isValidPackage(pkg, uid)) {
+ throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
+ + " package=" + pkg);
+ }
+
+ mHandler.postOrRun(new Runnable() {
+ @Override
+ public void run() {
+ final IBinder b = callbacks.asBinder();
+
+ // Clear out the old subscriptions. We are getting new ones.
+ mConnections.remove(b);
+
+ final ConnectionRecord connection = new ConnectionRecord();
+ connection.pkg = pkg;
+ connection.rootHints = rootHints;
+ connection.callbacks = callbacks;
+
+ connection.root =
+ MediaBrowserServiceCompat.this.onGetRoot(pkg, uid, rootHints);
+
+ // If they didn't return something, don't allow this client.
+ if (connection.root == null) {
+ Log.i(TAG, "No root for client " + pkg + " from service "
+ + getClass().getName());
+ try {
+ callbacks.onConnectFailed();
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. "
+ + "pkg=" + pkg);
+ }
+ } else {
+ try {
+ mConnections.put(b, connection);
+ if (mSession != null) {
+ callbacks.onConnect(connection.root.getRootId(),
+ mSession, connection.root.getExtras());
+ }
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Calling onConnect() failed. Dropping client. "
+ + "pkg=" + pkg);
+ mConnections.remove(b);
+ }
+ }
+ }
+ });
+ }
+
+ public void disconnect(final ServiceCallbacks callbacks) {
+ mHandler.postOrRun(new Runnable() {
+ @Override
+ public void run() {
+ final IBinder b = callbacks.asBinder();
+
+ // Clear out the old subscriptions. We are getting new ones.
+ final ConnectionRecord old = mConnections.remove(b);
+ if (old != null) {
+ // TODO
+ }
+ }
+ });
+ }
+
+
+ public void addSubscription(final String id, final ServiceCallbacks callbacks) {
+ mHandler.postOrRun(new Runnable() {
+ @Override
+ public void run() {
+ final IBinder b = callbacks.asBinder();
+
+ // Get the record for the connection
+ final ConnectionRecord connection = mConnections.get(b);
+ if (connection == null) {
+ Log.w(TAG, "addSubscription for callback that isn't registered id="
+ + id);
+ return;
+ }
+
+ MediaBrowserServiceCompat.this.addSubscription(id, connection);
+ }
+ });
+ }
+
+ public void removeSubscription(final String id, final ServiceCallbacks callbacks) {
+ mHandler.postOrRun(new Runnable() {
+ @Override
+ public void run() {
+ final IBinder b = callbacks.asBinder();
+
+ ConnectionRecord connection = mConnections.get(b);
+ if (connection == null) {
+ Log.w(TAG, "removeSubscription for callback that isn't registered id="
+ + id);
+ return;
+ }
+ if (!connection.subscriptions.remove(id)) {
+ Log.w(TAG, "removeSubscription called for " + id
+ + " which is not subscribed");
+ }
+ }
+ });
+ }
+
+ public void getMediaItem(final String mediaId, final ResultReceiver receiver) {
+ if (TextUtils.isEmpty(mediaId) || receiver == null) {
+ return;
+ }
+
+ mHandler.postOrRun(new Runnable() {
+ @Override
+ public void run() {
+ performLoadItem(mediaId, receiver);
+ }
+ });
+ }
+ }
+
+ private class ServiceImplApi21 implements MediaBrowserServiceCompatApi21.ServiceImplApi21 {
+ final ServiceImpl mServiceImpl;
+
+ ServiceImplApi21() {
+ mServiceImpl = mHandler.getServiceImpl();
+ }
+
+ @Override
+ public void connect(final String pkg, final Bundle rootHints,
+ final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+ mServiceImpl.connect(pkg, rootHints, new ServiceCallbacksApi21(callbacks));
+ }
+
+ @Override
+ public void disconnect(final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+ mServiceImpl.disconnect(new ServiceCallbacksApi21(callbacks));
+ }
+
+
+ @Override
+ public void addSubscription(
+ final String id, final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+ mServiceImpl.addSubscription(id, new ServiceCallbacksApi21(callbacks));
+ }
+
+ @Override
+ public void removeSubscription(final String id,
+ final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+ mServiceImpl.removeSubscription(id, new ServiceCallbacksApi21(callbacks));
+ }
+ }
+
+ private class ServiceImplApi23 extends ServiceImplApi21
+ implements MediaBrowserServiceCompatApi23.ServiceImplApi23 {
+ @Override
+ public void getMediaItem(final String mediaId,
+ final MediaBrowserServiceCompatApi23.ItemCallback cb) {
+ ResultReceiver receiverCompat = new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ MediaBrowserCompat.MediaItem item = resultData.getParcelable(KEY_MEDIA_ITEM);
+ Parcel itemParcel = null;
+ if (item != null) {
+ itemParcel = Parcel.obtain();
+ item.writeToParcel(itemParcel, 0);
+ }
+ cb.onItemLoaded(resultCode, resultData, itemParcel);
+ }
+ };
+ mServiceImpl.getMediaItem(mediaId, receiverCompat);
+ }
+ }
+
+ private interface ServiceCallbacks {
+ IBinder asBinder();
+ void onConnect(String root, MediaSessionCompat.Token session, Bundle extras)
+ throws RemoteException;
+ void onConnectFailed() throws RemoteException;
+ void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list)
+ throws RemoteException;
+ }
+
+ private class ServiceCallbacksCompat implements ServiceCallbacks {
+ final Messenger mCallbacks;
+
+ ServiceCallbacksCompat(Messenger callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ public IBinder asBinder() {
+ return mCallbacks.getBinder();
+ }
+
+ public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras)
+ throws RemoteException {
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT);
+ Bundle data = new Bundle();
+ data.putParcelable(SERVICE_DATA_MEDIA_SESSION_TOKEN, session);
+ data.putBundle(SERVICE_DATA_EXTRAS, extras);
+ sendRequest(SERVICE_MSG_ON_CONNECT, root, data);
+ }
+
+ public void onConnectFailed() throws RemoteException {
+ sendRequest(SERVICE_MSG_ON_CONNECT_FAILED, null, null);
+ }
+
+ public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list)
+ throws RemoteException {
+ Bundle data = null;
+ if (list != null) {
+ data = new Bundle();
+ data.putParcelableArrayList(SERVICE_DATA_MEDIA_ITEM_LIST,
+ list instanceof ArrayList ? (ArrayList) list : new ArrayList<>(list));
+ }
+ sendRequest(SERVICE_MSG_ON_LOAD_CHILDREN, mediaId, data);
+ }
+
+ private void sendRequest(int what, Object obj, Bundle data)
+ throws RemoteException {
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg1 = SERVICE_VERSION_CURRENT;
+ msg.obj = obj;
+ msg.setData(data);
+ mCallbacks.send(msg);
+ }
+ }
+
+ private class ServiceCallbacksApi21 implements ServiceCallbacks {
+ final MediaBrowserServiceCompatApi21.ServiceCallbacks mCallbacks;
+ Messenger mMessenger;
+
+ ServiceCallbacksApi21(MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ public IBinder asBinder() {
+ return mCallbacks.asBinder();
+ }
+
+ public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras)
+ throws RemoteException {
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ mMessenger = new Messenger(mHandler);
+ BundleCompat.putBinder(extras, EXTRA_MESSENGER_BINDER, mMessenger.getBinder());
+ extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT);
+ mCallbacks.onConnect(root, session.getToken(), extras);
+ }
+
+ public void onConnectFailed() throws RemoteException {
+ mCallbacks.onConnectFailed();
+ }
+
+ public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list)
+ throws RemoteException {
+ List<Parcel> parcelList = null;
+ if (list != null) {
+ parcelList = new ArrayList<>();
+ for (MediaBrowserCompat.MediaItem item : list) {
+ Parcel parcel = Parcel.obtain();
+ item.writeToParcel(parcel, 0);
+ parcelList.add(parcel);
+ }
+ }
+ mCallbacks.onLoadChildren(mediaId, parcelList);
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ if (Build.VERSION.SDK_INT >= 23) {
+ mImpl = new MediaBrowserServiceImplApi23();
+ } else if (Build.VERSION.SDK_INT >= 21) {
+ mImpl = new MediaBrowserServiceImplApi21();
+ } else {
+ mImpl = new MediaBrowserServiceImplBase();
+ }
+ mImpl.onCreate();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mImpl.onBind(intent);
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ }
+
+ /**
+ * Called to get the root information for browsing by a particular client.
+ * <p>
+ * The implementation should verify that the client package has permission
+ * to access browse media information before returning the root id; it
+ * should return null if the client is not allowed to access this
+ * information.
+ * </p>
+ *
+ * @param clientPackageName The package name of the application which is
+ * requesting access to browse media.
+ * @param clientUid The uid of the application which is requesting access to
+ * browse media.
+ * @param rootHints An optional bundle of service-specific arguments to send
+ * to the media browse service when connecting and retrieving the
+ * root id for browsing, or null if none. The contents of this
+ * bundle may affect the information returned when browsing.
+ * @return The {@link BrowserRoot} for accessing this app's content or null.
+ */
+ public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
+ int clientUid, @Nullable Bundle rootHints);
+
+ /**
+ * Called to get information about the children of a media item.
+ * <p>
+ * Implementations must call {@link Result#sendResult result.sendResult}
+ * with the list of children. If loading the children will be an expensive
+ * operation that should be performed on another thread,
+ * {@link Result#detach result.detach} may be called before returning from
+ * this function, and then {@link Result#sendResult result.sendResult}
+ * called when the loading is complete.
+ *
+ * @param parentId The id of the parent media item whose children are to be
+ * queried.
+ * @param result The Result to send the list of children to, or null if the
+ * id is invalid.
+ */
+ public abstract void onLoadChildren(@NonNull String parentId,
+ @NonNull Result<List<MediaBrowserCompat.MediaItem>> result);
+
+ /**
+ * Called to get information about a specific media item.
+ * <p>
+ * Implementations must call {@link Result#sendResult result.sendResult}. If
+ * loading the item will be an expensive operation {@link Result#detach
+ * result.detach} may be called before returning from this function, and
+ * then {@link Result#sendResult result.sendResult} called when the item has
+ * been loaded.
+ * <p>
+ * The default implementation sends a null result.
+ *
+ * @param itemId The id for the specific
+ * {@link MediaBrowserCompat.MediaItem}.
+ * @param result The Result to send the item to, or null if the id is
+ * invalid.
+ */
+ public void onLoadItem(String itemId, Result<MediaBrowserCompat.MediaItem> result) {
+ result.sendResult(null);
+ }
+
+ /**
+ * Call to set the media session.
+ * <p>
+ * This should be called as soon as possible during the service's startup.
+ * It may only be called once.
+ *
+ * @param token The token for the service's {@link MediaSessionCompat}.
+ */
+ public void setSessionToken(final MediaSessionCompat.Token token) {
+ if (token == null) {
+ throw new IllegalArgumentException("Session token may not be null.");
+ }
+ if (mSession != null) {
+ throw new IllegalStateException("The session token has already been set.");
+ }
+ mSession = token;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (IBinder key : mConnections.keySet()) {
+ ConnectionRecord connection = mConnections.get(key);
+ try {
+ connection.callbacks.onConnect(connection.root.getRootId(), token,
+ connection.root.getExtras());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
+ mConnections.remove(key);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Gets the session token, or null if it has not yet been created
+ * or if it has been destroyed.
+ */
+ public @Nullable MediaSessionCompat.Token getSessionToken() {
+ return mSession;
+ }
+
+ /**
+ * Notifies all connected media browsers that the children of
+ * the specified parent id have changed in some way.
+ * This will cause browsers to fetch subscribed content again.
+ *
+ * @param parentId The id of the parent media item whose
+ * children changed.
+ */
+ public void notifyChildrenChanged(@NonNull final String parentId) {
+ if (parentId == null) {
+ throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged");
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (IBinder binder : mConnections.keySet()) {
+ ConnectionRecord connection = mConnections.get(binder);
+ if (connection.subscriptions.contains(parentId)) {
+ performLoadChildren(parentId, connection);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Return whether the given package is one of the ones that is owned by the uid.
+ */
+ private boolean isValidPackage(String pkg, int uid) {
+ if (pkg == null) {
+ return false;
+ }
+ final PackageManager pm = getPackageManager();
+ final String[] packages = pm.getPackagesForUid(uid);
+ final int N = packages.length;
+ for (int i=0; i<N; i++) {
+ if (packages[i].equals(pkg)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Save the subscription and if it is a new subscription send the results.
+ */
+ private void addSubscription(String id, ConnectionRecord connection) {
+ // Save the subscription
+ connection.subscriptions.add(id);
+
+ // send the results
+ performLoadChildren(id, connection);
+ }
+
+ /**
+ * Call onLoadChildren and then send the results back to the connection.
+ * <p>
+ * Callers must make sure that this connection is still connected.
+ */
+ private void performLoadChildren(final String parentId, final ConnectionRecord connection) {
+ final Result<List<MediaBrowserCompat.MediaItem>> result
+ = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) {
+ @Override
+ void onResultSent(List<MediaBrowserCompat.MediaItem> list) {
+ if (mConnections.get(connection.callbacks.asBinder()) != connection) {
+ if (DBG) {
+ Log.d(TAG, "Not sending onLoadChildren result for connection that has"
+ + " been disconnected. pkg=" + connection.pkg + " id=" + parentId);
+ }
+ return;
+ }
+
+ try {
+ connection.callbacks.onLoadChildren(parentId, list);
+ } catch (RemoteException ex) {
+ // The other side is in the process of crashing.
+ Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
+ + " package=" + connection.pkg);
+ }
+ }
+ };
+
+ onLoadChildren(parentId, result);
+
+ if (!result.isDone()) {
+ throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
+ + " before returning for package=" + connection.pkg + " id=" + parentId);
+ }
+ }
+
+ private void performLoadItem(String itemId, final ResultReceiver receiver) {
+ final Result<MediaBrowserCompat.MediaItem> result =
+ new Result<MediaBrowserCompat.MediaItem>(itemId) {
+ @Override
+ void onResultSent(MediaBrowserCompat.MediaItem item) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_MEDIA_ITEM, item);
+ receiver.send(0, bundle);
+ }
+ };
+
+ MediaBrowserServiceCompat.this.onLoadItem(itemId, result);
+
+ if (!result.isDone()) {
+ throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
+ + " before returning for id=" + itemId);
+ }
+ }
+
+ /**
+ * Contains information that the browser service needs to send to the client
+ * when first connected.
+ */
+ public static final class BrowserRoot {
+ final private String mRootId;
+ final private Bundle mExtras;
+
+ /**
+ * Constructs a browser root.
+ * @param rootId The root id for browsing.
+ * @param extras Any extras about the browser service.
+ */
+ public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) {
+ if (rootId == null) {
+ throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " +
+ "Use null for BrowserRoot instead.");
+ }
+ mRootId = rootId;
+ mExtras = extras;
+ }
+
+ /**
+ * Gets the root id for browsing.
+ */
+ public String getRootId() {
+ return mRootId;
+ }
+
+ /**
+ * Gets any extras about the brwoser service.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+ }
+}
diff --git a/v4/java/android/support/v4/media/MediaMetadataCompat.java b/v4/java/android/support/v4/media/MediaMetadataCompat.java
index 088b208..0d07826 100644
--- a/v4/java/android/support/v4/media/MediaMetadataCompat.java
+++ b/v4/java/android/support/v4/media/MediaMetadataCompat.java
@@ -78,7 +78,8 @@
public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
/**
- * The date the media was created or published as TODO determine format.
+ * The date the media was created or published. The format is unspecified
+ * but RFC 3339 is recommended.
*/
public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
@@ -360,7 +361,13 @@
public RatingCompat getRating(@RatingKey String key) {
RatingCompat rating = null;
try {
- rating = mBundle.getParcelable(key);
+ if (Build.VERSION.SDK_INT >= 21) {
+ // On platform version 21 or higher, mBundle stores a Rating object. Convert it to
+ // RatingCompat.
+ rating = RatingCompat.fromRating(mBundle.getParcelable(key));
+ } else {
+ rating = mBundle.getParcelable(key);
+ }
} catch (Exception e) {
// ignore, value was not a bitmap
Log.w(TAG, "Failed to retrieve a key as Rating.", e);
@@ -509,31 +516,11 @@
return null;
}
- Builder builder = new Builder();
- for (String key : MediaMetadataCompatApi21.keySet(metadataObj)) {
- Integer type = METADATA_KEYS_TYPE.get(key);
- if (type != null) {
- switch (type) {
- case METADATA_TYPE_BITMAP:
- builder.putBitmap(key,
- MediaMetadataCompatApi21.getBitmap(metadataObj, key));
- break;
- case METADATA_TYPE_LONG:
- builder.putLong(key,
- MediaMetadataCompatApi21.getLong(metadataObj, key));
- break;
- case METADATA_TYPE_RATING:
- builder.putRating(key, RatingCompat.fromRating(
- MediaMetadataCompatApi21.getRating(metadataObj, key)));
- break;
- case METADATA_TYPE_TEXT:
- builder.putText(key,
- MediaMetadataCompatApi21.getText(metadataObj, key));
- break;
- }
- }
- }
- MediaMetadataCompat metadata = builder.build();
+ Parcel p = Parcel.obtain();
+ MediaMetadataCompatApi21.writeToParcel(metadataObj, p, 0);
+ p.setDataPosition(0);
+ MediaMetadataCompat metadata = MediaMetadataCompat.CREATOR.createFromParcel(p);
+ p.recycle();
metadata.mMetadataObj = metadataObj;
return metadata;
}
@@ -553,31 +540,11 @@
return mMetadataObj;
}
- Object builderObj = MediaMetadataCompatApi21.Builder.newInstance();
- for (String key : keySet()) {
- Integer type = METADATA_KEYS_TYPE.get(key);
- if (type != null) {
- switch (type) {
- case METADATA_TYPE_BITMAP:
- MediaMetadataCompatApi21.Builder.putBitmap(builderObj, key,
- getBitmap(key));
- break;
- case METADATA_TYPE_LONG:
- MediaMetadataCompatApi21.Builder.putLong(builderObj, key,
- getLong(key));
- break;
- case METADATA_TYPE_RATING:
- MediaMetadataCompatApi21.Builder.putRating(builderObj, key,
- getRating(key).getRating());
- break;
- case METADATA_TYPE_TEXT:
- MediaMetadataCompatApi21.Builder.putText(builderObj, key,
- getText(key));
- break;
- }
- }
- }
- mMetadataObj = MediaMetadataCompatApi21.Builder.build(builderObj);
+ Parcel p = Parcel.obtain();
+ writeToParcel(p, 0);
+ p.setDataPosition(0);
+ mMetadataObj = MediaMetadataCompatApi21.createFromParcel(p);
+ p.recycle();
return mMetadataObj;
}
@@ -741,7 +708,13 @@
+ " key cannot be used to put a Rating");
}
}
- mBundle.putParcelable(key, value);
+ if (Build.VERSION.SDK_INT >= 21) {
+ // On platform version 21 or higher, use Rating instead of RatingCompat so mBundle
+ // can be unmarshalled.
+ mBundle.putParcelable(key, (Parcelable) value.getRating());
+ } else {
+ mBundle.putParcelable(key, value);
+ }
return this;
}
diff --git a/v4/java/android/support/v4/media/session/MediaButtonReceiver.java b/v4/java/android/support/v4/media/session/MediaButtonReceiver.java
new file mode 100644
index 0000000..d5eb0e8
--- /dev/null
+++ b/v4/java/android/support/v4/media/session/MediaButtonReceiver.java
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.media.session;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.view.KeyEvent;
+
+import java.util.List;
+
+/**
+ * A media button receiver receives and helps translate hardware media playback buttons,
+ * such as those found on wired and wireless headsets, into the appropriate callbacks
+ * in your app.
+ * <p />
+ * You can add this MediaButtonReceiver to your app by adding it directly to your
+ * AndroidManifest.xml:
+ * <pre>
+ * <receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
+ * <intent-filter>
+ * <action android:name="android.intent.action.MEDIA_BUTTON" />
+ * </intent-filter>
+ * </receiver>
+ * </pre>
+ * This class assumes you have a {@link Service} in your app that controls
+ * media playback via a {@link MediaSessionCompat}. That {@link Service} must
+ * include an intent filter that also handles {@link Intent#ACTION_MEDIA_BUTTON}:
+ * <pre>
+ * <service android:name="com.example.android.MediaPlaybackService" >
+ * <intent-filter>
+ * <action android:name="android.intent.action.MEDIA_BUTTON" />
+ * </intent-filter>
+ * </service>
+ * </pre>
+ *
+ * All {@link Intent}s sent to this MediaButtonReceiver will then be forwarded
+ * to the {@link Service}. Events can then be handled in
+ * {@link Service#onStartCommand(Intent, int, int)} by calling
+ * {@link MediaButtonReceiver#handleIntent(MediaSessionCompat, Intent)}, passing in
+ * your current {@link MediaSessionCompat}:
+ * <pre>
+ * private MediaSessionCompat mMediaSessionCompat = ...;
+ *
+ * public int onStartCommand(Intent intent, int flags, int startId) {
+ * MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent);
+ * return super.onStartCommand(intent, flags, startId);
+ * }
+ * </pre>
+ *
+ * This ensures that the correct callbacks to {@link MediaSessionCompat.Callback}
+ * will be triggered based on the incoming {@link KeyEvent}.
+ */
+public class MediaButtonReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Intent queryIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ queryIntent.setPackage(context.getPackageName());
+ PackageManager pm = context.getPackageManager();
+ List<ResolveInfo> resolveInfos = pm.queryIntentServices(queryIntent, 0);
+ if (resolveInfos.size() != 1) {
+ throw new IllegalStateException("Expected 1 Service that handles " +
+ Intent.ACTION_MEDIA_BUTTON + ", found " + resolveInfos.size());
+ }
+ ResolveInfo resolveInfo = resolveInfos.get(0);
+ ComponentName componentName = new ComponentName(resolveInfo.serviceInfo.packageName,
+ resolveInfo.serviceInfo.name);
+ intent.setComponent(componentName);
+ context.startService(intent);
+ }
+
+ /**
+ * Extracts any available {@link KeyEvent} from an {@link Intent#ACTION_MEDIA_BUTTON}
+ * intent, passing it onto the {@link MediaSessionCompat} using
+ * {@link MediaControllerCompat#dispatchMediaButtonEvent(KeyEvent)}, which in turn
+ * will trigger callbacks to the {@link MediaSessionCompat.Callback} registered via
+ * {@link MediaSessionCompat#setCallback(MediaSessionCompat.Callback)}.
+ * <p />
+ * The returned {@link KeyEvent} is non-null if any {@link KeyEvent} is found and can
+ * be used if any additional processing is needed beyond what is done in the
+ * {@link MediaSessionCompat.Callback}. An example of is to prevent redelivery of a
+ * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE} Intent in the case of the Service being
+ * restarted (which, by default, will redeliver the last received Intent).
+ * <pre>
+ * KeyEvent keyEvent = MediaButtonReceiver.handleIntent(mediaSession, intent);
+ * if (keyEvent != null && keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
+ * Intent emptyIntent = new Intent(intent);
+ * emptyIntent.setAction("");
+ * startService(emptyIntent);
+ * }
+ * </pre>
+ * @param mediaSessionCompat A {@link MediaSessionCompat} that has a
+ * {@link MediaSessionCompat.Callback} set.
+ * @param intent The intent to parse.
+ * @return The extracted {@link KeyEvent} if found, or null.
+ */
+ public static KeyEvent handleIntent(MediaSessionCompat mediaSessionCompat, Intent intent) {
+ if (mediaSessionCompat == null || intent == null
+ || !Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
+ || !intent.hasExtra(Intent.EXTRA_KEY_EVENT)) {
+ return null;
+ }
+ KeyEvent ke = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+ MediaControllerCompat mediaController = mediaSessionCompat.getController();
+ mediaController.dispatchMediaButtonEvent(ke);
+ return ke;
+ }
+}
+
diff --git a/v4/java/android/support/v4/media/session/MediaControllerCompat.java b/v4/java/android/support/v4/media/session/MediaControllerCompat.java
index 1d2180c..a6a5c88 100644
--- a/v4/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/v4/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -92,7 +92,9 @@
}
mToken = sessionToken;
- if (android.os.Build.VERSION.SDK_INT >= 21) {
+ if (android.os.Build.VERSION.SDK_INT >= 23) {
+ mImpl = new MediaControllerImplApi23(context, sessionToken);
+ } else if (android.os.Build.VERSION.SDK_INT >= 21) {
mImpl = new MediaControllerImplApi21(context, sessionToken);
} else {
mImpl = new MediaControllerImplBase(mToken);
@@ -555,7 +557,9 @@
}
public void post(int what, Object obj, Bundle data) {
- obtainMessage(what, obj).sendToTarget();
+ Message msg = obtainMessage(what, obj);
+ msg.setData(data);
+ msg.sendToTarget();
}
}
}
@@ -1328,6 +1332,14 @@
@Override
public void playFromUri(Uri uri, Bundle extras) {
+ if (uri == null || Uri.EMPTY.equals(uri)) {
+ throw new IllegalArgumentException(
+ "You must specify a non-empty Uri for playFromUri.");
+ }
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(MediaSessionCompat.ACTION_ARGUMENT_URI, uri);
+ bundle.putParcelable(MediaSessionCompat.ACTION_ARGUMENT_EXTRAS, extras);
+ sendCustomAction(MediaSessionCompat.ACTION_PLAY_FROM_URI, bundle);
}
@Override
diff --git a/v4/java/android/support/v4/media/session/MediaSessionCompat.java b/v4/java/android/support/v4/media/session/MediaSessionCompat.java
index fa963df..d35ada6 100644
--- a/v4/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/v4/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -19,9 +19,12 @@
import android.app.Activity;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
@@ -77,6 +80,8 @@
* backwards compatible fashion.
*/
public class MediaSessionCompat {
+ private static final String TAG = "MediaSessionCompat";
+
private final MediaSessionImpl mImpl;
private final MediaControllerCompat mController;
private final ArrayList<OnActiveChangeListener>
@@ -102,12 +107,51 @@
public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
/**
+ * Custom action to invoke playFromUri() for the forward compatibility.
+ *
+ * @hide
+ */
+ public static final String ACTION_PLAY_FROM_URI =
+ "android.support.v4.media.session.action.PLAY_FROM_URI";
+
+ /**
+ * Argument for use with {@link #ACTION_PLAY_FROM_URI} indicating URI to play.
+ *
+ * @hide
+ */
+ public static final String ACTION_ARGUMENT_URI =
+ "android.support.v4.media.session.action.ARGUMENT_URI";
+
+ /**
+ * Argument for use with {@link #ACTION_PLAY_FROM_URI} indicating extra bundle.
+ *
+ * @hide
+ */
+ public static final String ACTION_ARGUMENT_EXTRAS =
+ "android.support.v4.media.session.action.ARGUMENT_EXTRAS";
+
+ /**
+ * Creates a new session using a media button receiver from your manifest.
+ * Note that a media button receiver is required to support platform versions
+ * earlier than {@link android.os.Build.VERSION_CODES#LOLLIPOP}.
+ *
+ * @param context The context.
+ * @param tag A short name for debugging purposes.
+ */
+ public MediaSessionCompat(Context context, String tag) {
+ this(context, tag, null, null);
+ }
+
+ /**
* Creates a new session.
*
* @param context The context.
* @param tag A short name for debugging purposes.
* @param mediaButtonEventReceiver The component name for your receiver.
- * This must be non-null to support platform versions earlier
+ * If null, this will attempt to find an appropriate
+ * {@link BroadcastReceiver} that handles
+ * {@link Intent#ACTION_MEDIA_BUTTON} from your manifest.
+ * A receiver is required to support platform versions earlier
* than {@link android.os.Build.VERSION_CODES#LOLLIPOP}.
* @param mbrIntent The PendingIntent for your receiver component that
* handles media button events. This is optional and will be used
@@ -123,6 +167,24 @@
throw new IllegalArgumentException("tag must not be null or empty");
}
+ if (mediaButtonEventReceiver == null) {
+ Intent queryIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ queryIntent.setPackage(context.getPackageName());
+ PackageManager pm = context.getPackageManager();
+ List<ResolveInfo> resolveInfos = pm.queryBroadcastReceivers(queryIntent, 0);
+ // If none are found, assume we are running on a newer platform version that does
+ // not require a media button receiver ComponentName. Later code will double check
+ // this assumption and throw an error if needed
+ if (resolveInfos.size() == 1) {
+ ResolveInfo resolveInfo = resolveInfos.get(0);
+ mediaButtonEventReceiver = new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ } else if (resolveInfos.size() > 1) {
+ Log.w(TAG, "More than one BroadcastReceiver that handles " +
+ Intent.ACTION_MEDIA_BUTTON + " was found, using null. Provide a " +
+ "specific ComponentName to use as this session's media button receiver");
+ }
+ }
if (mediaButtonEventReceiver != null && mbrIntent == null) {
// construct a PendingIntent for the media button
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
@@ -250,8 +312,8 @@
* <p>
* On platforms earlier than
* {@link android.os.Build.VERSION_CODES#LOLLIPOP},
- * {@link #setMediaButtonReceiver(PendingIntent)} must be called before
- * setting this to true.
+ * a media button event receiver should be set via the constructor to
+ * receive media button events.
*
* @param active Whether this session is active or not.
*/
@@ -675,7 +737,13 @@
@Override
public void onCustomAction(String action, Bundle extras) {
- Callback.this.onCustomAction(action, extras);
+ if (action.equals(ACTION_PLAY_FROM_URI)) {
+ Uri uri = (Uri) extras.getParcelable(ACTION_ARGUMENT_URI);
+ Bundle bundle = (Bundle) extras.getParcelable(ACTION_ARGUMENT_EXTRAS);
+ Callback.this.onPlayFromUri(uri, bundle);
+ } else {
+ Callback.this.onCustomAction(action, extras);
+ }
}
}
@@ -1309,7 +1377,7 @@
if (!mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) != 0) {
if (android.os.Build.VERSION.SDK_INT >= 18) {
MediaSessionCompatApi18.registerMediaButtonEventReceiver(mContext,
- mMediaButtonEventReceiver);
+ mMediaButtonEventReceiver, mComponentName);
} else {
MediaSessionCompatApi8.registerMediaButtonEventReceiver(mContext,
mComponentName);
@@ -1318,7 +1386,7 @@
} else if (mIsMbrRegistered && (mFlags & FLAG_HANDLES_MEDIA_BUTTONS) == 0) {
if (android.os.Build.VERSION.SDK_INT >= 18) {
MediaSessionCompatApi18.unregisterMediaButtonEventReceiver(mContext,
- mMediaButtonEventReceiver);
+ mMediaButtonEventReceiver, mComponentName);
} else {
MediaSessionCompatApi8.unregisterMediaButtonEventReceiver(mContext,
mComponentName);
@@ -1348,7 +1416,7 @@
if (mIsMbrRegistered) {
if (android.os.Build.VERSION.SDK_INT >= 18) {
MediaSessionCompatApi18.unregisterMediaButtonEventReceiver(mContext,
- mMediaButtonEventReceiver);
+ mMediaButtonEventReceiver, mComponentName);
} else {
MediaSessionCompatApi8.unregisterMediaButtonEventReceiver(mContext,
mComponentName);
@@ -1373,7 +1441,7 @@
mVolumeProvider.onAdjustVolume(direction);
}
} else {
- mAudioManager.adjustStreamVolume(direction, mLocalStream, flags);
+ mAudioManager.adjustStreamVolume(mLocalStream, direction, flags);
}
}
@@ -1928,7 +1996,8 @@
@Override
public void setCallback(Callback callback, Handler handler) {
- MediaSessionCompatApi21.setCallback(mSessionObj, callback.mCallbackObj, handler);
+ MediaSessionCompatApi21.setCallback(mSessionObj,
+ callback == null ? null : callback.mCallbackObj, handler);
}
@Override
@@ -1974,12 +2043,14 @@
@Override
public void setPlaybackState(PlaybackStateCompat state) {
- MediaSessionCompatApi21.setPlaybackState(mSessionObj, state.getPlaybackState());
+ MediaSessionCompatApi21.setPlaybackState(mSessionObj,
+ state == null ? null : state.getPlaybackState());
}
@Override
public void setMetadata(MediaMetadataCompat metadata) {
- MediaSessionCompatApi21.setMetadata(mSessionObj, metadata.getMediaMetadata());
+ MediaSessionCompatApi21.setMetadata(mSessionObj,
+ metadata == null ? null : metadata.getMediaMetadata());
}
@Override
diff --git a/v4/java/android/support/v4/os/IResultReceiver.aidl b/v4/java/android/support/v4/os/IResultReceiver.aidl
new file mode 100644
index 0000000..cd23ff3
--- /dev/null
+++ b/v4/java/android/support/v4/os/IResultReceiver.aidl
@@ -0,0 +1,24 @@
+/*
+** Copyright 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.
+*/
+
+package android.support.v4.os;
+
+import android.os.Bundle;
+
+/** @hide */
+oneway interface IResultReceiver {
+ void send(int resultCode, in Bundle resultData);
+}
diff --git a/v4/java/android/support/v4/os/ResultReceiver.aidl b/v4/java/android/support/v4/os/ResultReceiver.aidl
new file mode 100644
index 0000000..81c81f6
--- /dev/null
+++ b/v4/java/android/support/v4/os/ResultReceiver.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 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.
+*/
+
+package android.support.v4.os;
+
+parcelable ResultReceiver;
diff --git a/v4/java/android/support/v4/os/ResultReceiver.java b/v4/java/android/support/v4/os/ResultReceiver.java
new file mode 100644
index 0000000..f0dc001
--- /dev/null
+++ b/v4/java/android/support/v4/os/ResultReceiver.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.os;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.support.v4.os.IResultReceiver;
+
+/**
+ * Generic interface for receiving a callback result from someone. Use this
+ * by creating a subclass and implement {@link #onReceiveResult}, which you can
+ * then pass to others and send through IPC, and receive results they
+ * supply with {@link #send}.
+ *
+ * <p>Note: the implementation underneath is just a simple wrapper around
+ * a {@link Binder} that is used to perform the communication. This means
+ * semantically you should treat it as such: this class does not impact process
+ * lifecycle management (you must be using some higher-level component to tell
+ * the system that your process needs to continue running), the connection will
+ * break if your process goes away for any reason, etc.</p>
+ * @hide
+ */
+public class ResultReceiver implements Parcelable {
+ final boolean mLocal;
+ final Handler mHandler;
+
+ IResultReceiver mReceiver;
+
+ class MyRunnable implements Runnable {
+ final int mResultCode;
+ final Bundle mResultData;
+
+ MyRunnable(int resultCode, Bundle resultData) {
+ mResultCode = resultCode;
+ mResultData = resultData;
+ }
+
+ public void run() {
+ onReceiveResult(mResultCode, mResultData);
+ }
+ }
+
+ class MyResultReceiver extends IResultReceiver.Stub {
+ public void send(int resultCode, Bundle resultData) {
+ if (mHandler != null) {
+ mHandler.post(new MyRunnable(resultCode, resultData));
+ } else {
+ onReceiveResult(resultCode, resultData);
+ }
+ }
+ }
+
+ /**
+ * Create a new ResultReceive to receive results. Your
+ * {@link #onReceiveResult} method will be called from the thread running
+ * <var>handler</var> if given, or from an arbitrary thread if null.
+ */
+ public ResultReceiver(Handler handler) {
+ mLocal = true;
+ mHandler = handler;
+ }
+
+ /**
+ * Deliver a result to this receiver. Will call {@link #onReceiveResult},
+ * always asynchronously if the receiver has supplied a Handler in which
+ * to dispatch the result.
+ * @param resultCode Arbitrary result code to deliver, as defined by you.
+ * @param resultData Any additional data provided by you.
+ */
+ public void send(int resultCode, Bundle resultData) {
+ if (mLocal) {
+ if (mHandler != null) {
+ mHandler.post(new MyRunnable(resultCode, resultData));
+ } else {
+ onReceiveResult(resultCode, resultData);
+ }
+ return;
+ }
+
+ if (mReceiver != null) {
+ try {
+ mReceiver.send(resultCode, resultData);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /**
+ * Override to receive results delivered to this object.
+ *
+ * @param resultCode Arbitrary result code delivered by the sender, as
+ * defined by the sender.
+ * @param resultData Any additional data provided by the sender.
+ */
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ synchronized (this) {
+ if (mReceiver == null) {
+ mReceiver = new MyResultReceiver();
+ }
+ out.writeStrongBinder(mReceiver.asBinder());
+ }
+ }
+
+ ResultReceiver(Parcel in) {
+ mLocal = false;
+ mHandler = null;
+ mReceiver = IResultReceiver.Stub.asInterface(in.readStrongBinder());
+ }
+
+ public static final Parcelable.Creator<ResultReceiver> CREATOR
+ = new Parcelable.Creator<ResultReceiver>() {
+ public ResultReceiver createFromParcel(Parcel in) {
+ return new ResultReceiver(in);
+ }
+ public ResultReceiver[] newArray(int size) {
+ return new ResultReceiver[size];
+ }
+ };
+}
diff --git a/v4/java/android/support/v4/view/ActionProvider.java b/v4/java/android/support/v4/view/ActionProvider.java
index d195a3a..070ea46 100644
--- a/v4/java/android/support/v4/view/ActionProvider.java
+++ b/v4/java/android/support/v4/view/ActionProvider.java
@@ -60,6 +60,63 @@
* </code></pre>
* </li></ul></p>
*
+ * <h3>Creating a custom action provider</h3>
+ *
+ * <p>To create a custom action provider, extend ActionProvider and implement
+ * its callback methods as necessary. In particular, implement the following
+ * methods:</p>
+ *
+ * <dl>
+ * <dt>{@link #ActionProvider ActionProvider()} constructor</dt>
+ * <dd>This constructor is passed the application context. You should
+ * save the context in a member field to use in the other callback methods.</dd>
+ *
+ * <dt>{@link #onCreateActionView onCreateActionView(MenuItem)}</dt>
+ * <dd>The system calls this method when the action provider is created.
+ * You define the action provider's layout through the implementation of this
+ * method. Use the context acquired
+ * from the constructor to instantiate a {@link android.view.LayoutInflater} and
+ * inflate your action provider's layout from an XML resource, then hook up
+ * event listeners for the view's components. For example:
+ *
+ *<pre>
+ * public View onCreateActionView(MenuItem forItem) {
+ * // Inflate the action provider to be shown on the action bar.
+ * LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+ * View providerView =
+ * layoutInflater.inflate(R.layout.my_action_provider, null);
+ * ImageButton button =
+ * (ImageButton) providerView.findViewById(R.id.button);
+ * button.setOnClickListener(new View.OnClickListener() {
+ * @Override
+ * public void onClick(View v) {
+ * // Do something...
+ * }
+ * });
+ * return providerView;
+ * }</pre>
+ * </dd>
+ *
+ * <dt>{@link #onPerformDefaultAction onPerformDefaultAction()}</dt>
+ * <dd><p>The system calls this method when the user selects a menu item from the action
+ * overflow. The action provider should perform a default action for the
+ * menu item. The system does not call this method if the menu item opens a submenu.</p>
+ *
+ * <p>If your action provider presents a submenu through the
+ * {@link #onPrepareSubMenu onPrepareSubMenu()} callback, the submenu
+ * appears even if the action provider is in the overflow menu.
+ * Thus, the system never calls {@link #onPerformDefaultAction
+ * onPerformDefaultAction()} if there is a submenu.</p>
+ *
+ * <p class="note"> <strong>Note:</strong> An activity or a fragment that
+ * implements <code>onOptionsItemSelected()</code> can override the action
+ * provider's default behavior (unless it uses a submenu) by handling the
+ * item-selected event and returning <code>true</code>. In this case, the
+ * system does not call
+ * {@link #onPerformDefaultAction onPerformDefaultAction()}.</p></dd>
+ * </dl>
+ *
+ *
* @see android.support.v4.view.MenuItemCompat#setActionProvider(android.view.MenuItem, ActionProvider)
* @see android.support.v4.view.MenuItemCompat#getActionProvider(android.view.MenuItem)
*/
diff --git a/v4/java/android/support/v4/view/PagerAdapter.java b/v4/java/android/support/v4/view/PagerAdapter.java
index ef52404..55fb9c1 100644
--- a/v4/java/android/support/v4/view/PagerAdapter.java
+++ b/v4/java/android/support/v4/view/PagerAdapter.java
@@ -76,7 +76,8 @@
* the method {@link #getItemPosition(Object)}.</p>
*/
public abstract class PagerAdapter {
- private DataSetObservable mObservable = new DataSetObservable();
+ private final DataSetObservable mObservable = new DataSetObservable();
+ private DataSetObserver mViewPagerObserver;
public static final int POSITION_UNCHANGED = -1;
public static final int POSITION_NONE = -2;
@@ -273,6 +274,11 @@
* and associated views should update.
*/
public void notifyDataSetChanged() {
+ synchronized (this) {
+ if (mViewPagerObserver != null) {
+ mViewPagerObserver.onChanged();
+ }
+ }
mObservable.notifyChanged();
}
@@ -294,6 +300,12 @@
mObservable.unregisterObserver(observer);
}
+ void setViewPagerObserver(DataSetObserver observer) {
+ synchronized (this) {
+ mViewPagerObserver = observer;
+ }
+ }
+
/**
* This method may be called by the ViewPager to obtain a title string
* to describe the specified page. This method may return null
diff --git a/v4/java/android/support/v4/view/PagerTitleStrip.java b/v4/java/android/support/v4/view/PagerTitleStrip.java
index 72a83e6..6edbed8 100644
--- a/v4/java/android/support/v4/view/PagerTitleStrip.java
+++ b/v4/java/android/support/v4/view/PagerTitleStrip.java
@@ -423,35 +423,37 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
if (widthMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("Must measure with an exact width");
}
- int childHeight = heightSize;
- int minHeight = getMinHeight();
- int padding = 0;
- padding = getPaddingTop() + getPaddingBottom();
- childHeight -= padding;
+ final int heightPadding = getPaddingTop() + getPaddingBottom();
+ final int childHeightSpec = getChildMeasureSpec(heightMeasureSpec,
+ heightPadding, LayoutParams.WRAP_CONTENT);
- final int maxWidth = Math.max(0, (int) (widthSize * 0.8f));
- final int childWidthSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
- final int maxHeight = Math.min(0, childHeight);
- final int childHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int widthPadding = (int) (widthSize * 0.2f);
+ final int childWidthSpec = getChildMeasureSpec(widthMeasureSpec,
+ widthPadding, LayoutParams.WRAP_CONTENT);
mPrevText.measure(childWidthSpec, childHeightSpec);
mCurrText.measure(childWidthSpec, childHeightSpec);
mNextText.measure(childWidthSpec, childHeightSpec);
+ final int height;
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.EXACTLY) {
- setMeasuredDimension(widthSize, heightSize);
+ height = MeasureSpec.getSize(heightMeasureSpec);
} else {
- int textHeight = mCurrText.getMeasuredHeight();
- setMeasuredDimension(widthSize, Math.max(minHeight, textHeight + padding));
+ final int textHeight = mCurrText.getMeasuredHeight();
+ final int minHeight = getMinHeight();
+ height = Math.max(minHeight, textHeight + heightPadding);
}
+
+ final int childState = ViewCompat.getMeasuredState(mCurrText);
+ final int measuredHeight = ViewCompat.resolveSizeAndState(height, heightMeasureSpec,
+ childState << ViewCompat.MEASURED_HEIGHT_STATE_SHIFT);
+ setMeasuredDimension(widthSize, measuredHeight);
}
@Override
diff --git a/v4/java/android/support/v4/view/ViewCompat.java b/v4/java/android/support/v4/view/ViewCompat.java
index d3dce89..b88d7e5 100644
--- a/v4/java/android/support/v4/view/ViewCompat.java
+++ b/v4/java/android/support/v4/view/ViewCompat.java
@@ -27,6 +27,7 @@
import android.support.annotation.FloatRange;
import android.support.annotation.IdRes;
import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
@@ -276,6 +277,73 @@
*/
public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {
+ SCROLL_INDICATOR_TOP,
+ SCROLL_INDICATOR_BOTTOM,
+ SCROLL_INDICATOR_LEFT,
+ SCROLL_INDICATOR_RIGHT,
+ SCROLL_INDICATOR_START,
+ SCROLL_INDICATOR_END,
+ })
+ public @interface ScrollIndicators {}
+
+ /**
+ * Scroll indicator direction for the top edge of the view.
+ *
+ * @see #setScrollIndicators(int)
+ * @see #setScrollIndicators(int, int)
+ * @see #getScrollIndicators()
+ */
+ public static final int SCROLL_INDICATOR_TOP = 0x1;
+
+ /**
+ * Scroll indicator direction for the bottom edge of the view.
+ *
+ * @see #setScrollIndicators(int)
+ * @see #setScrollIndicators(int, int)
+ * @see #getScrollIndicators()
+ */
+ public static final int SCROLL_INDICATOR_BOTTOM = 0x2;
+
+ /**
+ * Scroll indicator direction for the left edge of the view.
+ *
+ * @see #setScrollIndicators(int)
+ * @see #setScrollIndicators(int, int)
+ * @see #getScrollIndicators()
+ */
+ public static final int SCROLL_INDICATOR_LEFT = 0x4;
+
+ /**
+ * Scroll indicator direction for the right edge of the view.
+ *
+ * @see #setScrollIndicators(int)
+ * @see #setScrollIndicators(int, int)
+ * @see #getScrollIndicators()
+ */
+ public static final int SCROLL_INDICATOR_RIGHT = 0x8;
+
+ /**
+ * Scroll indicator direction for the starting edge of the view.
+ *
+ * @see #setScrollIndicators(View, int)
+ * @see #setScrollIndicators(View, int, int)
+ * @see #getScrollIndicators(View)
+ */
+ public static final int SCROLL_INDICATOR_START = 0x10;
+
+ /**
+ * Scroll indicator direction for the ending edge of the view.
+ *
+ * @see #setScrollIndicators(int)
+ * @see #setScrollIndicators(int, int)
+ * @see #getScrollIndicators()
+ */
+ public static final int SCROLL_INDICATOR_END = 0x20;
+
interface ViewCompatImpl {
public boolean canScrollHorizontally(View v, int direction);
public boolean canScrollVertically(View v, int direction);
@@ -384,6 +452,10 @@
int combineMeasuredStates(int curState, int newState);
public float getZ(View view);
public boolean isAttachedToWindow(View view);
+ public boolean hasOnClickListeners(View view);
+ public void setScrollIndicators(View view, int indicators);
+ public void setScrollIndicators(View view, int indicators, int mask);
+ public int getScrollIndicators(View view);
}
static class BaseViewCompatImpl implements ViewCompatImpl {
@@ -963,6 +1035,26 @@
public boolean isAttachedToWindow(View view) {
return ViewCompatBase.isAttachedToWindow(view);
}
+
+ @Override
+ public boolean hasOnClickListeners(View view) {
+ return false;
+ }
+
+ @Override
+ public int getScrollIndicators(View view) {
+ return 0;
+ }
+
+ @Override
+ public void setScrollIndicators(View view, int indicators) {
+ // no-op
+ }
+
+ @Override
+ public void setScrollIndicators(View view, int indicators, int mask) {
+ // no-op
+ }
}
static class EclairMr1ViewCompatImpl extends BaseViewCompatImpl {
@@ -1222,7 +1314,14 @@
}
}
- static class JBViewCompatImpl extends ICSViewCompatImpl {
+ static class ICSMr1ViewCompatImpl extends ICSViewCompatImpl {
+ @Override
+ public boolean hasOnClickListeners(View view) {
+ return ViewCompatICSMr1.hasOnClickListeners(view);
+ }
+ }
+
+ static class JBViewCompatImpl extends ICSMr1ViewCompatImpl {
@Override
public boolean hasTransientState(View view) {
return ViewCompatJB.hasTransientState(view);
@@ -1529,10 +1628,29 @@
}
}
+ static class MarshmallowViewCompatImpl extends LollipopViewCompatImpl {
+ @Override
+ public void setScrollIndicators(View view, int indicators) {
+ ViewCompatMarshmallow.setScrollIndicators(view, indicators);
+ }
+
+ @Override
+ public void setScrollIndicators(View view, int indicators, int mask) {
+ ViewCompatMarshmallow.setScrollIndicators(view, indicators, mask);
+ }
+
+ @Override
+ public int getScrollIndicators(View view) {
+ return ViewCompatMarshmallow.getScrollIndicators(view);
+ }
+ }
+
static final ViewCompatImpl IMPL;
static {
final int version = android.os.Build.VERSION.SDK_INT;
- if (version >= 21) {
+ if (version >= 23) {
+ IMPL = new MarshmallowViewCompatImpl();
+ } else if (version >= 21) {
IMPL = new LollipopViewCompatImpl();
} else if (version >= 19) {
IMPL = new KitKatViewCompatImpl();
@@ -1540,6 +1658,8 @@
IMPL = new JbMr1ViewCompatImpl();
} else if (version >= 16) {
IMPL = new JBViewCompatImpl();
+ } else if (version >= 15) {
+ IMPL = new ICSMr1ViewCompatImpl();
} else if (version >= 14) {
IMPL = new ICSViewCompatImpl();
} else if (version >= 11) {
@@ -2513,7 +2633,7 @@
* @param value The y location of the pivot point.
*/
public static void setPivotY(View view, float value) {
- IMPL.setPivotX(view, value);
+ IMPL.setPivotY(view, value);
}
public static float getRotation(View view) {
@@ -3085,4 +3205,76 @@
public static boolean isAttachedToWindow(View view) {
return IMPL.isAttachedToWindow(view);
}
+
+ /**
+ * Returns whether the provided view has an attached {@link View.OnClickListener}.
+ *
+ * @return true if there is a listener, false if there is none.
+ */
+ public static boolean hasOnClickListeners(View view) {
+ return IMPL.hasOnClickListeners(view);
+ }
+
+ /**
+ * Sets the state of all scroll indicators.
+ * <p>
+ * See {@link #setScrollIndicators(View, int, int)} for usage information.
+ *
+ * @param indicators a bitmask of indicators that should be enabled, or
+ * {@code 0} to disable all indicators
+ *
+ * @see #setScrollIndicators(View, int, int)
+ * @see #getScrollIndicators(View)
+ */
+ public static void setScrollIndicators(@NonNull View view, @ScrollIndicators int indicators) {
+ IMPL.setScrollIndicators(view, indicators);
+ }
+
+ /**
+ * Sets the state of the scroll indicators specified by the mask. To change
+ * all scroll indicators at once, see {@link #setScrollIndicators(View, int)}.
+ * <p>
+ * When a scroll indicator is enabled, it will be displayed if the view
+ * can scroll in the direction of the indicator.
+ * <p>
+ * Multiple indicator types may be enabled or disabled by passing the
+ * logical OR of the desired types. If multiple types are specified, they
+ * will all be set to the same enabled state.
+ * <p>
+ * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators}
+ *
+ * @param indicators the indicator direction, or the logical OR of multiple
+ * indicator directions. One or more of:
+ * <ul>
+ * <li>{@link #SCROLL_INDICATOR_TOP}</li>
+ * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li>
+ * <li>{@link #SCROLL_INDICATOR_LEFT}</li>
+ * <li>{@link #SCROLL_INDICATOR_RIGHT}</li>
+ * <li>{@link #SCROLL_INDICATOR_START}</li>
+ * <li>{@link #SCROLL_INDICATOR_END}</li>
+ * </ul>
+ *
+ * @see #setScrollIndicators(View, int)
+ * @see #getScrollIndicators(View)
+ */
+ public static void setScrollIndicators(@NonNull View view, @ScrollIndicators int indicators,
+ @ScrollIndicators int mask) {
+ IMPL.setScrollIndicators(view, indicators, mask);
+ }
+
+ /**
+ * Returns a bitmask representing the enabled scroll indicators.
+ * <p>
+ * For example, if the top and left scroll indicators are enabled and all
+ * other indicators are disabled, the return value will be
+ * {@code ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_LEFT}.
+ * <p>
+ * To check whether the bottom scroll indicator is enabled, use the value
+ * of {@code (ViewCompat.getScrollIndicators(view) & ViewCompat.SCROLL_INDICATOR_BOTTOM) != 0}.
+ *
+ * @return a bitmask representing the enabled scroll indicators
+ */
+ public static int getScrollIndicators(@NonNull View view) {
+ return IMPL.getScrollIndicators(view);
+ }
}
diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java
index f19104a..c6f3648 100644
--- a/v4/java/android/support/v4/view/ViewPager.java
+++ b/v4/java/android/support/v4/view/ViewPager.java
@@ -144,7 +144,10 @@
private int mRestoredCurItem = -1;
private Parcelable mRestoredAdapterState = null;
private ClassLoader mRestoredClassLoader = null;
+
private Scroller mScroller;
+ private boolean mIsScrollStarted;
+
private PagerObserver mObserver;
private int mPageMargin;
@@ -388,6 +391,10 @@
@Override
protected void onDetachedFromWindow() {
removeCallbacks(mEndScrollRunnable);
+ // To be on the safe side, abort the scroller
+ if ((mScroller != null) && !mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
super.onDetachedFromWindow();
}
@@ -411,7 +418,7 @@
*/
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
- mAdapter.unregisterDataSetObserver(mObserver);
+ mAdapter.setViewPagerObserver(null);
mAdapter.startUpdate(this);
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
@@ -432,7 +439,7 @@
if (mObserver == null) {
mObserver = new PagerObserver();
}
- mAdapter.registerDataSetObserver(mObserver);
+ mAdapter.setViewPagerObserver(mObserver);
mPopulatePending = false;
final boolean wasFirstLayout = mFirstLayout;
mFirstLayout = true;
@@ -829,7 +836,21 @@
setScrollingCacheEnabled(false);
return;
}
- int sx = getScrollX();
+
+ int sx;
+ boolean wasScrolling = (mScroller != null) && !mScroller.isFinished();
+ if (wasScrolling) {
+ // We're in the middle of a previously initiated scrolling. Check to see
+ // whether that scrolling has actually started (if we always call getStartX
+ // we can get a stale value from the scroller if it hadn't yet had its first
+ // computeScrollOffset call) to decide what is the current scrolling position.
+ sx = mIsScrollStarted ? mScroller.getCurrX() : mScroller.getStartX();
+ // And abort the current scrolling.
+ mScroller.abortAnimation();
+ setScrollingCacheEnabled(false);
+ } else {
+ sx = getScrollX();
+ }
int sy = getScrollY();
int dx = x - sx;
int dy = y - sy;
@@ -849,7 +870,7 @@
final float distance = halfWidth + halfWidth *
distanceInfluenceForSnapDuration(distanceRatio);
- int duration = 0;
+ int duration;
velocity = Math.abs(velocity);
if (velocity > 0) {
duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
@@ -860,6 +881,9 @@
}
duration = Math.min(duration, MAX_SETTLE_DURATION);
+ // Reset the "scroll started" flag. It will be flipped to true in all places
+ // where we call computeScrollOffset().
+ mIsScrollStarted = false;
mScroller.startScroll(sx, sy, dx, dy, duration);
ViewCompat.postInvalidateOnAnimation(this);
}
@@ -1642,6 +1666,7 @@
@Override
public void computeScroll() {
+ mIsScrollStarted = true;
if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
int oldX = getScrollX();
int oldY = getScrollY();
@@ -1822,15 +1847,18 @@
if (needPopulate) {
// Done with scroll, no longer want to cache view drawing.
setScrollingCacheEnabled(false);
- mScroller.abortAnimation();
- int oldX = getScrollX();
- int oldY = getScrollY();
- int x = mScroller.getCurrX();
- int y = mScroller.getCurrY();
- if (oldX != x || oldY != y) {
- scrollTo(x, y);
- if (x != oldX) {
- pageScrolled(x);
+ boolean wasScrolling = !mScroller.isFinished();
+ if (wasScrolling) {
+ mScroller.abortAnimation();
+ int oldX = getScrollX();
+ int oldY = getScrollY();
+ int x = mScroller.getCurrX();
+ int y = mScroller.getCurrY();
+ if (oldX != x || oldY != y) {
+ scrollTo(x, y);
+ if (x != oldX) {
+ pageScrolled(x);
+ }
}
}
}
@@ -1878,13 +1906,7 @@
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
// Release the drag.
if (DEBUG) Log.v(TAG, "Intercept done!");
- mIsBeingDragged = false;
- mIsUnableToDrag = false;
- mActivePointerId = INVALID_POINTER;
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
+ resetTouch();
return false;
}
@@ -1970,6 +1992,7 @@
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
mIsUnableToDrag = false;
+ mIsScrollStarted = true;
mScroller.computeScrollOffset();
if (mScrollState == SCROLL_STATE_SETTLING &&
Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
@@ -2051,6 +2074,11 @@
case MotionEvent.ACTION_MOVE:
if (!mIsBeingDragged) {
final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+ if (pointerIndex == -1) {
+ // A child has consumed some touch events and put us into an inconsistent state.
+ needsInvalidate = resetTouch();
+ break;
+ }
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float xDiff = Math.abs(x - mLastMotionX);
final float y = MotionEventCompat.getY(ev, pointerIndex);
@@ -2102,17 +2130,13 @@
totalDelta);
setCurrentItemInternal(nextPage, true, true, initialVelocity);
- mActivePointerId = INVALID_POINTER;
- endDrag();
- needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
+ needsInvalidate = resetTouch();
}
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged) {
scrollToItem(mCurItem, true, 0, false);
- mActivePointerId = INVALID_POINTER;
- endDrag();
- needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
+ needsInvalidate = resetTouch();
}
break;
case MotionEventCompat.ACTION_POINTER_DOWN: {
@@ -2134,6 +2158,14 @@
return true;
}
+ private boolean resetTouch() {
+ boolean needsInvalidate;
+ mActivePointerId = INVALID_POINTER;
+ endDrag();
+ needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
+ return needsInvalidate;
+ }
+
private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
final ViewParent parent = getParent();
if (parent != null) {
diff --git a/v4/java/android/support/v4/widget/DrawerLayout.java b/v4/java/android/support/v4/widget/DrawerLayout.java
index a9560ad..549b8ea 100644
--- a/v4/java/android/support/v4/widget/DrawerLayout.java
+++ b/v4/java/android/support/v4/widget/DrawerLayout.java
@@ -59,17 +59,20 @@
/**
* DrawerLayout acts as a top-level container for window content that allows for
- * interactive "drawer" views to be pulled out from the edge of the window.
+ * interactive "drawer" views to be pulled out from one or both vertical edges of the window.
*
* <p>Drawer positioning and layout is controlled using the <code>android:layout_gravity</code>
* attribute on child views corresponding to which side of the view you want the drawer
- * to emerge from: left or right. (Or start/end on platform versions that support layout direction.)
+ * to emerge from: left or right (or start/end on platform versions that support layout direction.)
+ * Note that you can only have one drawer view for each vertical edge of the window. If your
+ * layout configures more than one drawer view per vertical edge of the window, an exception will
+ * be thrown at runtime.
* </p>
*
* <p>To use a DrawerLayout, position your primary content view as the first child with
- * a width and height of <code>match_parent</code>. Add drawers as child views after the main
- * content view and set the <code>layout_gravity</code> appropriately. Drawers commonly use
- * <code>match_parent</code> for height with a fixed width.</p>
+ * width and height of <code>match_parent</code> and no <code>layout_gravity></code>.
+ * Add drawers as child views after the main content view and set the <code>layout_gravity</code>
+ * appropriately. Drawers commonly use <code>match_parent</code> for height with a fixed width.</p>
*
* <p>{@link DrawerListener} can be used to monitor the state and motion of drawer views.
* Avoid performing expensive operations such as layout during animation as it can cause
@@ -110,7 +113,8 @@
public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
/** @hide */
- @IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN})
+ @IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN,
+ LOCK_MODE_UNDEFINED})
@Retention(RetentionPolicy.SOURCE)
private @interface LockMode {}
@@ -131,6 +135,11 @@
*/
public static final int LOCK_MODE_LOCKED_OPEN = 2;
+ /**
+ * The drawer's lock state is reset to default.
+ */
+ public static final int LOCK_MODE_UNDEFINED = 3;
+
/** @hide */
@IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
@Retention(RetentionPolicy.SOURCE)
@@ -189,8 +198,12 @@
private int mDrawerState;
private boolean mInLayout;
private boolean mFirstLayout = true;
- private int mLockModeLeft;
- private int mLockModeRight;
+
+ private @LockMode int mLockModeLeft = LOCK_MODE_UNDEFINED;
+ private @LockMode int mLockModeRight = LOCK_MODE_UNDEFINED;
+ private @LockMode int mLockModeStart = LOCK_MODE_UNDEFINED;
+ private @LockMode int mLockModeEnd = LOCK_MODE_UNDEFINED;
+
private boolean mDisallowInterceptRequested;
private boolean mChildrenCanceledTouch;
@@ -544,11 +557,22 @@
public void setDrawerLockMode(@LockMode int lockMode, @EdgeGravity int edgeGravity) {
final int absGravity = GravityCompat.getAbsoluteGravity(edgeGravity,
ViewCompat.getLayoutDirection(this));
- if (absGravity == Gravity.LEFT) {
- mLockModeLeft = lockMode;
- } else if (absGravity == Gravity.RIGHT) {
- mLockModeRight = lockMode;
+
+ switch (edgeGravity) {
+ case Gravity.LEFT:
+ mLockModeLeft = lockMode;
+ break;
+ case Gravity.RIGHT:
+ mLockModeRight = lockMode;
+ break;
+ case GravityCompat.START:
+ mLockModeStart = lockMode;
+ break;
+ case GravityCompat.END:
+ mLockModeEnd = lockMode;
+ break;
}
+
if (lockMode != LOCK_MODE_UNLOCKED) {
// Cancel interaction in progress
final ViewDragHelper helper = absGravity == Gravity.LEFT ? mLeftDragger : mRightDragger;
@@ -566,8 +590,8 @@
if (toClose != null) {
closeDrawer(toClose);
}
- break;
- // default: do nothing
+ break;
+ // default: do nothing
}
}
@@ -607,13 +631,51 @@
*/
@LockMode
public int getDrawerLockMode(@EdgeGravity int edgeGravity) {
- final int absGravity = GravityCompat.getAbsoluteGravity(
- edgeGravity, ViewCompat.getLayoutDirection(this));
- if (absGravity == Gravity.LEFT) {
- return mLockModeLeft;
- } else if (absGravity == Gravity.RIGHT) {
- return mLockModeRight;
+ int layoutDirection = ViewCompat.getLayoutDirection(this);
+
+ switch (edgeGravity) {
+ case Gravity.LEFT:
+ if (mLockModeLeft != LOCK_MODE_UNDEFINED) {
+ return mLockModeLeft;
+ }
+ int leftLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
+ mLockModeStart : mLockModeEnd;
+ if (leftLockMode != LOCK_MODE_UNDEFINED) {
+ return leftLockMode;
+ }
+ break;
+ case Gravity.RIGHT:
+ if (mLockModeRight != LOCK_MODE_UNDEFINED) {
+ return mLockModeRight;
+ }
+ int rightLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
+ mLockModeEnd : mLockModeStart;
+ if (rightLockMode != LOCK_MODE_UNDEFINED) {
+ return rightLockMode;
+ }
+ break;
+ case GravityCompat.START:
+ if (mLockModeStart != LOCK_MODE_UNDEFINED) {
+ return mLockModeStart;
+ }
+ int startLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
+ mLockModeLeft : mLockModeRight;
+ if (startLockMode != LOCK_MODE_UNDEFINED) {
+ return startLockMode;
+ }
+ break;
+ case GravityCompat.END:
+ if (mLockModeEnd != LOCK_MODE_UNDEFINED) {
+ return mLockModeEnd;
+ }
+ int endLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) ?
+ mLockModeRight : mLockModeLeft;
+ if (endLockMode != LOCK_MODE_UNDEFINED) {
+ return endLockMode;
+ }
+ break;
}
+
return LOCK_MODE_UNLOCKED;
}
@@ -626,13 +688,8 @@
*/
@LockMode
public int getDrawerLockMode(View drawerView) {
- final int absGravity = getDrawerViewAbsoluteGravity(drawerView);
- if (absGravity == Gravity.LEFT) {
- return mLockModeLeft;
- } else if (absGravity == Gravity.RIGHT) {
- return mLockModeRight;
- }
- return LOCK_MODE_UNLOCKED;
+ final int drawerGravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
+ return getDrawerLockMode(drawerGravity);
}
/**
@@ -712,8 +769,8 @@
void dispatchOnDrawerClosed(View drawerView) {
final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
- if (lp.knownOpen) {
- lp.knownOpen = false;
+ if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
+ lp.openState = 0;
if (mListener != null) {
mListener.onDrawerClosed(drawerView);
}
@@ -734,8 +791,8 @@
void dispatchOnDrawerOpened(View drawerView) {
final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
- if (!lp.knownOpen) {
- lp.knownOpen = true;
+ if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 0) {
+ lp.openState = LayoutParams.FLAG_IS_OPENED;
if (mListener != null) {
mListener.onDrawerOpened(drawerView);
}
@@ -806,7 +863,8 @@
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
- if (((LayoutParams) child.getLayoutParams()).knownOpen) {
+ final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
+ if ((childLp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
return child;
}
}
@@ -951,6 +1009,7 @@
gravityToString(childGravity) + " but this " + TAG + " already has a " +
"drawer view along that edge");
}
+ foundDrawers = foundDrawers | childGravity;
final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
mMinDrawerMargin + lp.leftMargin + lp.rightMargin,
lp.width);
@@ -1435,13 +1494,15 @@
throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
}
+ final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
if (mFirstLayout) {
- final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
lp.onScreen = 1.f;
- lp.knownOpen = true;
+ lp.openState = LayoutParams.FLAG_IS_OPENED;
updateChildrenImportantForAccessibility(drawerView, true);
} else {
+ lp.openState |= LayoutParams.FLAG_IS_OPENING;
+
if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
} else {
@@ -1477,11 +1538,13 @@
throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
}
+ final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
if (mFirstLayout) {
- final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
lp.onScreen = 0.f;
- lp.knownOpen = false;
+ lp.openState = 0;
} else {
+ lp.openState |= LayoutParams.FLAG_IS_CLOSING;
+
if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(),
drawerView.getTop());
@@ -1521,7 +1584,8 @@
if (!isDrawerView(drawer)) {
throw new IllegalArgumentException("View " + drawer + " is not a drawer");
}
- return ((LayoutParams) drawer.getLayoutParams()).knownOpen;
+ LayoutParams drawerLp = (LayoutParams) drawer.getLayoutParams();
+ return (drawerLp.openState & LayoutParams.FLAG_IS_OPENED) == 1;
}
/**
@@ -1705,8 +1769,18 @@
}
}
- setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT);
- setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT);
+ if (ss.lockModeLeft != LOCK_MODE_UNDEFINED) {
+ setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT);
+ }
+ if (ss.lockModeRight != LOCK_MODE_UNDEFINED) {
+ setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT);
+ }
+ if (ss.lockModeStart != LOCK_MODE_UNDEFINED) {
+ setDrawerLockMode(ss.lockModeStart, GravityCompat.START);
+ }
+ if (ss.lockModeEnd != LOCK_MODE_UNDEFINED) {
+ setDrawerLockMode(ss.lockModeEnd, GravityCompat.END);
+ }
}
@Override
@@ -1714,13 +1788,26 @@
final Parcelable superState = super.onSaveInstanceState();
final SavedState ss = new SavedState(superState);
- final View openDrawer = findOpenDrawer();
- if (openDrawer != null) {
- ss.openDrawerGravity = ((LayoutParams) openDrawer.getLayoutParams()).gravity;
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ // Is the current child fully opened (that is, not closing)?
+ boolean isOpenedAndNotClosing = (lp.openState == LayoutParams.FLAG_IS_OPENED);
+ // Is the current child opening?
+ boolean isClosedAndOpening = (lp.openState == LayoutParams.FLAG_IS_OPENING);
+ if (isOpenedAndNotClosing || isClosedAndOpening) {
+ // If one of the conditions above holds, save the child's gravity
+ // so that we open that child during state restore.
+ ss.openDrawerGravity = lp.gravity;
+ break;
+ }
}
ss.lockModeLeft = mLockModeLeft;
ss.lockModeRight = mLockModeRight;
+ ss.lockModeStart = mLockModeStart;
+ ss.lockModeEnd = mLockModeEnd;
return ss;
}
@@ -1766,12 +1853,18 @@
*/
protected static class SavedState extends BaseSavedState {
int openDrawerGravity = Gravity.NO_GRAVITY;
- int lockModeLeft = LOCK_MODE_UNLOCKED;
- int lockModeRight = LOCK_MODE_UNLOCKED;
+ @LockMode int lockModeLeft;
+ @LockMode int lockModeRight;
+ @LockMode int lockModeStart;
+ @LockMode int lockModeEnd;
public SavedState(Parcel in) {
super(in);
openDrawerGravity = in.readInt();
+ lockModeLeft = in.readInt();
+ lockModeRight = in.readInt();
+ lockModeStart = in.readInt();
+ lockModeEnd = in.readInt();
}
public SavedState(Parcelable superState) {
@@ -1782,6 +1875,10 @@
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(openDrawerGravity);
+ dest.writeInt(lockModeLeft);
+ dest.writeInt(lockModeRight);
+ dest.writeInt(lockModeStart);
+ dest.writeInt(lockModeEnd);
}
public static final Parcelable.Creator<SavedState> CREATOR =
@@ -1965,11 +2062,14 @@
}
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
+ private static final int FLAG_IS_OPENED = 0x1;
+ private static final int FLAG_IS_OPENING = 0x2;
+ private static final int FLAG_IS_CLOSING = 0x4;
public int gravity = Gravity.NO_GRAVITY;
- float onScreen;
- boolean isPeeking;
- boolean knownOpen;
+ private float onScreen;
+ private boolean isPeeking;
+ private int openState;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/v4/java/android/support/v4/widget/NestedScrollView.java b/v4/java/android/support/v4/widget/NestedScrollView.java
index 788761a..27e4307 100644
--- a/v4/java/android/support/v4/widget/NestedScrollView.java
+++ b/v4/java/android/support/v4/widget/NestedScrollView.java
@@ -31,6 +31,7 @@
import android.support.v4.view.NestedScrollingChildHelper;
import android.support.v4.view.NestedScrollingParent;
import android.support.v4.view.NestedScrollingParentHelper;
+import android.support.v4.view.ScrollingView;
import android.support.v4.view.VelocityTrackerCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -61,13 +62,35 @@
* Nested scrolling is enabled by default.
*/
public class NestedScrollView extends FrameLayout implements NestedScrollingParent,
- NestedScrollingChild {
+ NestedScrollingChild, ScrollingView {
static final int ANIMATED_SCROLL_GAP = 250;
static final float MAX_SCROLL_FACTOR = 0.5f;
private static final String TAG = "NestedScrollView";
+ /**
+ * Interface definition for a callback to be invoked when the scroll
+ * X or Y positions of a view change.
+ *
+ * <p>This version of the interface works on all versions of Android, back to API v4.</p>
+ *
+ * @see #setOnScrollChangeListener(OnScrollChangeListener)
+ */
+ public interface OnScrollChangeListener {
+ /**
+ * Called when the scroll position of a view changes.
+ *
+ * @param v The view whose scroll position has changed.
+ * @param scrollX Current horizontal scroll origin.
+ * @param scrollY Current vertical scroll origin.
+ * @param oldScrollX Previous horizontal scroll origin.
+ * @param oldScrollY Previous vertical scroll origin.
+ */
+ void onScrollChange(NestedScrollView v, int scrollX, int scrollY,
+ int oldScrollX, int oldScrollY);
+ }
+
private long mLastScroll;
private final Rect mTempRect = new Rect();
@@ -153,6 +176,8 @@
private float mVerticalScrollFactor;
+ private OnScrollChangeListener mOnScrollChangeListener;
+
public NestedScrollView(Context context) {
this(context, null);
}
@@ -245,6 +270,7 @@
@Override
public void onStopNestedScroll(View target) {
+ mParentHelper.onStopNestedScroll(target);
stopNestedScroll();
}
@@ -376,6 +402,19 @@
}
/**
+ * Register a callback to be invoked when the scroll X or Y positions of
+ * this view change.
+ * <p>This version of the method works on all versions of Android, back to API v4.</p>
+ *
+ * @param l The listener to notify when the scroll X or Y position changes.
+ * @see android.view.View#getScrollX()
+ * @see android.view.View#getScrollY()
+ */
+ public void setOnScrollChangeListener(OnScrollChangeListener l) {
+ mOnScrollChangeListener = l;
+ }
+
+ /**
* @return Returns true this ScrollView can be scrolled
*/
private boolean canScroll() {
@@ -430,6 +469,15 @@
}
@Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+
+ if (mOnScrollChangeListener != null) {
+ mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
+ }
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -576,13 +624,6 @@
return true;
}
- /*
- * Don't try to intercept touch if we can't scroll anyway.
- */
- if (getScrollY() == 0 && !ViewCompat.canScrollVertically(this, 1)) {
- return false;
- }
-
switch (action & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
/*
@@ -657,6 +698,9 @@
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
recycleVelocityTracker();
+ if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0, getScrollRange())) {
+ ViewCompat.postInvalidateOnAnimation(this);
+ }
stopNestedScroll();
break;
case MotionEventCompat.ACTION_POINTER_UP:
@@ -795,17 +839,23 @@
if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
flingWithNestedDispatch(-initialVelocity);
+ } else if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
+ getScrollRange())) {
+ ViewCompat.postInvalidateOnAnimation(this);
}
-
- mActivePointerId = INVALID_POINTER;
- endDrag();
}
+ mActivePointerId = INVALID_POINTER;
+ endDrag();
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged && getChildCount() > 0) {
- mActivePointerId = INVALID_POINTER;
- endDrag();
+ if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
+ getScrollRange())) {
+ ViewCompat.postInvalidateOnAnimation(this);
+ }
}
+ mActivePointerId = INVALID_POINTER;
+ endDrag();
break;
case MotionEventCompat.ACTION_POINTER_DOWN: {
final int index = MotionEventCompat.getActionIndex(ev);
@@ -942,6 +992,10 @@
clampedY = true;
}
+ if (clampedY) {
+ mScroller.springBack(newScrollX, newScrollY, 0, 0, 0, getScrollRange());
+ }
+
onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
return clampedX || clampedY;
@@ -1280,9 +1334,10 @@
/**
* <p>The scroll range of a scroll view is the overall height of all of its
* children.</p>
+ * @hide
*/
@Override
- protected int computeVerticalScrollRange() {
+ public int computeVerticalScrollRange() {
final int count = getChildCount();
final int contentHeight = getHeight() - getPaddingBottom() - getPaddingTop();
if (count == 0) {
@@ -1301,11 +1356,36 @@
return scrollRange;
}
+ /** @hide */
@Override
- protected int computeVerticalScrollOffset() {
+ public int computeVerticalScrollOffset() {
return Math.max(0, super.computeVerticalScrollOffset());
}
+ /** @hide */
+ @Override
+ public int computeVerticalScrollExtent() {
+ return super.computeVerticalScrollExtent();
+ }
+
+ /** @hide */
+ @Override
+ public int computeHorizontalScrollRange() {
+ return super.computeHorizontalScrollRange();
+ }
+
+ /** @hide */
+ @Override
+ public int computeHorizontalScrollOffset() {
+ return super.computeHorizontalScrollOffset();
+ }
+
+ /** @hide */
+ @Override
+ public int computeHorizontalScrollExtent() {
+ return super.computeHorizontalScrollExtent();
+ }
+
@Override
protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
diff --git a/v4/java/android/support/v4/widget/ScrollerCompat.java b/v4/java/android/support/v4/widget/ScrollerCompat.java
index afbf897..3115a41 100644
--- a/v4/java/android/support/v4/widget/ScrollerCompat.java
+++ b/v4/java/android/support/v4/widget/ScrollerCompat.java
@@ -54,6 +54,8 @@
boolean isOverScrolled(Object scroller);
int getFinalX(Object scroller);
int getFinalY(Object scroller);
+ boolean springBack(Object scroller, int startX, int startY, int minX, int maxX,
+ int minY, int maxY);
}
static final int CHASE_FRAME_TIME = 16; // ms per target frame
@@ -145,6 +147,12 @@
public int getFinalY(Object scroller) {
return ((Scroller) scroller).getFinalY();
}
+
+ @Override
+ public boolean springBack(Object scroller, int startX, int startY, int minX, int maxX,
+ int minY, int maxY) {
+ return false;
+ }
}
static class ScrollerCompatImplGingerbread implements ScrollerCompatImpl {
@@ -233,6 +241,13 @@
public int getFinalY(Object scroller) {
return ScrollerCompatGingerbread.getFinalY(scroller);
}
+
+ @Override
+ public boolean springBack(Object scroller, int startX, int startY, int minX, int maxX,
+ int minY, int maxY) {
+ return ScrollerCompatGingerbread.springBack(scroller, startX, startY, minX, maxX,
+ minY, maxY);
+ }
}
static class ScrollerCompatImplIcs extends ScrollerCompatImplGingerbread {
@@ -423,6 +438,22 @@
}
/**
+ * Call this when you want to 'spring back' into a valid coordinate range.
+ *
+ * @param startX Starting X coordinate
+ * @param startY Starting Y coordinate
+ * @param minX Minimum valid X value
+ * @param maxX Maximum valid X value
+ * @param minY Minimum valid Y value
+ * @param maxY Maximum valid Y value
+ * @return true if a springback was initiated, false if startX and startY were
+ * already within the valid range.
+ */
+ public boolean springBack(int startX, int startY, int minX, int maxX, int minY, int maxY) {
+ return mImpl.springBack(mScroller, startX, startY, minX, maxX, minY, maxY);
+ }
+
+ /**
* Stops the animation. Aborting the animation causes the scroller to move to the final x and y
* position.
*/
diff --git a/v4/java/android/support/v4/widget/SwipeRefreshLayout.java b/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
index d6b35ef..06db6f2 100644
--- a/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -102,6 +102,7 @@
private boolean mRefreshing = false;
private int mTouchSlop;
private float mTotalDragDistance = -1;
+
// If nested scrolling is enabled, the total amount that needed to be
// consumed by this as the nested scrolling parent is used in place of the
// overscroll determined by MOVE events in the onTouch handler
@@ -109,6 +110,8 @@
private final NestedScrollingParentHelper mNestedScrollingParentHelper;
private final NestedScrollingChildHelper mNestedScrollingChildHelper;
private final int[] mParentScrollConsumed = new int[2];
+ private final int[] mParentOffsetInWindow = new int[2];
+ private boolean mNestedScrollInProgress;
private int mMediumAnimationDuration;
private int mCurrentTargetOffsetTop;
@@ -182,22 +185,34 @@
mListener.onRefresh();
}
}
+ mCurrentTargetOffsetTop = mCircleView.getTop();
} else {
- mProgress.stop();
- mCircleView.setVisibility(View.GONE);
- setColorViewAlpha(MAX_ALPHA);
- // Return the circle to its start position
- if (mScale) {
- setAnimationProgress(0 /* animation complete and view is hidden */);
- } else {
- setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop,
- true /* requires update */);
- }
+ reset();
}
- mCurrentTargetOffsetTop = mCircleView.getTop();
}
};
+ private void reset() {
+ mCircleView.clearAnimation();
+ mProgress.stop();
+ mCircleView.setVisibility(View.GONE);
+ setColorViewAlpha(MAX_ALPHA);
+ // Return the circle to its start position
+ if (mScale) {
+ setAnimationProgress(0 /* animation complete and view is hidden */);
+ } else {
+ setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop,
+ true /* requires update */);
+ }
+ mCurrentTargetOffsetTop = mCircleView.getTop();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ reset();
+ }
+
private void setColorViewAlpha(int targetAlpha) {
mCircleView.getBackground().setAlpha(targetAlpha);
mProgress.setAlpha(targetAlpha);
@@ -654,7 +669,8 @@
mReturningToStart = false;
}
- if (!isEnabled() || mReturningToStart || canChildScrollUp() || mRefreshing) {
+ if (!isEnabled() || mReturningToStart || canChildScrollUp()
+ || mRefreshing || mNestedScrollInProgress) {
// Fail fast if we're not in a state where a swipe is possible
return false;
}
@@ -728,19 +744,18 @@
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
- if (isEnabled() && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0) {
- // Dispatch up to the nested parent
- startNestedScroll(nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL);
- return true;
- }
- return false;
+ return isEnabled() && canChildScrollUp() && !mReturningToStart && !mRefreshing
+ && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
@Override
public void onNestedScrollAccepted(View child, View target, int axes) {
// Reset the counter of how much leftover scroll needs to be consumed.
mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
+ // Dispatch up to the nested parent
+ startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
mTotalUnconsumed = 0;
+ mNestedScrollInProgress = true;
}
@Override
@@ -759,6 +774,15 @@
moveSpinner(mTotalUnconsumed);
}
+ // If a client layout is using a custom start position for the circle
+ // view, they mean to hide it again before scrolling the child view
+ // If we get back to mTotalUnconsumed == 0 and there is more to go, hide
+ // the circle so it isn't exposed if its blocking content is moved
+ if (mUsingCustomStart && dy > 0 && mTotalUnconsumed == 0
+ && Math.abs(dy - consumed[1]) > 0) {
+ mCircleView.setVisibility(View.GONE);
+ }
+
// Now let our nested parent consume the leftovers
final int[] parentConsumed = mParentScrollConsumed;
if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
@@ -775,6 +799,7 @@
@Override
public void onStopNestedScroll(View target) {
mNestedScrollingParentHelper.onStopNestedScroll(target);
+ mNestedScrollInProgress = false;
// Finish the spinner for nested scrolling if we ever consumed any
// unconsumed nested scroll
if (mTotalUnconsumed > 0) {
@@ -786,30 +811,27 @@
}
@Override
- public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
- int dyUnconsumed) {
- if (dyUnconsumed < 0) {
- dyUnconsumed = Math.abs(dyUnconsumed);
- mTotalUnconsumed += dyUnconsumed;
+ public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed,
+ final int dxUnconsumed, final int dyUnconsumed) {
+ // Dispatch up to the nested parent first
+ dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
+ mParentOffsetInWindow);
+
+ // This is a bit of a hack. Nested scrolling works from the bottom up, and as we are
+ // sometimes between two nested scrolling views, we need a way to be able to know when any
+ // nested scrolling parent has stopped handling events. We do that by using the
+ // 'offset in window 'functionality to see if we have been moved from the event.
+ // This is a decent indication of whether we should take over the event stream or not.
+ final int dy = dyUnconsumed + mParentOffsetInWindow[1];
+ if (dy < 0) {
+ mTotalUnconsumed += Math.abs(dy);
moveSpinner(mTotalUnconsumed);
}
- // Dispatch up to the nested parent
- dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dxConsumed, null);
}
// NestedScrollingChild
@Override
- public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
- return false;
- }
-
- @Override
- public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
- return false;
- }
-
- @Override
public void setNestedScrollingEnabled(boolean enabled) {
mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
}
@@ -847,6 +869,18 @@
}
@Override
+ public boolean onNestedPreFling(View target, float velocityX,
+ float velocityY) {
+ return dispatchNestedPreFling(velocityX, velocityY);
+ }
+
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY,
+ boolean consumed) {
+ return dispatchNestedFling(velocityX, velocityY, consumed);
+ }
+
+ @Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@@ -943,12 +977,13 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
+ int pointerIndex = -1;
if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
mReturningToStart = false;
}
- if (!isEnabled() || mReturningToStart || canChildScrollUp()) {
+ if (!isEnabled() || mReturningToStart || canChildScrollUp() || mNestedScrollInProgress) {
// Fail fast if we're not in a state where a swipe is possible
return false;
}
@@ -960,7 +995,7 @@
break;
case MotionEvent.ACTION_MOVE: {
- final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+ pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
if (pointerIndex < 0) {
Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
return false;
@@ -978,8 +1013,12 @@
break;
}
case MotionEventCompat.ACTION_POINTER_DOWN: {
- final int index = MotionEventCompat.getActionIndex(ev);
- mActivePointerId = MotionEventCompat.getPointerId(ev, index);
+ pointerIndex = MotionEventCompat.getActionIndex(ev);
+ if (pointerIndex < 0) {
+ Log.e(LOG_TAG, "Got ACTION_POINTER_DOWN event but have an invalid action index.");
+ return false;
+ }
+ mActivePointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
break;
}
@@ -987,15 +1026,13 @@
onSecondaryPointerUp(ev);
break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL: {
- if (mActivePointerId == INVALID_POINTER) {
- if (action == MotionEvent.ACTION_UP) {
- Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
- }
+ case MotionEvent.ACTION_UP: {
+ pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+ if (pointerIndex < 0) {
+ Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
return false;
}
- final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+
final float y = MotionEventCompat.getY(ev, pointerIndex);
final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
mIsBeingDragged = false;
@@ -1003,6 +1040,8 @@
mActivePointerId = INVALID_POINTER;
return false;
}
+ case MotionEvent.ACTION_CANCEL:
+ return false;
}
return true;
@@ -1020,18 +1059,6 @@
mCircleView.startAnimation(mAnimateToCorrectPosition);
}
- private void peek(int from, AnimationListener listener) {
- mFrom = from;
- mPeek.reset();
- mPeek.setDuration(500);
- mPeek.setInterpolator(mDecelerateInterpolator);
- if (listener != null) {
- mCircleView.setAnimationListener(listener);
- }
- mCircleView.clearAnimation();
- mCircleView.startAnimation(mPeek);
- }
-
private void animateOffsetToStartPosition(int from, AnimationListener listener) {
if (mScale) {
// Scale the item back down
@@ -1066,23 +1093,6 @@
}
};
- private final Animation mPeek = new Animation() {
- @Override
- public void applyTransformation(float interpolatedTime, Transformation t) {
- int targetTop = 0;
- int endTarget = 0;
- if (!mUsingCustomStart) {
- endTarget = (int) (mSpinnerFinalOffset - Math.abs(mOriginalOffsetTop));
- } else {
- endTarget = (int) mSpinnerFinalOffset; //mSpinnerFinalOffset;
- }
- targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
- int offset = targetTop - mCircleView.getTop();
- setTargetOffsetTopAndBottom(offset, false /* requires update */);
- mProgress.setArrowScale(1 - interpolatedTime);
- }
- };
-
private void moveToStart(float interpolatedTime) {
int targetTop = 0;
targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
diff --git a/v4/java/android/support/v4/widget/TextViewCompat.java b/v4/java/android/support/v4/widget/TextViewCompat.java
index c31196a..621ee66 100644
--- a/v4/java/android/support/v4/widget/TextViewCompat.java
+++ b/v4/java/android/support/v4/widget/TextViewCompat.java
@@ -18,6 +18,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.TextView;
@@ -29,26 +30,23 @@
public class TextViewCompat {
// Hide constructor
- private TextViewCompat() {
- }
+ private TextViewCompat() {}
interface TextViewCompatImpl {
-
- public void setCompoundDrawablesRelative(@NonNull TextView textView,
+ void setCompoundDrawablesRelative(@NonNull TextView textView,
@Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@Nullable Drawable bottom);
-
- public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
+ void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
@Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@Nullable Drawable bottom);
-
- public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
+ void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
int start, int top, int end, int bottom);
-
+ int getMaxLines(TextView textView);
+ int getMinLines(TextView textView);
+ void setTextAppearance(@NonNull TextView textView, @IdRes int resId);
}
static class BaseTextViewCompatImpl implements TextViewCompatImpl {
-
@Override
public void setCompoundDrawablesRelative(@NonNull TextView textView,
@Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@@ -69,11 +67,36 @@
textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
}
+ @Override
+ public int getMaxLines(TextView textView) {
+ return TextViewCompatDonut.getMaxLines(textView);
+ }
+
+ @Override
+ public int getMinLines(TextView textView) {
+ return TextViewCompatDonut.getMinLines(textView);
+ }
+
+ @Override
+ public void setTextAppearance(TextView textView, int resId) {
+ TextViewCompatDonut.setTextAppearance(textView, resId);
+ }
}
- static class JbMr1TextViewCompatImpl extends BaseTextViewCompatImpl {
+ static class JbTextViewCompatImpl extends BaseTextViewCompatImpl {
+ @Override
+ public int getMaxLines(TextView textView) {
+ return TextViewCompatJb.getMaxLines(textView);
+ }
@Override
+ public int getMinLines(TextView textView) {
+ return TextViewCompatJb.getMinLines(textView);
+ }
+ }
+
+ static class JbMr1TextViewCompatImpl extends JbTextViewCompatImpl {
+ @Override
public void setCompoundDrawablesRelative(@NonNull TextView textView,
@Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@Nullable Drawable bottom) {
@@ -94,11 +117,9 @@
TextViewCompatJbMr1.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
start, top, end, bottom);
}
-
}
static class JbMr2TextViewCompatImpl extends JbMr1TextViewCompatImpl {
-
@Override
public void setCompoundDrawablesRelative(@NonNull TextView textView,
@Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
@@ -123,14 +144,25 @@
}
}
+ static class Api23TextViewCompatImpl extends JbMr2TextViewCompatImpl {
+ @Override
+ public void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+ TextViewCompatApi23.setTextAppearance(textView, resId);
+ }
+ }
+
static final TextViewCompatImpl IMPL;
static {
final int version = Build.VERSION.SDK_INT;
- if (version >= 18) {
+ if (version >= 23) {
+ IMPL = new Api23TextViewCompatImpl();
+ } else if (version >= 18) {
IMPL = new JbMr2TextViewCompatImpl();
} else if (version >= 17) {
IMPL = new JbMr1TextViewCompatImpl();
+ } else if (version >= 16) {
+ IMPL = new JbTextViewCompatImpl();
} else {
IMPL = new BaseTextViewCompatImpl();
}
@@ -200,4 +232,34 @@
IMPL.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end, bottom);
}
+ /**
+ * Returns the maximum number of lines displayed in the given TextView, or -1 if the maximum
+ * height was set in pixels instead.
+ */
+ public static int getMaxLines(@NonNull TextView textView) {
+ return IMPL.getMaxLines(textView);
+ }
+
+ /**
+ * Returns the minimum number of lines displayed in the given TextView, or -1 if the minimum
+ * height was set in pixels instead.
+ */
+ public static int getMinLines(@NonNull TextView textView) {
+ return IMPL.getMinLines(textView);
+ }
+
+ /**
+ * Sets the text appearance from the specified style resource.
+ * <p>
+ * Use a framework-defined {@code TextAppearance} style like
+ * {@link android.R.style#TextAppearance_Material_Body1 @android:style/TextAppearance.Material.Body1}
+ * or see {@link android.R.styleable#TextAppearance TextAppearance} for the
+ * set of attributes that can be used in a custom style.
+ *
+ * @param textView The TextView against which to invoke the method.
+ * @param resId The resource identifier of the style to apply.
+ */
+ public static void setTextAppearance(@NonNull TextView textView, @IdRes int resId) {
+ IMPL.setTextAppearance(textView, resId);
+ }
}
diff --git a/v4/java/android/support/v4/widget/TextViewCompatDonut.java b/v4/java/android/support/v4/widget/TextViewCompatDonut.java
new file mode 100644
index 0000000..ba155fe
--- /dev/null
+++ b/v4/java/android/support/v4/widget/TextViewCompatDonut.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.widget;
+
+import android.util.Log;
+import android.widget.TextView;
+
+import java.lang.reflect.Field;
+
+class TextViewCompatDonut {
+
+ private static final String LOG_TAG = "TextViewCompatDonut";
+ private static final int LINES = 1;
+
+ private static Field sMaximumField;
+ private static boolean sMaximumFieldFetched;
+ private static Field sMaxModeField;
+ private static boolean sMaxModeFieldFetched;
+
+ private static Field sMinimumField;
+ private static boolean sMinimumFieldFetched;
+ private static Field sMinModeField;
+ private static boolean sMinModeFieldFetched;
+
+ static int getMaxLines(TextView textView) {
+ if (!sMaxModeFieldFetched) {
+ sMaxModeField = retrieveField("mMaxMode");
+ sMaxModeFieldFetched = true;
+ }
+ if (sMaxModeField != null && retrieveIntFromField(sMaxModeField, textView) == LINES) {
+ // If the max mode is using lines, we can grab the maximum value
+ if (!sMaximumFieldFetched) {
+ sMaximumField = retrieveField("mMaximum");
+ sMaximumFieldFetched = true;
+ }
+ if (sMaximumField != null) {
+ return retrieveIntFromField(sMaximumField, textView);
+ }
+ }
+ return -1;
+ }
+
+ static int getMinLines(TextView textView) {
+ if (!sMinModeFieldFetched) {
+ sMinModeField = retrieveField("mMinMode");
+ sMinModeFieldFetched = true;
+ }
+ if (sMinModeField != null && retrieveIntFromField(sMinModeField, textView) == LINES) {
+ // If the min mode is using lines, we can grab the maximum value
+ if (!sMinimumFieldFetched) {
+ sMinimumField = retrieveField("mMinimum");
+ sMinimumFieldFetched = true;
+ }
+ if (sMinimumField != null) {
+ return retrieveIntFromField(sMinimumField, textView);
+ }
+ }
+ return -1;
+ }
+
+ private static Field retrieveField(String fieldName) {
+ Field field = null;
+ try {
+ field = TextView.class.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ Log.e(LOG_TAG, "Could not retrieve " + fieldName + " field.");
+ }
+ return field;
+ }
+
+ private static int retrieveIntFromField(Field field, TextView textView) {
+ try {
+ return field.getInt(textView);
+ } catch (IllegalAccessException e) {
+ Log.d(LOG_TAG, "Could not retrieve value of " + field.getName() + " field.");
+ }
+ return -1;
+ }
+
+ static void setTextAppearance(TextView textView, int resId) {
+ textView.setTextAppearance(textView.getContext(), resId);
+ }
+}
diff --git a/v4/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java b/v4/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
index fcdf8b5..d5b675b4d 100644
--- a/v4/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
+++ b/v4/jellybean-mr1/android/support/v4/text/TextUtilsCompatJellybeanMr1.java
@@ -25,7 +25,7 @@
/**
* Jellybean MR1 - specific TextUtils API access.
*/
-public class TextUtilsCompatJellybeanMr1 {
+class TextUtilsCompatJellybeanMr1 {
@NonNull
public static String htmlEncode(@NonNull String s) {
return TextUtils.htmlEncode(s);
diff --git a/v4/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java b/v4/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
index 38b6778..be3555e 100644
--- a/v4/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
+++ b/v4/jellybean-mr2/android/support/v4/media/TransportMediatorJellybeanMR2.java
@@ -28,9 +28,7 @@
import android.view.View;
import android.view.ViewTreeObserver;
-class TransportMediatorJellybeanMR2
- implements RemoteControlClient.OnGetPlaybackPositionListener,
- RemoteControlClient.OnPlaybackPositionUpdateListener {
+class TransportMediatorJellybeanMR2 {
final Context mContext;
final AudioManager mAudioManager;
final View mTargetView;
@@ -75,7 +73,20 @@
mTransportCallback.handleAudioFocusChange(focusChange);
}
};
-
+ final RemoteControlClient.OnGetPlaybackPositionListener mGetPlaybackPositionListener
+ = new RemoteControlClient.OnGetPlaybackPositionListener() {
+ @Override
+ public long onGetPlaybackPosition() {
+ return mTransportCallback.getPlaybackPosition();
+ }
+ };
+ final RemoteControlClient.OnPlaybackPositionUpdateListener mPlaybackPositionUpdateListener
+ = new RemoteControlClient.OnPlaybackPositionUpdateListener() {
+ public void onPlaybackPositionUpdate(long newPositionMs) {
+ mTransportCallback.playbackPositionUpdate(newPositionMs);
+ }
+ };
+
PendingIntent mPendingIntent;
RemoteControlClient mRemoteControl;
boolean mFocused;
@@ -112,8 +123,8 @@
mPendingIntent = PendingIntent.getBroadcast(mContext, 0, mIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
mRemoteControl = new RemoteControlClient(mPendingIntent);
- mRemoteControl.setOnGetPlaybackPositionListener(this);
- mRemoteControl.setPlaybackPositionUpdateListener(this);
+ mRemoteControl.setOnGetPlaybackPositionListener(mGetPlaybackPositionListener);
+ mRemoteControl.setPlaybackPositionUpdateListener(mPlaybackPositionUpdateListener);
}
void gainFocus() {
@@ -145,16 +156,6 @@
}
}
- @Override
- public long onGetPlaybackPosition() {
- return mTransportCallback.getPlaybackPosition();
- }
-
- @Override
- public void onPlaybackPositionUpdate(long newPositionMs) {
- mTransportCallback.playbackPositionUpdate(newPositionMs);
- }
-
public void refreshState(boolean playing, long position, int transportControls) {
if (mRemoteControl != null) {
mRemoteControl.setPlaybackState(playing ? RemoteControlClient.PLAYSTATE_PLAYING
diff --git a/v4/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java b/v4/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java
index 1c5dca7..8ceb38c 100644
--- a/v4/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java
+++ b/v4/jellybean-mr2/android/support/v4/media/session/MediaSessionCompatApi18.java
@@ -16,28 +16,56 @@
package android.support.v4.media.session;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.media.AudioManager;
import android.media.RemoteControlClient;
+import android.util.Log;
import android.os.SystemClock;
-public class MediaSessionCompatApi18 {
+class MediaSessionCompatApi18 {
+ private static final String TAG = "MediaSessionCompatApi18";
+
/***** PlaybackState actions *****/
private static final long ACTION_SEEK_TO = 1 << 8;
+ private static boolean sIsMbrPendingIntentSupported = true;
+
public static Object createPlaybackPositionUpdateListener(
MediaSessionCompatApi14.Callback callback) {
return new OnPlaybackPositionUpdateListener<MediaSessionCompatApi14.Callback>(callback);
}
- public static void registerMediaButtonEventReceiver(Context context, PendingIntent pi) {
+ public static void registerMediaButtonEventReceiver(Context context, PendingIntent pi,
+ ComponentName cn) {
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- am.registerMediaButtonEventReceiver(pi);
+
+ // Some Android implementations are not able to register a media button event receiver
+ // using a PendingIntent but need a ComponentName instead. These will raise a
+ // NullPointerException.
+ if (sIsMbrPendingIntentSupported) {
+ try {
+ am.registerMediaButtonEventReceiver(pi);
+ } catch (NullPointerException e) {
+ Log.w(TAG, "Unable to register media button event receiver with "
+ + "PendingIntent, falling back to ComponentName.");
+ sIsMbrPendingIntentSupported = false;
+ }
+ }
+
+ if (!sIsMbrPendingIntentSupported) {
+ am.registerMediaButtonEventReceiver(cn);
+ }
}
- public static void unregisterMediaButtonEventReceiver(Context context, PendingIntent pi) {
+ public static void unregisterMediaButtonEventReceiver(Context context, PendingIntent pi,
+ ComponentName cn) {
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- am.unregisterMediaButtonEventReceiver(pi);
+ if (sIsMbrPendingIntentSupported) {
+ am.unregisterMediaButtonEventReceiver(pi);
+ } else {
+ am.unregisterMediaButtonEventReceiver(cn);
+ }
}
public static void setState(Object rccObj, int state, long position, float speed,
diff --git a/v4/jellybean/android/support/v4/widget/TextViewCompatJb.java b/v4/jellybean/android/support/v4/widget/TextViewCompatJb.java
new file mode 100644
index 0000000..1658874
--- /dev/null
+++ b/v4/jellybean/android/support/v4/widget/TextViewCompatJb.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.widget;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.TextView;
+
+class TextViewCompatJb {
+ static int getMaxLines(TextView textView) {
+ return textView.getMaxLines();
+ }
+
+ static int getMinLines(TextView textView) {
+ return textView.getMinLines();
+ }
+}
diff --git a/v4/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java b/v4/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java
index 61039d3..f3c19e2 100644
--- a/v4/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java
+++ b/v4/kitkat/android/support/v4/media/session/MediaSessionCompatApi19.java
@@ -15,14 +15,13 @@
*/
package android.support.v4.media.session;
-import android.graphics.Bitmap;
import android.media.MediaMetadataEditor;
import android.media.MediaMetadataRetriever;
import android.media.Rating;
import android.media.RemoteControlClient;
import android.os.Bundle;
-public class MediaSessionCompatApi19 {
+class MediaSessionCompatApi19 {
/***** PlaybackState actions *****/
private static final long ACTION_SET_RATING = 1 << 7;
diff --git a/v4/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java b/v4/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
index 5439972..64f1969 100644
--- a/v4/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
+++ b/v4/kitkat/android/support/v4/view/ViewPropertyAnimatorCompatKK.java
@@ -22,12 +22,16 @@
public static void setUpdateListener(final View view,
final ViewPropertyAnimatorUpdateListener listener) {
- view.animate().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- listener.onAnimationUpdate(view);
- }
- });
+ ValueAnimator.AnimatorUpdateListener wrapped = null;
+ if (listener != null) {
+ wrapped = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ listener.onAnimationUpdate(view);
+ }
+ };
+ }
+ view.animate().setUpdateListener(wrapped);
}
}
diff --git a/v4/tests/AndroidManifest.xml b/v4/tests/AndroidManifest.xml
new file mode 100644
index 0000000..556c885
--- /dev/null
+++ b/v4/tests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="android.support.v4.test">
+ <uses-sdk android:minSdkVersion="4" tools:overrideLibrary="android.support.test,
+ android.support.test.espresso, android.support.test.espresso.idling"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
+ <activity android:name="android.support.v4.widget.TestActivity"/>
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="android.support.v4.test"
+ />
+</manifest>
diff --git a/v4/tests/java/android/support/v4/graphics/ColorUtilsTest.java b/v4/tests/java/android/support/v4/graphics/ColorUtilsTest.java
index 855cdba..56cb6fb 100644
--- a/v4/tests/java/android/support/v4/graphics/ColorUtilsTest.java
+++ b/v4/tests/java/android/support/v4/graphics/ColorUtilsTest.java
@@ -17,9 +17,9 @@
package android.support.v4.graphics;
import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
import android.test.AndroidTestCase;
+import java.lang.Integer;
import java.util.ArrayList;
/**
@@ -31,21 +31,31 @@
private static final float ALLOWED_OFFSET_HUE = 360 * 0.005f;
private static final float ALLOWED_OFFSET_SATURATION = 0.005f;
private static final float ALLOWED_OFFSET_LIGHTNESS = 0.005f;
+ private static final float ALLOWED_OFFSET_MIN_ALPHA = 0.01f;
private static final int ALLOWED_OFFSET_RGB_COMPONENT = 2;
private static final ArrayList<TestEntry> sEntryList = new ArrayList<>();
static {
- sEntryList.add(new TestEntry(Color.BLACK).setHsl(0f, 0f, 0f));
- sEntryList.add(new TestEntry(Color.WHITE).setHsl(0f, 0f, 1f));
- sEntryList.add(new TestEntry(Color.BLUE).setHsl(240f, 1f, 0.5f));
- sEntryList.add(new TestEntry(Color.GREEN).setHsl(120f, 1f, 0.5f));
- sEntryList.add(new TestEntry(Color.RED).setHsl(0f, 1f, 0.5f));
- sEntryList.add(new TestEntry(Color.CYAN).setHsl(180f, 1f, 0.5f));
- sEntryList.add(new TestEntry(0x2196F3).setHsl(207f, 0.9f, 0.54f));
- sEntryList.add(new TestEntry(0xD1C4E9).setHsl(261f, 0.46f, 0.84f));
- sEntryList.add(new TestEntry(0x311B92).setHsl(251.09f, 0.687f, 0.339f));
+ sEntryList.add(new TestEntry(Color.BLACK).setHsl(0f, 0f, 0f)
+ .setWhiteMinAlpha30(0.35f).setWhiteMinAlpha45(0.46f));
+ sEntryList.add(new TestEntry(Color.WHITE).setHsl(0f, 0f, 1f)
+ .setBlackMinAlpha30(0.42f).setBlackMinAlpha45(0.54f));
+ sEntryList.add(new TestEntry(Color.BLUE).setHsl(240f, 1f, 0.5f)
+ .setWhiteMinAlpha30(0.55f).setWhiteMinAlpha45(0.71f));
+ sEntryList.add(new TestEntry(Color.GREEN).setHsl(120f, 1f, 0.5f)
+ .setBlackMinAlpha30(0.43f).setBlackMinAlpha45(0.55f));
+ sEntryList.add(new TestEntry(Color.RED).setHsl(0f, 1f, 0.5f)
+ .setWhiteMinAlpha30(0.84f).setBlackMinAlpha30(0.55f).setBlackMinAlpha45(0.78f));
+ sEntryList.add(new TestEntry(Color.CYAN).setHsl(180f, 1f, 0.5f)
+ .setBlackMinAlpha30(0.43f).setBlackMinAlpha45(0.55f));
+ sEntryList.add(new TestEntry(0xFF2196F3).setHsl(207f, 0.9f, 0.54f)
+ .setBlackMinAlpha30(0.52f).setWhiteMinAlpha30(0.97f).setBlackMinAlpha45(0.7f));
+ sEntryList.add(new TestEntry(0xFFD1C4E9).setHsl(261f, 0.46f, 0.84f)
+ .setBlackMinAlpha30(0.45f).setBlackMinAlpha45(0.58f));
+ sEntryList.add(new TestEntry(0xFF311B92).setHsl(251.09f, 0.687f, 0.339f)
+ .setWhiteMinAlpha30(0.39f).setWhiteMinAlpha45(0.54f));
}
public void testToHSL() {
@@ -72,6 +82,28 @@
}
}
+ public void testMinAlphas() {
+ for (TestEntry entry : sEntryList) {
+ testMinAlpha("Black title", entry.rgb, entry.blackMinAlpha30,
+ ColorUtils.calculateMinimumAlpha(Color.BLACK, entry.rgb, 3.0f));
+ testMinAlpha("Black body", entry.rgb, entry.blackMinAlpha45,
+ ColorUtils.calculateMinimumAlpha(Color.BLACK, entry.rgb, 4.5f));
+ testMinAlpha("White title", entry.rgb, entry.whiteMinAlpha30,
+ ColorUtils.calculateMinimumAlpha(Color.WHITE, entry.rgb, 3.0f));
+ testMinAlpha("White body", entry.rgb, entry.whiteMinAlpha45,
+ ColorUtils.calculateMinimumAlpha(Color.WHITE, entry.rgb, 4.5f));
+ }
+ }
+
+ private static void testMinAlpha(String title, int color, float expected, int actual) {
+ final String message = title + " text within error for #" + Integer.toHexString(color);
+ if (expected < 0) {
+ assertEquals(message, actual, -1);
+ } else {
+ assertClose(message, expected, actual / 255f, ALLOWED_OFFSET_MIN_ALPHA);
+ }
+ }
+
private static void assertClose(String message, float expected, float actual,
float allowedOffset) {
StringBuilder sb = new StringBuilder(message);
@@ -114,6 +146,10 @@
private static class TestEntry {
final int rgb;
final float[] hsl = new float[3];
+ float blackMinAlpha45 = -1;
+ float blackMinAlpha30 = -1;
+ float whiteMinAlpha45 = -1;
+ float whiteMinAlpha30 = -1;
TestEntry(int rgb) {
this.rgb = rgb;
@@ -125,5 +161,25 @@
hsl[2] = l;
return this;
}
+
+ TestEntry setBlackMinAlpha30(float minAlpha) {
+ blackMinAlpha30 = minAlpha;
+ return this;
+ }
+
+ TestEntry setBlackMinAlpha45(float minAlpha) {
+ blackMinAlpha45 = minAlpha;
+ return this;
+ }
+
+ TestEntry setWhiteMinAlpha30(float minAlpha) {
+ whiteMinAlpha30 = minAlpha;
+ return this;
+ }
+
+ TestEntry setWhiteMinAlpha45(float minAlpha) {
+ whiteMinAlpha45 = minAlpha;
+ return this;
+ }
}
}
\ No newline at end of file
diff --git a/v4/tests/java/android/support/v4/widget/TestActivity.java b/v4/tests/java/android/support/v4/widget/TestActivity.java
new file mode 100644
index 0000000..9ab5188
--- /dev/null
+++ b/v4/tests/java/android/support/v4/widget/TestActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+public class TestActivity extends Activity {
+ FrameLayout mContainer;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mContainer = new FrameLayout(this);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ setContentView(mContainer);
+ }
+}
diff --git a/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java b/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java
new file mode 100644
index 0000000..a7d2339
--- /dev/null
+++ b/v4/tests/java/android/support/v4/widget/TextViewCompatTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+
+package android.support.v4.widget;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.v4.widget.TextViewCompat;
+import android.util.Log;
+import android.widget.TextView;
+
+import android.support.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+public class TextViewCompatTest extends ActivityInstrumentationTestCase2<TestActivity> {
+ private boolean mDebug;
+
+ Throwable mainThreadException;
+
+ Thread mInstrumentationThread;
+
+ public TextViewCompatTest() {
+ super("android.support.v4.widget", TestActivity.class);
+ mDebug = false;
+ }
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mInstrumentationThread = Thread.currentThread();
+
+ // Note that injectInstrumentation was added in v5. Since this is v4 we have to use
+ // the misspelled (and deprecated) inject API.
+ injectInsrumentation(InstrumentationRegistry.getInstrumentation());
+ }
+
+ @After
+ @Override
+ public void tearDown() throws Exception {
+ getInstrumentation().waitForIdleSync();
+ super.tearDown();
+ }
+
+ @Test
+ public void testMaxLines() throws Throwable {
+ final TextView textView = new TextView(getActivity());
+ textView.setMaxLines(4);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().mContainer.addView(textView);
+ }
+ });
+
+ assertEquals("Max lines must match", TextViewCompat.getMaxLines(textView), 4);
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java b/v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
similarity index 60%
copy from v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
copy to v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
index 8eea38d..7366127 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
+++ b/v4/tests/java/android/support/v4/widget/test/TextViewTestActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,17 +14,11 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v4.widget.test;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-/**
- * @hide
- */
-public class TintInfo {
- public ColorStateList mTintList;
- public PorterDuff.Mode mTintMode;
- public boolean mHasTintMode;
- public boolean mHasTintList;
+import android.app.Activity;
+
+public class TextViewTestActivity extends Activity {
+
}
diff --git a/v7/appcompat/api/23.txt b/v7/appcompat/api/23.0.0.txt
similarity index 100%
rename from v7/appcompat/api/23.txt
rename to v7/appcompat/api/23.0.0.txt
diff --git a/v7/appcompat/api/23.1.0.txt b/v7/appcompat/api/23.1.0.txt
new file mode 100644
index 0000000..2df0ec0
--- /dev/null
+++ b/v7/appcompat/api/23.1.0.txt
@@ -0,0 +1,2081 @@
+package android.support.v7.app {
+
+ public abstract class ActionBar {
+ ctor public ActionBar();
+ method public abstract void addOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+ method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab);
+ method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, boolean);
+ method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, int);
+ method public abstract deprecated void addTab(android.support.v7.app.ActionBar.Tab, int, boolean);
+ method public abstract android.view.View getCustomView();
+ method public abstract int getDisplayOptions();
+ method public float getElevation();
+ method public abstract int getHeight();
+ method public int getHideOffset();
+ method public abstract deprecated int getNavigationItemCount();
+ method public abstract deprecated int getNavigationMode();
+ method public abstract deprecated int getSelectedNavigationIndex();
+ method public abstract deprecated android.support.v7.app.ActionBar.Tab getSelectedTab();
+ method public abstract java.lang.CharSequence getSubtitle();
+ method public abstract deprecated android.support.v7.app.ActionBar.Tab getTabAt(int);
+ method public abstract deprecated int getTabCount();
+ method public android.content.Context getThemedContext();
+ method public abstract java.lang.CharSequence getTitle();
+ method public abstract void hide();
+ method public boolean isHideOnContentScrollEnabled();
+ method public abstract boolean isShowing();
+ method public abstract deprecated android.support.v7.app.ActionBar.Tab newTab();
+ method public abstract deprecated void removeAllTabs();
+ method public abstract void removeOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+ method public abstract deprecated void removeTab(android.support.v7.app.ActionBar.Tab);
+ method public abstract deprecated void removeTabAt(int);
+ method public abstract deprecated void selectTab(android.support.v7.app.ActionBar.Tab);
+ method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public abstract void setCustomView(android.view.View);
+ method public abstract void setCustomView(android.view.View, android.support.v7.app.ActionBar.LayoutParams);
+ method public abstract void setCustomView(int);
+ method public abstract void setDisplayHomeAsUpEnabled(boolean);
+ method public abstract void setDisplayOptions(int);
+ method public abstract void setDisplayOptions(int, int);
+ method public abstract void setDisplayShowCustomEnabled(boolean);
+ method public abstract void setDisplayShowHomeEnabled(boolean);
+ method public abstract void setDisplayShowTitleEnabled(boolean);
+ method public abstract void setDisplayUseLogoEnabled(boolean);
+ method public void setElevation(float);
+ method public void setHideOffset(int);
+ method public void setHideOnContentScrollEnabled(boolean);
+ method public void setHomeActionContentDescription(java.lang.CharSequence);
+ method public void setHomeActionContentDescription(int);
+ method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+ method public void setHomeAsUpIndicator(int);
+ method public void setHomeButtonEnabled(boolean);
+ method public abstract void setIcon(int);
+ method public abstract void setIcon(android.graphics.drawable.Drawable);
+ method public abstract deprecated void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.support.v7.app.ActionBar.OnNavigationListener);
+ method public abstract void setLogo(int);
+ method public abstract void setLogo(android.graphics.drawable.Drawable);
+ method public abstract deprecated void setNavigationMode(int);
+ method public abstract deprecated void setSelectedNavigationItem(int);
+ method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public abstract void setSubtitle(java.lang.CharSequence);
+ method public abstract void setSubtitle(int);
+ method public abstract void setTitle(java.lang.CharSequence);
+ method public abstract void setTitle(int);
+ method public abstract void show();
+ field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
+ field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
+ field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
+ field public static final int DISPLAY_SHOW_TITLE = 8; // 0x8
+ field public static final int DISPLAY_USE_LOGO = 1; // 0x1
+ field public static final deprecated int NAVIGATION_MODE_LIST = 1; // 0x1
+ field public static final deprecated int NAVIGATION_MODE_STANDARD = 0; // 0x0
+ field public static final deprecated int NAVIGATION_MODE_TABS = 2; // 0x2
+ }
+
+ public static class ActionBar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ActionBar.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public ActionBar.LayoutParams(int, int);
+ ctor public ActionBar.LayoutParams(int, int, int);
+ ctor public ActionBar.LayoutParams(int);
+ ctor public ActionBar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+ ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
+ field public int gravity;
+ }
+
+ public static abstract interface ActionBar.OnMenuVisibilityListener {
+ method public abstract void onMenuVisibilityChanged(boolean);
+ }
+
+ public static abstract deprecated interface ActionBar.OnNavigationListener {
+ method public abstract boolean onNavigationItemSelected(int, long);
+ }
+
+ public static abstract deprecated class ActionBar.Tab {
+ ctor public ActionBar.Tab();
+ method public abstract java.lang.CharSequence getContentDescription();
+ method public abstract android.view.View getCustomView();
+ method public abstract android.graphics.drawable.Drawable getIcon();
+ method public abstract int getPosition();
+ method public abstract java.lang.Object getTag();
+ method public abstract java.lang.CharSequence getText();
+ method public abstract void select();
+ method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(int);
+ method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
+ method public abstract android.support.v7.app.ActionBar.Tab setCustomView(android.view.View);
+ method public abstract android.support.v7.app.ActionBar.Tab setCustomView(int);
+ method public abstract android.support.v7.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
+ method public abstract android.support.v7.app.ActionBar.Tab setIcon(int);
+ method public abstract android.support.v7.app.ActionBar.Tab setTabListener(android.support.v7.app.ActionBar.TabListener);
+ method public abstract android.support.v7.app.ActionBar.Tab setTag(java.lang.Object);
+ method public abstract android.support.v7.app.ActionBar.Tab setText(java.lang.CharSequence);
+ method public abstract android.support.v7.app.ActionBar.Tab setText(int);
+ field public static final int INVALID_POSITION = -1; // 0xffffffff
+ }
+
+ public static abstract deprecated interface ActionBar.TabListener {
+ method public abstract void onTabReselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+ method public abstract void onTabSelected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+ method public abstract void onTabUnselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+ }
+
+ public deprecated class ActionBarActivity extends android.support.v7.app.AppCompatActivity {
+ ctor public ActionBarActivity();
+ }
+
+ public class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+ ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int);
+ ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, android.support.v7.widget.Toolbar, int, int);
+ method public android.view.View.OnClickListener getToolbarNavigationClickListener();
+ method public boolean isDrawerIndicatorEnabled();
+ method public void onConfigurationChanged(android.content.res.Configuration);
+ method public void onDrawerClosed(android.view.View);
+ method public void onDrawerOpened(android.view.View);
+ method public void onDrawerSlide(android.view.View, float);
+ method public void onDrawerStateChanged(int);
+ method public boolean onOptionsItemSelected(android.view.MenuItem);
+ method public void setDrawerIndicatorEnabled(boolean);
+ method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+ method public void setHomeAsUpIndicator(int);
+ method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
+ method public void syncState();
+ }
+
+ public static abstract interface ActionBarDrawerToggle.Delegate {
+ method public abstract android.content.Context getActionBarThemedContext();
+ method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+ method public abstract boolean isNavigationVisible();
+ method public abstract void setActionBarDescription(int);
+ method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+ }
+
+ public static abstract interface ActionBarDrawerToggle.DelegateProvider {
+ method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+ }
+
+ public class AlertDialog extends android.support.v7.app.AppCompatDialog implements android.content.DialogInterface {
+ ctor protected AlertDialog(android.content.Context);
+ ctor protected AlertDialog(android.content.Context, int);
+ ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+ method public android.widget.Button getButton(int);
+ method public android.widget.ListView getListView();
+ method public void setButton(int, java.lang.CharSequence, android.os.Message);
+ method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public void setCustomTitle(android.view.View);
+ method public void setIcon(int);
+ method public void setIcon(android.graphics.drawable.Drawable);
+ method public void setIconAttribute(int);
+ method public void setMessage(java.lang.CharSequence);
+ method public void setView(android.view.View);
+ method public void setView(android.view.View, int, int, int, int);
+ }
+
+ public static class AlertDialog.Builder {
+ ctor public AlertDialog.Builder(android.content.Context);
+ ctor public AlertDialog.Builder(android.content.Context, int);
+ method public android.support.v7.app.AlertDialog create();
+ method public android.content.Context getContext();
+ method public android.support.v7.app.AlertDialog.Builder setAdapter(android.widget.ListAdapter, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setCancelable(boolean);
+ method public android.support.v7.app.AlertDialog.Builder setCursor(android.database.Cursor, android.content.DialogInterface.OnClickListener, java.lang.String);
+ method public android.support.v7.app.AlertDialog.Builder setCustomTitle(android.view.View);
+ method public android.support.v7.app.AlertDialog.Builder setIcon(int);
+ method public android.support.v7.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
+ method public android.support.v7.app.AlertDialog.Builder setIconAttribute(int);
+ method public android.support.v7.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+ method public android.support.v7.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setMessage(int);
+ method public android.support.v7.app.AlertDialog.Builder setMessage(java.lang.CharSequence);
+ method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(int, boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(java.lang.CharSequence[], boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setMultiChoiceItems(android.database.Cursor, java.lang.String, java.lang.String, android.content.DialogInterface.OnMultiChoiceClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setNegativeButton(int, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setNegativeButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setNeutralButton(int, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setNeutralButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setOnCancelListener(android.content.DialogInterface.OnCancelListener);
+ method public android.support.v7.app.AlertDialog.Builder setOnDismissListener(android.content.DialogInterface.OnDismissListener);
+ method public android.support.v7.app.AlertDialog.Builder setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+ method public android.support.v7.app.AlertDialog.Builder setOnKeyListener(android.content.DialogInterface.OnKeyListener);
+ method public android.support.v7.app.AlertDialog.Builder setPositiveButton(int, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setPositiveButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(int, int, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.database.Cursor, int, java.lang.String, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(java.lang.CharSequence[], int, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setSingleChoiceItems(android.widget.ListAdapter, int, android.content.DialogInterface.OnClickListener);
+ method public android.support.v7.app.AlertDialog.Builder setTitle(int);
+ method public android.support.v7.app.AlertDialog.Builder setTitle(java.lang.CharSequence);
+ method public android.support.v7.app.AlertDialog.Builder setView(int);
+ method public android.support.v7.app.AlertDialog.Builder setView(android.view.View);
+ method public android.support.v7.app.AlertDialog show();
+ }
+
+ public class AppCompatActivity extends android.support.v4.app.FragmentActivity implements android.support.v7.app.ActionBarDrawerToggle.DelegateProvider android.support.v7.app.AppCompatCallback {
+ ctor public AppCompatActivity();
+ method public android.support.v7.app.AppCompatDelegate getDelegate();
+ method public android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+ method public android.support.v7.app.ActionBar getSupportActionBar();
+ method public android.content.Intent getSupportParentActivityIntent();
+ method public void onCreateSupportNavigateUpTaskStack(android.support.v4.app.TaskStackBuilder);
+ method public final boolean onMenuItemSelected(int, android.view.MenuItem);
+ method public void onPrepareSupportNavigateUpTaskStack(android.support.v4.app.TaskStackBuilder);
+ method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+ method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+ method public deprecated void onSupportContentChanged();
+ method public boolean onSupportNavigateUp();
+ method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ method public void setSupportActionBar(android.support.v7.widget.Toolbar);
+ method public deprecated void setSupportProgress(int);
+ method public deprecated void setSupportProgressBarIndeterminate(boolean);
+ method public deprecated void setSupportProgressBarIndeterminateVisibility(boolean);
+ method public deprecated void setSupportProgressBarVisibility(boolean);
+ method public android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ method public void supportNavigateUpTo(android.content.Intent);
+ method public boolean supportRequestWindowFeature(int);
+ method public boolean supportShouldUpRecreateTask(android.content.Intent);
+ }
+
+ public abstract interface AppCompatCallback {
+ method public abstract void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+ method public abstract void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+ method public abstract android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ }
+
+ public abstract class AppCompatDelegate {
+ method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public static android.support.v7.app.AppCompatDelegate create(android.app.Activity, android.support.v7.app.AppCompatCallback);
+ method public static android.support.v7.app.AppCompatDelegate create(android.app.Dialog, android.support.v7.app.AppCompatCallback);
+ method public abstract android.view.View createView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+ method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+ method public abstract android.view.MenuInflater getMenuInflater();
+ method public abstract android.support.v7.app.ActionBar getSupportActionBar();
+ method public abstract boolean hasWindowFeature(int);
+ method public abstract void installViewFactory();
+ method public abstract void invalidateOptionsMenu();
+ method public abstract boolean isHandleNativeActionModesEnabled();
+ method public abstract void onConfigurationChanged(android.content.res.Configuration);
+ method public abstract void onCreate(android.os.Bundle);
+ method public abstract void onDestroy();
+ method public abstract void onPostCreate(android.os.Bundle);
+ method public abstract void onPostResume();
+ method public abstract void onStop();
+ method public abstract boolean requestWindowFeature(int);
+ method public abstract void setContentView(android.view.View);
+ method public abstract void setContentView(int);
+ method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public abstract void setHandleNativeActionModesEnabled(boolean);
+ method public abstract void setSupportActionBar(android.support.v7.widget.Toolbar);
+ method public abstract void setTitle(java.lang.CharSequence);
+ method public abstract android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ field public static final int FEATURE_SUPPORT_ACTION_BAR = 108; // 0x6c
+ field public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 109; // 0x6d
+ }
+
+ public class AppCompatDialog extends android.app.Dialog implements android.support.v7.app.AppCompatCallback {
+ ctor public AppCompatDialog(android.content.Context);
+ ctor public AppCompatDialog(android.content.Context, int);
+ ctor protected AppCompatDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+ method public android.support.v7.app.AppCompatDelegate getDelegate();
+ method public android.support.v7.app.ActionBar getSupportActionBar();
+ method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+ method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+ method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ method public boolean supportRequestWindowFeature(int);
+ }
+
+ public class AppCompatDialogFragment extends android.support.v4.app.DialogFragment {
+ ctor public AppCompatDialogFragment();
+ }
+
+ public class NotificationCompat extends android.support.v4.app.NotificationCompat {
+ ctor public NotificationCompat();
+ }
+
+ public static class NotificationCompat.Builder extends android.support.v4.app.NotificationCompat.Builder {
+ ctor public NotificationCompat.Builder(android.content.Context);
+ }
+
+ 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);
+ method public android.support.v7.app.NotificationCompat.MediaStyle setCancelButtonIntent(android.app.PendingIntent);
+ method public android.support.v7.app.NotificationCompat.MediaStyle setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token);
+ method public android.support.v7.app.NotificationCompat.MediaStyle setShowActionsInCompactView(int...);
+ method public android.support.v7.app.NotificationCompat.MediaStyle setShowCancelButton(boolean);
+ }
+
+}
+
+package android.support.v7.appcompat {
+
+ public final class R {
+ ctor public R();
+ }
+
+ public static final class R.anim {
+ ctor public R.anim();
+ field public static int abc_fade_in;
+ field public static int abc_fade_out;
+ field public static int abc_grow_fade_in_from_bottom;
+ field public static int abc_popup_enter;
+ field public static int abc_popup_exit;
+ field public static int abc_shrink_fade_out_from_bottom;
+ field public static int abc_slide_in_bottom;
+ field public static int abc_slide_in_top;
+ field public static int abc_slide_out_bottom;
+ field public static int abc_slide_out_top;
+ }
+
+ public static final class R.attr {
+ ctor public R.attr();
+ field public static int actionBarDivider;
+ field public static int actionBarItemBackground;
+ field public static int actionBarPopupTheme;
+ field public static int actionBarSize;
+ field public static int actionBarSplitStyle;
+ field public static int actionBarStyle;
+ field public static int actionBarTabBarStyle;
+ field public static int actionBarTabStyle;
+ field public static int actionBarTabTextStyle;
+ field public static int actionBarTheme;
+ field public static int actionBarWidgetTheme;
+ field public static int actionButtonStyle;
+ field public static int actionDropDownStyle;
+ field public static int actionLayout;
+ field public static int actionMenuTextAppearance;
+ field public static int actionMenuTextColor;
+ field public static int actionModeBackground;
+ field public static int actionModeCloseButtonStyle;
+ field public static int actionModeCloseDrawable;
+ field public static int actionModeCopyDrawable;
+ field public static int actionModeCutDrawable;
+ field public static int actionModeFindDrawable;
+ field public static int actionModePasteDrawable;
+ field public static int actionModePopupWindowStyle;
+ field public static int actionModeSelectAllDrawable;
+ field public static int actionModeShareDrawable;
+ field public static int actionModeSplitBackground;
+ field public static int actionModeStyle;
+ field public static int actionModeWebSearchDrawable;
+ field public static int actionOverflowButtonStyle;
+ field public static int actionOverflowMenuStyle;
+ field public static int actionProviderClass;
+ field public static int actionViewClass;
+ field public static int activityChooserViewStyle;
+ field public static int alertDialogButtonGroupStyle;
+ field public static int alertDialogCenterButtons;
+ field public static int alertDialogStyle;
+ field public static int alertDialogTheme;
+ field public static int allowStacking;
+ field public static int arrowHeadLength;
+ field public static int arrowShaftLength;
+ field public static int autoCompleteTextViewStyle;
+ field public static int background;
+ field public static int backgroundSplit;
+ field public static int backgroundStacked;
+ field public static int backgroundTint;
+ field public static int backgroundTintMode;
+ field public static int barLength;
+ field public static int borderlessButtonStyle;
+ field public static int buttonBarButtonStyle;
+ field public static int buttonBarNegativeButtonStyle;
+ field public static int buttonBarNeutralButtonStyle;
+ field public static int buttonBarPositiveButtonStyle;
+ field public static int buttonBarStyle;
+ field public static int buttonPanelSideLayout;
+ field public static int buttonStyle;
+ field public static int buttonStyleSmall;
+ field public static int buttonTint;
+ field public static int buttonTintMode;
+ field public static int checkboxStyle;
+ field public static int checkedTextViewStyle;
+ field public static int closeIcon;
+ field public static int closeItemLayout;
+ field public static int collapseContentDescription;
+ field public static int collapseIcon;
+ field public static int color;
+ field public static int colorAccent;
+ field public static int colorButtonNormal;
+ field public static int colorControlActivated;
+ field public static int colorControlHighlight;
+ field public static int colorControlNormal;
+ field public static int colorPrimary;
+ field public static int colorPrimaryDark;
+ field public static int colorSwitchThumbNormal;
+ field public static int commitIcon;
+ field public static int contentInsetEnd;
+ field public static int contentInsetLeft;
+ field public static int contentInsetRight;
+ field public static int contentInsetStart;
+ field public static int controlBackground;
+ field public static int customNavigationLayout;
+ field public static int defaultQueryHint;
+ field public static int dialogPreferredPadding;
+ field public static int dialogTheme;
+ field public static int displayOptions;
+ field public static int divider;
+ field public static int dividerHorizontal;
+ field public static int dividerPadding;
+ field public static int dividerVertical;
+ field public static int drawableSize;
+ field public static int drawerArrowStyle;
+ field public static int dropDownListViewStyle;
+ field public static int dropdownListPreferredItemHeight;
+ field public static int editTextBackground;
+ field public static int editTextColor;
+ field public static int editTextStyle;
+ field public static int elevation;
+ field public static int expandActivityOverflowButtonDrawable;
+ field public static int gapBetweenBars;
+ field public static int goIcon;
+ field public static int height;
+ field public static int hideOnContentScroll;
+ field public static int homeAsUpIndicator;
+ field public static int homeLayout;
+ field public static int icon;
+ field public static int iconifiedByDefault;
+ field public static int imageButtonStyle;
+ field public static int indeterminateProgressStyle;
+ field public static int initialActivityCount;
+ field public static int isLightTheme;
+ field public static int itemPadding;
+ field public static int layout;
+ field public static int listChoiceBackgroundIndicator;
+ field public static int listDividerAlertDialog;
+ field public static int listItemLayout;
+ field public static int listLayout;
+ field public static int listPopupWindowStyle;
+ field public static int listPreferredItemHeight;
+ field public static int listPreferredItemHeightLarge;
+ field public static int listPreferredItemHeightSmall;
+ field public static int listPreferredItemPaddingLeft;
+ field public static int listPreferredItemPaddingRight;
+ field public static int logo;
+ field public static int logoDescription;
+ field public static int maxButtonHeight;
+ field public static int measureWithLargestChild;
+ field public static int multiChoiceItemLayout;
+ field public static int navigationContentDescription;
+ field public static int navigationIcon;
+ field public static int navigationMode;
+ field public static int overlapAnchor;
+ field public static int paddingEnd;
+ field public static int paddingStart;
+ field public static int panelBackground;
+ field public static int panelMenuListTheme;
+ field public static int panelMenuListWidth;
+ field public static int popupMenuStyle;
+ field public static int popupTheme;
+ field public static int popupWindowStyle;
+ field public static int preserveIconSpacing;
+ field public static int progressBarPadding;
+ field public static int progressBarStyle;
+ field public static int queryBackground;
+ field public static int queryHint;
+ field public static int radioButtonStyle;
+ field public static int ratingBarStyle;
+ field public static int searchHintIcon;
+ field public static int searchIcon;
+ field public static int searchViewStyle;
+ field public static int seekBarStyle;
+ field public static int selectableItemBackground;
+ field public static int selectableItemBackgroundBorderless;
+ field public static int showAsAction;
+ field public static int showDividers;
+ field public static int showText;
+ field public static int singleChoiceItemLayout;
+ field public static int spinBars;
+ field public static int spinnerDropDownItemStyle;
+ field public static int spinnerStyle;
+ field public static int splitTrack;
+ field public static int state_above_anchor;
+ field public static int submitBackground;
+ field public static int subtitle;
+ field public static int subtitleTextAppearance;
+ field public static int subtitleTextColor;
+ field public static int subtitleTextStyle;
+ field public static int suggestionRowLayout;
+ field public static int switchMinWidth;
+ field public static int switchPadding;
+ field public static int switchStyle;
+ field public static int switchTextAppearance;
+ field public static int textAllCaps;
+ field public static int textAppearanceLargePopupMenu;
+ field public static int textAppearanceListItem;
+ field public static int textAppearanceListItemSmall;
+ field public static int textAppearanceSearchResultSubtitle;
+ field public static int textAppearanceSearchResultTitle;
+ field public static int textAppearanceSmallPopupMenu;
+ field public static int textColorAlertDialogListItem;
+ field public static int textColorSearchUrl;
+ field public static int theme;
+ field public static int thickness;
+ field public static int thumbTextPadding;
+ field public static int title;
+ field public static int titleMarginBottom;
+ field public static int titleMarginEnd;
+ field public static int titleMarginStart;
+ field public static int titleMarginTop;
+ field public static int titleMargins;
+ field public static int titleTextAppearance;
+ field public static int titleTextColor;
+ field public static int titleTextStyle;
+ field public static int toolbarNavigationButtonStyle;
+ field public static int toolbarStyle;
+ field public static int track;
+ field public static int voiceIcon;
+ field public static int windowActionBar;
+ field public static int windowActionBarOverlay;
+ field public static int windowActionModeOverlay;
+ field public static int windowFixedHeightMajor;
+ field public static int windowFixedHeightMinor;
+ field public static int windowFixedWidthMajor;
+ field public static int windowFixedWidthMinor;
+ field public static int windowMinWidthMajor;
+ field public static int windowMinWidthMinor;
+ field public static int windowNoTitle;
+ }
+
+ public static final class R.bool {
+ ctor public R.bool();
+ field public static int abc_action_bar_embed_tabs;
+ field public static int abc_action_bar_embed_tabs_pre_jb;
+ field public static int abc_action_bar_expanded_action_views_exclusive;
+ field public static int abc_allow_stacked_button_bar;
+ field public static int abc_config_actionMenuItemAllCaps;
+ field public static int abc_config_allowActionMenuItemTextWithIcon;
+ field public static int abc_config_closeDialogWhenTouchOutside;
+ field public static int abc_config_showMenuShortcutsWhenKeyboardPresent;
+ }
+
+ public static final class R.color {
+ ctor public R.color();
+ field public static int abc_background_cache_hint_selector_material_dark;
+ field public static int abc_background_cache_hint_selector_material_light;
+ field public static int abc_color_highlight_material;
+ field public static int abc_input_method_navigation_guard;
+ field public static int abc_primary_text_disable_only_material_dark;
+ field public static int abc_primary_text_disable_only_material_light;
+ field public static int abc_primary_text_material_dark;
+ field public static int abc_primary_text_material_light;
+ field public static int abc_search_url_text;
+ field public static int abc_search_url_text_normal;
+ field public static int abc_search_url_text_pressed;
+ field public static int abc_search_url_text_selected;
+ field public static int abc_secondary_text_material_dark;
+ field public static int abc_secondary_text_material_light;
+ field public static int accent_material_dark;
+ field public static int accent_material_light;
+ field public static int background_floating_material_dark;
+ field public static int background_floating_material_light;
+ field public static int background_material_dark;
+ field public static int background_material_light;
+ field public static int bright_foreground_disabled_material_dark;
+ field public static int bright_foreground_disabled_material_light;
+ field public static int bright_foreground_inverse_material_dark;
+ field public static int bright_foreground_inverse_material_light;
+ field public static int bright_foreground_material_dark;
+ field public static int bright_foreground_material_light;
+ field public static int button_material_dark;
+ field public static int button_material_light;
+ field public static int dim_foreground_disabled_material_dark;
+ field public static int dim_foreground_disabled_material_light;
+ field public static int dim_foreground_material_dark;
+ field public static int dim_foreground_material_light;
+ field public static int foreground_material_dark;
+ field public static int foreground_material_light;
+ field public static int highlighted_text_material_dark;
+ field public static int highlighted_text_material_light;
+ field public static int hint_foreground_material_dark;
+ field public static int hint_foreground_material_light;
+ field public static int material_blue_grey_800;
+ field public static int material_blue_grey_900;
+ field public static int material_blue_grey_950;
+ field public static int material_deep_teal_200;
+ field public static int material_deep_teal_500;
+ field public static int material_grey_100;
+ field public static int material_grey_300;
+ field public static int material_grey_50;
+ field public static int material_grey_600;
+ field public static int material_grey_800;
+ field public static int material_grey_850;
+ field public static int material_grey_900;
+ field public static int primary_dark_material_dark;
+ field public static int primary_dark_material_light;
+ field public static int primary_material_dark;
+ field public static int primary_material_light;
+ field public static int primary_text_default_material_dark;
+ field public static int primary_text_default_material_light;
+ field public static int primary_text_disabled_material_dark;
+ field public static int primary_text_disabled_material_light;
+ field public static int ripple_material_dark;
+ field public static int ripple_material_light;
+ field public static int secondary_text_default_material_dark;
+ field public static int secondary_text_default_material_light;
+ field public static int secondary_text_disabled_material_dark;
+ field public static int secondary_text_disabled_material_light;
+ field public static int switch_thumb_disabled_material_dark;
+ field public static int switch_thumb_disabled_material_light;
+ field public static int switch_thumb_material_dark;
+ field public static int switch_thumb_material_light;
+ field public static int switch_thumb_normal_material_dark;
+ field public static int switch_thumb_normal_material_light;
+ }
+
+ public static final class R.dimen {
+ ctor public R.dimen();
+ field public static int abc_action_bar_content_inset_material;
+ field public static int abc_action_bar_default_height_material;
+ field public static int abc_action_bar_default_padding_end_material;
+ field public static int abc_action_bar_default_padding_start_material;
+ field public static int abc_action_bar_icon_vertical_padding_material;
+ field public static int abc_action_bar_overflow_padding_end_material;
+ field public static int abc_action_bar_overflow_padding_start_material;
+ field public static int abc_action_bar_progress_bar_size;
+ field public static int abc_action_bar_stacked_max_height;
+ field public static int abc_action_bar_stacked_tab_max_width;
+ field public static int abc_action_bar_subtitle_bottom_margin_material;
+ field public static int abc_action_bar_subtitle_top_margin_material;
+ field public static int abc_action_button_min_height_material;
+ field public static int abc_action_button_min_width_material;
+ field public static int abc_action_button_min_width_overflow_material;
+ field public static int abc_alert_dialog_button_bar_height;
+ field public static int abc_button_inset_horizontal_material;
+ field public static int abc_button_inset_vertical_material;
+ field public static int abc_button_padding_horizontal_material;
+ field public static int abc_button_padding_vertical_material;
+ field public static int abc_config_prefDialogWidth;
+ field public static int abc_control_corner_material;
+ field public static int abc_control_inset_material;
+ field public static int abc_control_padding_material;
+ field public static int abc_dialog_fixed_height_major;
+ field public static int abc_dialog_fixed_height_minor;
+ field public static int abc_dialog_fixed_width_major;
+ field public static int abc_dialog_fixed_width_minor;
+ field public static int abc_dialog_list_padding_vertical_material;
+ field public static int abc_dialog_min_width_major;
+ field public static int abc_dialog_min_width_minor;
+ field public static int abc_dialog_padding_material;
+ field public static int abc_dialog_padding_top_material;
+ field public static int abc_disabled_alpha_material_dark;
+ field public static int abc_disabled_alpha_material_light;
+ field public static int abc_dropdownitem_icon_width;
+ field public static int abc_dropdownitem_text_padding_left;
+ field public static int abc_dropdownitem_text_padding_right;
+ field public static int abc_edit_text_inset_bottom_material;
+ field public static int abc_edit_text_inset_horizontal_material;
+ field public static int abc_edit_text_inset_top_material;
+ field public static int abc_floating_window_z;
+ field public static int abc_list_item_padding_horizontal_material;
+ field public static int abc_panel_menu_list_width;
+ field public static int abc_search_view_preferred_width;
+ field public static int abc_search_view_text_min_width;
+ field public static int abc_seekbar_track_background_height_material;
+ field public static int abc_seekbar_track_progress_height_material;
+ field public static int abc_select_dialog_padding_start_material;
+ field public static int abc_switch_padding;
+ field public static int abc_text_size_body_1_material;
+ field public static int abc_text_size_body_2_material;
+ field public static int abc_text_size_button_material;
+ field public static int abc_text_size_caption_material;
+ field public static int abc_text_size_display_1_material;
+ field public static int abc_text_size_display_2_material;
+ field public static int abc_text_size_display_3_material;
+ field public static int abc_text_size_display_4_material;
+ field public static int abc_text_size_headline_material;
+ field public static int abc_text_size_large_material;
+ field public static int abc_text_size_medium_material;
+ field public static int abc_text_size_menu_material;
+ field public static int abc_text_size_small_material;
+ field public static int abc_text_size_subhead_material;
+ field public static int abc_text_size_subtitle_material_toolbar;
+ field public static int abc_text_size_title_material;
+ field public static int abc_text_size_title_material_toolbar;
+ field public static int disabled_alpha_material_dark;
+ field public static int disabled_alpha_material_light;
+ field public static int highlight_alpha_material_colored;
+ field public static int highlight_alpha_material_dark;
+ field public static int highlight_alpha_material_light;
+ field public static int notification_large_icon_height;
+ field public static int notification_large_icon_width;
+ field public static int notification_subtext_size;
+ }
+
+ public static final class R.drawable {
+ ctor public R.drawable();
+ field public static int abc_ab_share_pack_mtrl_alpha;
+ field public static int abc_action_bar_item_background_material;
+ field public static int abc_btn_borderless_material;
+ field public static int abc_btn_check_material;
+ field public static int abc_btn_check_to_on_mtrl_000;
+ field public static int abc_btn_check_to_on_mtrl_015;
+ field public static int abc_btn_colored_material;
+ field public static int abc_btn_default_material;
+ field public static int abc_btn_default_mtrl_shape;
+ field public static int abc_btn_radio_material;
+ field public static int abc_btn_radio_to_on_mtrl_000;
+ field public static int abc_btn_radio_to_on_mtrl_015;
+ field public static int abc_btn_rating_star_off_mtrl_alpha;
+ field public static int abc_btn_rating_star_on_mtrl_alpha;
+ field public static int abc_btn_switch_to_on_mtrl_00001;
+ field public static int abc_btn_switch_to_on_mtrl_00012;
+ field public static int abc_cab_background_internal_bg;
+ field public static int abc_cab_background_top_material;
+ field public static int abc_cab_background_top_mtrl_alpha;
+ field public static int abc_control_background_material;
+ field public static int abc_dialog_material_background_dark;
+ field public static int abc_dialog_material_background_light;
+ field public static int abc_edit_text_material;
+ field public static int abc_ic_ab_back_mtrl_am_alpha;
+ field public static int abc_ic_clear_mtrl_alpha;
+ field public static int abc_ic_commit_search_api_mtrl_alpha;
+ field public static int abc_ic_go_search_api_mtrl_alpha;
+ field public static int abc_ic_menu_copy_mtrl_am_alpha;
+ field public static int abc_ic_menu_cut_mtrl_alpha;
+ field public static int abc_ic_menu_moreoverflow_mtrl_alpha;
+ field public static int abc_ic_menu_paste_mtrl_am_alpha;
+ field public static int abc_ic_menu_selectall_mtrl_alpha;
+ field public static int abc_ic_menu_share_mtrl_alpha;
+ field public static int abc_ic_search_api_mtrl_alpha;
+ field public static int abc_ic_voice_search_api_mtrl_alpha;
+ field public static int abc_item_background_holo_dark;
+ field public static int abc_item_background_holo_light;
+ field public static int abc_list_divider_mtrl_alpha;
+ field public static int abc_list_focused_holo;
+ field public static int abc_list_longpressed_holo;
+ field public static int abc_list_pressed_holo_dark;
+ field public static int abc_list_pressed_holo_light;
+ field public static int abc_list_selector_background_transition_holo_dark;
+ field public static int abc_list_selector_background_transition_holo_light;
+ field public static int abc_list_selector_disabled_holo_dark;
+ field public static int abc_list_selector_disabled_holo_light;
+ field public static int abc_list_selector_holo_dark;
+ field public static int abc_list_selector_holo_light;
+ field public static int abc_menu_hardkey_panel_mtrl_mult;
+ field public static int abc_popup_background_mtrl_mult;
+ field public static int abc_ratingbar_full_material;
+ field public static int abc_scrubber_control_off_mtrl_alpha;
+ field public static int abc_scrubber_control_to_pressed_mtrl_000;
+ field public static int abc_scrubber_control_to_pressed_mtrl_005;
+ field public static int abc_scrubber_primary_mtrl_alpha;
+ field public static int abc_scrubber_track_mtrl_alpha;
+ field public static int abc_seekbar_thumb_material;
+ field public static int abc_seekbar_track_material;
+ field public static int abc_spinner_mtrl_am_alpha;
+ field public static int abc_spinner_textfield_background_material;
+ field public static int abc_switch_thumb_material;
+ field public static int abc_switch_track_mtrl_alpha;
+ field public static int abc_tab_indicator_material;
+ field public static int abc_tab_indicator_mtrl_alpha;
+ field public static int abc_text_cursor_material;
+ field public static int abc_textfield_activated_mtrl_alpha;
+ field public static int abc_textfield_default_mtrl_alpha;
+ field public static int abc_textfield_search_activated_mtrl_alpha;
+ field public static int abc_textfield_search_default_mtrl_alpha;
+ field public static int abc_textfield_search_material;
+ field public static int notification_template_icon_bg;
+ }
+
+ public static final class R.id {
+ ctor public R.id();
+ field public static int action0;
+ field public static int action_bar;
+ field public static int action_bar_activity_content;
+ field public static int action_bar_container;
+ field public static int action_bar_root;
+ field public static int action_bar_spinner;
+ field public static int action_bar_subtitle;
+ field public static int action_bar_title;
+ field public static int action_context_bar;
+ field public static int action_divider;
+ field public static int action_menu_divider;
+ field public static int action_menu_presenter;
+ field public static int action_mode_bar;
+ field public static int action_mode_bar_stub;
+ field public static int action_mode_close_button;
+ field public static int activity_chooser_view_content;
+ field public static int alertTitle;
+ field public static int always;
+ field public static int beginning;
+ field public static int buttonPanel;
+ field public static int cancel_action;
+ field public static int checkbox;
+ field public static int chronometer;
+ field public static int collapseActionView;
+ field public static int contentPanel;
+ field public static int custom;
+ field public static int customPanel;
+ field public static int decor_content_parent;
+ field public static int default_activity_button;
+ field public static int disableHome;
+ field public static int edit_query;
+ field public static int end;
+ field public static int end_padder;
+ field public static int expand_activities_button;
+ field public static int expanded_menu;
+ field public static int home;
+ field public static int homeAsUp;
+ field public static int icon;
+ field public static int ifRoom;
+ field public static int image;
+ field public static int info;
+ field public static int line1;
+ field public static int line3;
+ field public static int listMode;
+ field public static int list_item;
+ field public static int media_actions;
+ field public static int middle;
+ field public static int multiply;
+ field public static int never;
+ field public static int none;
+ field public static int normal;
+ field public static int parentPanel;
+ field public static int progress_circular;
+ field public static int progress_horizontal;
+ field public static int radio;
+ field public static int screen;
+ field public static int scrollIndicatorDown;
+ field public static int scrollIndicatorUp;
+ field public static int scrollView;
+ field public static int search_badge;
+ field public static int search_bar;
+ field public static int search_button;
+ field public static int search_close_btn;
+ field public static int search_edit_frame;
+ field public static int search_go_btn;
+ field public static int search_mag_icon;
+ field public static int search_plate;
+ field public static int search_src_text;
+ field public static int search_voice_btn;
+ field public static int select_dialog_listview;
+ field public static int shortcut;
+ field public static int showCustom;
+ field public static int showHome;
+ field public static int showTitle;
+ field public static int spacer;
+ field public static int split_action_bar;
+ field public static int src_atop;
+ field public static int src_in;
+ field public static int src_over;
+ field public static int status_bar_latest_event_content;
+ field public static int submit_area;
+ field public static int tabMode;
+ field public static int text;
+ field public static int text2;
+ field public static int textSpacerNoButtons;
+ field public static int time;
+ field public static int title;
+ field public static int title_template;
+ field public static int topPanel;
+ field public static int up;
+ field public static int useLogo;
+ field public static int withText;
+ field public static int wrap_content;
+ }
+
+ public static final class R.integer {
+ ctor public R.integer();
+ field public static int abc_config_activityDefaultDur;
+ field public static int abc_config_activityShortDur;
+ field public static int abc_max_action_buttons;
+ field public static int cancel_button_image_alpha;
+ field public static int status_bar_notification_info_maxnum;
+ }
+
+ public static final class R.layout {
+ ctor public R.layout();
+ field public static int abc_action_bar_title_item;
+ field public static int abc_action_bar_up_container;
+ field public static int abc_action_bar_view_list_nav_layout;
+ field public static int abc_action_menu_item_layout;
+ field public static int abc_action_menu_layout;
+ field public static int abc_action_mode_bar;
+ field public static int abc_action_mode_close_item_material;
+ field public static int abc_activity_chooser_view;
+ field public static int abc_activity_chooser_view_list_item;
+ field public static int abc_alert_dialog_button_bar_material;
+ field public static int abc_alert_dialog_material;
+ field public static int abc_dialog_title_material;
+ field public static int abc_expanded_menu_layout;
+ field public static int abc_list_menu_item_checkbox;
+ field public static int abc_list_menu_item_icon;
+ field public static int abc_list_menu_item_layout;
+ field public static int abc_list_menu_item_radio;
+ field public static int abc_popup_menu_item_layout;
+ field public static int abc_screen_content_include;
+ field public static int abc_screen_simple;
+ field public static int abc_screen_simple_overlay_action_mode;
+ field public static int abc_screen_toolbar;
+ field public static int abc_search_dropdown_item_icons_2line;
+ field public static int abc_search_view;
+ field public static int abc_select_dialog_material;
+ field public static int notification_media_action;
+ field public static int notification_media_cancel_action;
+ field public static int notification_template_big_media;
+ field public static int notification_template_big_media_narrow;
+ field public static int notification_template_lines;
+ field public static int notification_template_media;
+ field public static int notification_template_part_chronometer;
+ field public static int notification_template_part_time;
+ field public static int select_dialog_item_material;
+ field public static int select_dialog_multichoice_material;
+ field public static int select_dialog_singlechoice_material;
+ field public static int support_simple_spinner_dropdown_item;
+ }
+
+ public static final class R.string {
+ ctor public R.string();
+ field public static int abc_action_bar_home_description;
+ field public static int abc_action_bar_home_description_format;
+ field public static int abc_action_bar_home_subtitle_description_format;
+ field public static int abc_action_bar_up_description;
+ field public static int abc_action_menu_overflow_description;
+ field public static int abc_action_mode_done;
+ field public static int abc_activity_chooser_view_see_all;
+ field public static int abc_activitychooserview_choose_application;
+ field public static int abc_capital_off;
+ field public static int abc_capital_on;
+ field public static int abc_search_hint;
+ field public static int abc_searchview_description_clear;
+ field public static int abc_searchview_description_query;
+ field public static int abc_searchview_description_search;
+ field public static int abc_searchview_description_submit;
+ field public static int abc_searchview_description_voice;
+ field public static int abc_shareactionprovider_share_with;
+ field public static int abc_shareactionprovider_share_with_application;
+ field public static int abc_toolbar_collapse_description;
+ field public static int status_bar_notification_info_overflow;
+ }
+
+ public static final class R.style {
+ ctor public R.style();
+ field public static int AlertDialog_AppCompat;
+ field public static int AlertDialog_AppCompat_Light;
+ field public static int Animation_AppCompat_Dialog;
+ field public static int Animation_AppCompat_DropDownUp;
+ field public static int Base_AlertDialog_AppCompat;
+ field public static int Base_AlertDialog_AppCompat_Light;
+ field public static int Base_Animation_AppCompat_Dialog;
+ field public static int Base_Animation_AppCompat_DropDownUp;
+ field public static int Base_DialogWindowTitleBackground_AppCompat;
+ field public static int Base_DialogWindowTitle_AppCompat;
+ field public static int Base_TextAppearance_AppCompat;
+ field public static int Base_TextAppearance_AppCompat_Body1;
+ field public static int Base_TextAppearance_AppCompat_Body2;
+ field public static int Base_TextAppearance_AppCompat_Button;
+ field public static int Base_TextAppearance_AppCompat_Caption;
+ field public static int Base_TextAppearance_AppCompat_Display1;
+ field public static int Base_TextAppearance_AppCompat_Display2;
+ field public static int Base_TextAppearance_AppCompat_Display3;
+ field public static int Base_TextAppearance_AppCompat_Display4;
+ field public static int Base_TextAppearance_AppCompat_Headline;
+ field public static int Base_TextAppearance_AppCompat_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Large;
+ field public static int Base_TextAppearance_AppCompat_Large_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Light_Widget_PopupMenu_Large;
+ field public static int Base_TextAppearance_AppCompat_Light_Widget_PopupMenu_Small;
+ field public static int Base_TextAppearance_AppCompat_Medium;
+ field public static int Base_TextAppearance_AppCompat_Medium_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Menu;
+ field public static int Base_TextAppearance_AppCompat_SearchResult;
+ field public static int Base_TextAppearance_AppCompat_SearchResult_Subtitle;
+ field public static int Base_TextAppearance_AppCompat_SearchResult_Title;
+ field public static int Base_TextAppearance_AppCompat_Small;
+ field public static int Base_TextAppearance_AppCompat_Small_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Subhead;
+ field public static int Base_TextAppearance_AppCompat_Subhead_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Title;
+ field public static int Base_TextAppearance_AppCompat_Title_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Menu;
+ field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Subtitle;
+ field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Title;
+ field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Widget_ActionMode_Subtitle;
+ field public static int Base_TextAppearance_AppCompat_Widget_ActionMode_Title;
+ field public static int Base_TextAppearance_AppCompat_Widget_Button;
+ field public static int Base_TextAppearance_AppCompat_Widget_Button_Inverse;
+ field public static int Base_TextAppearance_AppCompat_Widget_DropDownItem;
+ field public static int Base_TextAppearance_AppCompat_Widget_PopupMenu_Large;
+ field public static int Base_TextAppearance_AppCompat_Widget_PopupMenu_Small;
+ field public static int Base_TextAppearance_AppCompat_Widget_Switch;
+ field public static int Base_TextAppearance_AppCompat_Widget_TextView_SpinnerItem;
+ field public static int Base_TextAppearance_Widget_AppCompat_ExpandedMenu_Item;
+ field public static int Base_TextAppearance_Widget_AppCompat_Toolbar_Subtitle;
+ field public static int Base_TextAppearance_Widget_AppCompat_Toolbar_Title;
+ field public static int Base_ThemeOverlay_AppCompat;
+ field public static int Base_ThemeOverlay_AppCompat_ActionBar;
+ field public static int Base_ThemeOverlay_AppCompat_Dark;
+ field public static int Base_ThemeOverlay_AppCompat_Dark_ActionBar;
+ field public static int Base_ThemeOverlay_AppCompat_Light;
+ field public static int Base_Theme_AppCompat;
+ field public static int Base_Theme_AppCompat_CompactMenu;
+ field public static int Base_Theme_AppCompat_Dialog;
+ field public static int Base_Theme_AppCompat_DialogWhenLarge;
+ field public static int Base_Theme_AppCompat_Dialog_Alert;
+ field public static int Base_Theme_AppCompat_Dialog_FixedSize;
+ field public static int Base_Theme_AppCompat_Dialog_MinWidth;
+ field public static int Base_Theme_AppCompat_Light;
+ field public static int Base_Theme_AppCompat_Light_DarkActionBar;
+ field public static int Base_Theme_AppCompat_Light_Dialog;
+ field public static int Base_Theme_AppCompat_Light_DialogWhenLarge;
+ field public static int Base_Theme_AppCompat_Light_Dialog_Alert;
+ field public static int Base_Theme_AppCompat_Light_Dialog_FixedSize;
+ field public static int Base_Theme_AppCompat_Light_Dialog_MinWidth;
+ field public static int Base_V11_Theme_AppCompat_Dialog;
+ field public static int Base_V11_Theme_AppCompat_Light_Dialog;
+ field public static int Base_V12_Widget_AppCompat_AutoCompleteTextView;
+ field public static int Base_V12_Widget_AppCompat_EditText;
+ field public static int Base_V21_Theme_AppCompat;
+ field public static int Base_V21_Theme_AppCompat_Dialog;
+ field public static int Base_V21_Theme_AppCompat_Light;
+ field public static int Base_V21_Theme_AppCompat_Light_Dialog;
+ field public static int Base_V22_Theme_AppCompat;
+ field public static int Base_V22_Theme_AppCompat_Light;
+ field public static int Base_V23_Theme_AppCompat;
+ field public static int Base_V23_Theme_AppCompat_Light;
+ field public static int Base_V7_Theme_AppCompat;
+ field public static int Base_V7_Theme_AppCompat_Dialog;
+ field public static int Base_V7_Theme_AppCompat_Light;
+ field public static int Base_V7_Theme_AppCompat_Light_Dialog;
+ field public static int Base_V7_Widget_AppCompat_AutoCompleteTextView;
+ field public static int Base_V7_Widget_AppCompat_EditText;
+ field public static int Base_Widget_AppCompat_ActionBar;
+ field public static int Base_Widget_AppCompat_ActionBar_Solid;
+ field public static int Base_Widget_AppCompat_ActionBar_TabBar;
+ field public static int Base_Widget_AppCompat_ActionBar_TabText;
+ field public static int Base_Widget_AppCompat_ActionBar_TabView;
+ field public static int Base_Widget_AppCompat_ActionButton;
+ field public static int Base_Widget_AppCompat_ActionButton_CloseMode;
+ field public static int Base_Widget_AppCompat_ActionButton_Overflow;
+ field public static int Base_Widget_AppCompat_ActionMode;
+ field public static int Base_Widget_AppCompat_ActivityChooserView;
+ field public static int Base_Widget_AppCompat_AutoCompleteTextView;
+ field public static int Base_Widget_AppCompat_Button;
+ field public static int Base_Widget_AppCompat_ButtonBar;
+ field public static int Base_Widget_AppCompat_ButtonBar_AlertDialog;
+ field public static int Base_Widget_AppCompat_Button_Borderless;
+ field public static int Base_Widget_AppCompat_Button_Borderless_Colored;
+ field public static int Base_Widget_AppCompat_Button_ButtonBar_AlertDialog;
+ field public static int Base_Widget_AppCompat_Button_Colored;
+ field public static int Base_Widget_AppCompat_Button_Small;
+ field public static int Base_Widget_AppCompat_CompoundButton_CheckBox;
+ field public static int Base_Widget_AppCompat_CompoundButton_RadioButton;
+ field public static int Base_Widget_AppCompat_CompoundButton_Switch;
+ field public static int Base_Widget_AppCompat_DrawerArrowToggle;
+ field public static int Base_Widget_AppCompat_DrawerArrowToggle_Common;
+ field public static int Base_Widget_AppCompat_DropDownItem_Spinner;
+ field public static int Base_Widget_AppCompat_EditText;
+ field public static int Base_Widget_AppCompat_ImageButton;
+ field public static int Base_Widget_AppCompat_Light_ActionBar;
+ field public static int Base_Widget_AppCompat_Light_ActionBar_Solid;
+ field public static int Base_Widget_AppCompat_Light_ActionBar_TabBar;
+ field public static int Base_Widget_AppCompat_Light_ActionBar_TabText;
+ field public static int Base_Widget_AppCompat_Light_ActionBar_TabText_Inverse;
+ field public static int Base_Widget_AppCompat_Light_ActionBar_TabView;
+ field public static int Base_Widget_AppCompat_Light_PopupMenu;
+ field public static int Base_Widget_AppCompat_Light_PopupMenu_Overflow;
+ field public static int Base_Widget_AppCompat_ListPopupWindow;
+ field public static int Base_Widget_AppCompat_ListView;
+ field public static int Base_Widget_AppCompat_ListView_DropDown;
+ field public static int Base_Widget_AppCompat_ListView_Menu;
+ field public static int Base_Widget_AppCompat_PopupMenu;
+ field public static int Base_Widget_AppCompat_PopupMenu_Overflow;
+ field public static int Base_Widget_AppCompat_PopupWindow;
+ field public static int Base_Widget_AppCompat_ProgressBar;
+ field public static int Base_Widget_AppCompat_ProgressBar_Horizontal;
+ field public static int Base_Widget_AppCompat_RatingBar;
+ field public static int Base_Widget_AppCompat_SearchView;
+ field public static int Base_Widget_AppCompat_SearchView_ActionBar;
+ field public static int Base_Widget_AppCompat_SeekBar;
+ field public static int Base_Widget_AppCompat_Spinner;
+ field public static int Base_Widget_AppCompat_Spinner_Underlined;
+ field public static int Base_Widget_AppCompat_TextView_SpinnerItem;
+ field public static int Base_Widget_AppCompat_Toolbar;
+ field public static int Base_Widget_AppCompat_Toolbar_Button_Navigation;
+ field public static int Platform_AppCompat;
+ field public static int Platform_AppCompat_Light;
+ field public static int Platform_ThemeOverlay_AppCompat;
+ field public static int Platform_ThemeOverlay_AppCompat_Dark;
+ field public static int Platform_ThemeOverlay_AppCompat_Light;
+ field public static int Platform_V11_AppCompat;
+ field public static int Platform_V11_AppCompat_Light;
+ field public static int Platform_V14_AppCompat;
+ field public static int Platform_V14_AppCompat_Light;
+ field public static int Platform_Widget_AppCompat_Spinner;
+ field public static int RtlOverlay_DialogWindowTitle_AppCompat;
+ field public static int RtlOverlay_Widget_AppCompat_ActionBar_TitleItem;
+ field public static int RtlOverlay_Widget_AppCompat_DialogTitle_Icon;
+ field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem;
+ field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem_InternalGroup;
+ field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem_Text;
+ field public static int RtlOverlay_Widget_AppCompat_SearchView_MagIcon;
+ field public static int RtlOverlay_Widget_AppCompat_Search_DropDown;
+ field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Icon1;
+ field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Icon2;
+ field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Query;
+ field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Text;
+ field public static int RtlUnderlay_Widget_AppCompat_ActionButton;
+ field public static int RtlUnderlay_Widget_AppCompat_ActionButton_Overflow;
+ field public static int TextAppearance_AppCompat;
+ field public static int TextAppearance_AppCompat_Body1;
+ field public static int TextAppearance_AppCompat_Body2;
+ field public static int TextAppearance_AppCompat_Button;
+ field public static int TextAppearance_AppCompat_Caption;
+ field public static int TextAppearance_AppCompat_Display1;
+ field public static int TextAppearance_AppCompat_Display2;
+ field public static int TextAppearance_AppCompat_Display3;
+ field public static int TextAppearance_AppCompat_Display4;
+ field public static int TextAppearance_AppCompat_Headline;
+ field public static int TextAppearance_AppCompat_Inverse;
+ field public static int TextAppearance_AppCompat_Large;
+ field public static int TextAppearance_AppCompat_Large_Inverse;
+ field public static int TextAppearance_AppCompat_Light_SearchResult_Subtitle;
+ field public static int TextAppearance_AppCompat_Light_SearchResult_Title;
+ field public static int TextAppearance_AppCompat_Light_Widget_PopupMenu_Large;
+ field public static int TextAppearance_AppCompat_Light_Widget_PopupMenu_Small;
+ field public static int TextAppearance_AppCompat_Medium;
+ field public static int TextAppearance_AppCompat_Medium_Inverse;
+ field public static int TextAppearance_AppCompat_Menu;
+ field public static int TextAppearance_AppCompat_SearchResult_Subtitle;
+ field public static int TextAppearance_AppCompat_SearchResult_Title;
+ field public static int TextAppearance_AppCompat_Small;
+ field public static int TextAppearance_AppCompat_Small_Inverse;
+ field public static int TextAppearance_AppCompat_Subhead;
+ field public static int TextAppearance_AppCompat_Subhead_Inverse;
+ field public static int TextAppearance_AppCompat_Title;
+ field public static int TextAppearance_AppCompat_Title_Inverse;
+ field public static int TextAppearance_AppCompat_Widget_ActionBar_Menu;
+ field public static int TextAppearance_AppCompat_Widget_ActionBar_Subtitle;
+ field public static int TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse;
+ field public static int TextAppearance_AppCompat_Widget_ActionBar_Title;
+ field public static int TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse;
+ field public static int TextAppearance_AppCompat_Widget_ActionMode_Subtitle;
+ field public static int TextAppearance_AppCompat_Widget_ActionMode_Subtitle_Inverse;
+ field public static int TextAppearance_AppCompat_Widget_ActionMode_Title;
+ field public static int TextAppearance_AppCompat_Widget_ActionMode_Title_Inverse;
+ field public static int TextAppearance_AppCompat_Widget_Button;
+ field public static int TextAppearance_AppCompat_Widget_Button_Inverse;
+ field public static int TextAppearance_AppCompat_Widget_DropDownItem;
+ field public static int TextAppearance_AppCompat_Widget_PopupMenu_Large;
+ field public static int TextAppearance_AppCompat_Widget_PopupMenu_Small;
+ field public static int TextAppearance_AppCompat_Widget_Switch;
+ field public static int TextAppearance_AppCompat_Widget_TextView_SpinnerItem;
+ field public static int TextAppearance_StatusBar_EventContent;
+ field public static int TextAppearance_StatusBar_EventContent_Info;
+ field public static int TextAppearance_StatusBar_EventContent_Line2;
+ field public static int TextAppearance_StatusBar_EventContent_Time;
+ field public static int TextAppearance_StatusBar_EventContent_Title;
+ field public static int TextAppearance_Widget_AppCompat_ExpandedMenu_Item;
+ field public static int TextAppearance_Widget_AppCompat_Toolbar_Subtitle;
+ field public static int TextAppearance_Widget_AppCompat_Toolbar_Title;
+ field public static int ThemeOverlay_AppCompat;
+ field public static int ThemeOverlay_AppCompat_ActionBar;
+ field public static int ThemeOverlay_AppCompat_Dark;
+ field public static int ThemeOverlay_AppCompat_Dark_ActionBar;
+ field public static int ThemeOverlay_AppCompat_Light;
+ field public static int Theme_AppCompat;
+ field public static int Theme_AppCompat_CompactMenu;
+ field public static int Theme_AppCompat_Dialog;
+ field public static int Theme_AppCompat_DialogWhenLarge;
+ field public static int Theme_AppCompat_Dialog_Alert;
+ field public static int Theme_AppCompat_Dialog_MinWidth;
+ field public static int Theme_AppCompat_Light;
+ field public static int Theme_AppCompat_Light_DarkActionBar;
+ field public static int Theme_AppCompat_Light_Dialog;
+ field public static int Theme_AppCompat_Light_DialogWhenLarge;
+ field public static int Theme_AppCompat_Light_Dialog_Alert;
+ field public static int Theme_AppCompat_Light_Dialog_MinWidth;
+ field public static int Theme_AppCompat_Light_NoActionBar;
+ field public static int Theme_AppCompat_NoActionBar;
+ field public static int Widget_AppCompat_ActionBar;
+ field public static int Widget_AppCompat_ActionBar_Solid;
+ field public static int Widget_AppCompat_ActionBar_TabBar;
+ field public static int Widget_AppCompat_ActionBar_TabText;
+ field public static int Widget_AppCompat_ActionBar_TabView;
+ field public static int Widget_AppCompat_ActionButton;
+ field public static int Widget_AppCompat_ActionButton_CloseMode;
+ field public static int Widget_AppCompat_ActionButton_Overflow;
+ field public static int Widget_AppCompat_ActionMode;
+ field public static int Widget_AppCompat_ActivityChooserView;
+ field public static int Widget_AppCompat_AutoCompleteTextView;
+ field public static int Widget_AppCompat_Button;
+ field public static int Widget_AppCompat_ButtonBar;
+ field public static int Widget_AppCompat_ButtonBar_AlertDialog;
+ field public static int Widget_AppCompat_Button_Borderless;
+ field public static int Widget_AppCompat_Button_Borderless_Colored;
+ field public static int Widget_AppCompat_Button_ButtonBar_AlertDialog;
+ field public static int Widget_AppCompat_Button_Colored;
+ field public static int Widget_AppCompat_Button_Small;
+ field public static int Widget_AppCompat_CompoundButton_CheckBox;
+ field public static int Widget_AppCompat_CompoundButton_RadioButton;
+ field public static int Widget_AppCompat_CompoundButton_Switch;
+ field public static int Widget_AppCompat_DrawerArrowToggle;
+ field public static int Widget_AppCompat_DropDownItem_Spinner;
+ field public static int Widget_AppCompat_EditText;
+ field public static int Widget_AppCompat_ImageButton;
+ field public static int Widget_AppCompat_Light_ActionBar;
+ field public static int Widget_AppCompat_Light_ActionBar_Solid;
+ field public static int Widget_AppCompat_Light_ActionBar_Solid_Inverse;
+ field public static int Widget_AppCompat_Light_ActionBar_TabBar;
+ field public static int Widget_AppCompat_Light_ActionBar_TabBar_Inverse;
+ field public static int Widget_AppCompat_Light_ActionBar_TabText;
+ field public static int Widget_AppCompat_Light_ActionBar_TabText_Inverse;
+ field public static int Widget_AppCompat_Light_ActionBar_TabView;
+ field public static int Widget_AppCompat_Light_ActionBar_TabView_Inverse;
+ field public static int Widget_AppCompat_Light_ActionButton;
+ field public static int Widget_AppCompat_Light_ActionButton_CloseMode;
+ field public static int Widget_AppCompat_Light_ActionButton_Overflow;
+ field public static int Widget_AppCompat_Light_ActionMode_Inverse;
+ field public static int Widget_AppCompat_Light_ActivityChooserView;
+ field public static int Widget_AppCompat_Light_AutoCompleteTextView;
+ field public static int Widget_AppCompat_Light_DropDownItem_Spinner;
+ field public static int Widget_AppCompat_Light_ListPopupWindow;
+ field public static int Widget_AppCompat_Light_ListView_DropDown;
+ field public static int Widget_AppCompat_Light_PopupMenu;
+ field public static int Widget_AppCompat_Light_PopupMenu_Overflow;
+ field public static int Widget_AppCompat_Light_SearchView;
+ field public static int Widget_AppCompat_Light_Spinner_DropDown_ActionBar;
+ field public static int Widget_AppCompat_ListPopupWindow;
+ field public static int Widget_AppCompat_ListView;
+ field public static int Widget_AppCompat_ListView_DropDown;
+ field public static int Widget_AppCompat_ListView_Menu;
+ field public static int Widget_AppCompat_PopupMenu;
+ field public static int Widget_AppCompat_PopupMenu_Overflow;
+ field public static int Widget_AppCompat_PopupWindow;
+ field public static int Widget_AppCompat_ProgressBar;
+ field public static int Widget_AppCompat_ProgressBar_Horizontal;
+ field public static int Widget_AppCompat_RatingBar;
+ field public static int Widget_AppCompat_SearchView;
+ field public static int Widget_AppCompat_SearchView_ActionBar;
+ field public static int Widget_AppCompat_SeekBar;
+ field public static int Widget_AppCompat_Spinner;
+ field public static int Widget_AppCompat_Spinner_DropDown;
+ field public static int Widget_AppCompat_Spinner_DropDown_ActionBar;
+ field public static int Widget_AppCompat_Spinner_Underlined;
+ field public static int Widget_AppCompat_TextView_SpinnerItem;
+ field public static int Widget_AppCompat_Toolbar;
+ field public static int Widget_AppCompat_Toolbar_Button_Navigation;
+ }
+
+ public static final class R.styleable {
+ ctor public R.styleable();
+ field public static final int[] ActionBar;
+ field public static final int[] ActionBarLayout;
+ field public static int ActionBarLayout_android_layout_gravity;
+ field public static int ActionBar_background;
+ field public static int ActionBar_backgroundSplit;
+ field public static int ActionBar_backgroundStacked;
+ field public static int ActionBar_contentInsetEnd;
+ field public static int ActionBar_contentInsetLeft;
+ field public static int ActionBar_contentInsetRight;
+ field public static int ActionBar_contentInsetStart;
+ field public static int ActionBar_customNavigationLayout;
+ field public static int ActionBar_displayOptions;
+ field public static int ActionBar_divider;
+ field public static int ActionBar_elevation;
+ field public static int ActionBar_height;
+ field public static int ActionBar_hideOnContentScroll;
+ field public static int ActionBar_homeAsUpIndicator;
+ field public static int ActionBar_homeLayout;
+ field public static int ActionBar_icon;
+ field public static int ActionBar_indeterminateProgressStyle;
+ field public static int ActionBar_itemPadding;
+ field public static int ActionBar_logo;
+ field public static int ActionBar_navigationMode;
+ field public static int ActionBar_popupTheme;
+ field public static int ActionBar_progressBarPadding;
+ field public static int ActionBar_progressBarStyle;
+ field public static int ActionBar_subtitle;
+ field public static int ActionBar_subtitleTextStyle;
+ field public static int ActionBar_title;
+ field public static int ActionBar_titleTextStyle;
+ field public static final int[] ActionMenuItemView;
+ field public static int ActionMenuItemView_android_minWidth;
+ field public static final int[] ActionMenuView;
+ field public static final int[] ActionMode;
+ field public static int ActionMode_background;
+ field public static int ActionMode_backgroundSplit;
+ field public static int ActionMode_closeItemLayout;
+ field public static int ActionMode_height;
+ field public static int ActionMode_subtitleTextStyle;
+ field public static int ActionMode_titleTextStyle;
+ field public static final int[] ActivityChooserView;
+ field public static int ActivityChooserView_expandActivityOverflowButtonDrawable;
+ field public static int ActivityChooserView_initialActivityCount;
+ field public static final int[] AlertDialog;
+ field public static int AlertDialog_android_layout;
+ field public static int AlertDialog_buttonPanelSideLayout;
+ field public static int AlertDialog_listItemLayout;
+ field public static int AlertDialog_listLayout;
+ field public static int AlertDialog_multiChoiceItemLayout;
+ field public static int AlertDialog_singleChoiceItemLayout;
+ field public static final int[] AppCompatTextView;
+ field public static int AppCompatTextView_android_textAppearance;
+ field public static int AppCompatTextView_textAllCaps;
+ field public static int ButtonBarLayout_allowStacking;
+ field public static final int[] CompoundButton;
+ field public static int CompoundButton_android_button;
+ field public static int CompoundButton_buttonTint;
+ field public static int CompoundButton_buttonTintMode;
+ field public static final int[] DrawerArrowToggle;
+ field public static int DrawerArrowToggle_arrowHeadLength;
+ field public static int DrawerArrowToggle_arrowShaftLength;
+ field public static int DrawerArrowToggle_barLength;
+ field public static int DrawerArrowToggle_color;
+ field public static int DrawerArrowToggle_drawableSize;
+ field public static int DrawerArrowToggle_gapBetweenBars;
+ field public static int DrawerArrowToggle_spinBars;
+ field public static int DrawerArrowToggle_thickness;
+ field public static final int[] LinearLayoutCompat;
+ field public static final int[] LinearLayoutCompat_Layout;
+ field public static int LinearLayoutCompat_Layout_android_layout_gravity;
+ field public static int LinearLayoutCompat_Layout_android_layout_height;
+ field public static int LinearLayoutCompat_Layout_android_layout_weight;
+ field public static int LinearLayoutCompat_Layout_android_layout_width;
+ field public static int LinearLayoutCompat_android_baselineAligned;
+ field public static int LinearLayoutCompat_android_baselineAlignedChildIndex;
+ field public static int LinearLayoutCompat_android_gravity;
+ field public static int LinearLayoutCompat_android_orientation;
+ field public static int LinearLayoutCompat_android_weightSum;
+ field public static int LinearLayoutCompat_divider;
+ field public static int LinearLayoutCompat_dividerPadding;
+ field public static int LinearLayoutCompat_measureWithLargestChild;
+ field public static int LinearLayoutCompat_showDividers;
+ field public static final int[] ListPopupWindow;
+ field public static int ListPopupWindow_android_dropDownHorizontalOffset;
+ field public static int ListPopupWindow_android_dropDownVerticalOffset;
+ field public static final int[] MenuGroup;
+ field public static int MenuGroup_android_checkableBehavior;
+ field public static int MenuGroup_android_enabled;
+ field public static int MenuGroup_android_id;
+ field public static int MenuGroup_android_menuCategory;
+ field public static int MenuGroup_android_orderInCategory;
+ field public static int MenuGroup_android_visible;
+ field public static final int[] MenuItem;
+ field public static int MenuItem_actionLayout;
+ field public static int MenuItem_actionProviderClass;
+ field public static int MenuItem_actionViewClass;
+ field public static int MenuItem_android_alphabeticShortcut;
+ field public static int MenuItem_android_checkable;
+ field public static int MenuItem_android_checked;
+ field public static int MenuItem_android_enabled;
+ field public static int MenuItem_android_icon;
+ field public static int MenuItem_android_id;
+ field public static int MenuItem_android_menuCategory;
+ field public static int MenuItem_android_numericShortcut;
+ field public static int MenuItem_android_onClick;
+ field public static int MenuItem_android_orderInCategory;
+ field public static int MenuItem_android_title;
+ field public static int MenuItem_android_titleCondensed;
+ field public static int MenuItem_android_visible;
+ field public static int MenuItem_showAsAction;
+ field public static final int[] MenuView;
+ field public static int MenuView_android_headerBackground;
+ field public static int MenuView_android_horizontalDivider;
+ field public static int MenuView_android_itemBackground;
+ field public static int MenuView_android_itemIconDisabledAlpha;
+ field public static int MenuView_android_itemTextAppearance;
+ field public static int MenuView_android_verticalDivider;
+ field public static int MenuView_android_windowAnimationStyle;
+ field public static int MenuView_preserveIconSpacing;
+ field public static final int[] PopupWindow;
+ field public static final int[] PopupWindowBackgroundState;
+ field public static int PopupWindowBackgroundState_state_above_anchor;
+ field public static int PopupWindow_android_popupBackground;
+ field public static int PopupWindow_overlapAnchor;
+ field public static final int[] SearchView;
+ field public static int SearchView_android_focusable;
+ field public static int SearchView_android_imeOptions;
+ field public static int SearchView_android_inputType;
+ field public static int SearchView_android_maxWidth;
+ field public static int SearchView_closeIcon;
+ field public static int SearchView_commitIcon;
+ field public static int SearchView_defaultQueryHint;
+ field public static int SearchView_goIcon;
+ field public static int SearchView_iconifiedByDefault;
+ field public static int SearchView_layout;
+ field public static int SearchView_queryBackground;
+ field public static int SearchView_queryHint;
+ field public static int SearchView_searchHintIcon;
+ field public static int SearchView_searchIcon;
+ field public static int SearchView_submitBackground;
+ field public static int SearchView_suggestionRowLayout;
+ field public static int SearchView_voiceIcon;
+ field public static final int[] Spinner;
+ field public static int Spinner_android_dropDownWidth;
+ field public static int Spinner_android_popupBackground;
+ field public static int Spinner_android_prompt;
+ field public static int Spinner_popupTheme;
+ field public static final int[] SwitchCompat;
+ field public static int SwitchCompat_android_textOff;
+ field public static int SwitchCompat_android_textOn;
+ field public static int SwitchCompat_android_thumb;
+ field public static int SwitchCompat_showText;
+ field public static int SwitchCompat_splitTrack;
+ field public static int SwitchCompat_switchMinWidth;
+ field public static int SwitchCompat_switchPadding;
+ field public static int SwitchCompat_switchTextAppearance;
+ field public static int SwitchCompat_thumbTextPadding;
+ field public static int SwitchCompat_track;
+ field public static final int[] TextAppearance;
+ field public static int TextAppearance_android_shadowColor;
+ field public static int TextAppearance_android_shadowDx;
+ field public static int TextAppearance_android_shadowDy;
+ field public static int TextAppearance_android_shadowRadius;
+ field public static int TextAppearance_android_textColor;
+ field public static int TextAppearance_android_textSize;
+ field public static int TextAppearance_android_textStyle;
+ field public static int TextAppearance_android_typeface;
+ field public static int TextAppearance_textAllCaps;
+ field public static final int[] Theme;
+ field public static int Theme_actionBarDivider;
+ field public static int Theme_actionBarItemBackground;
+ field public static int Theme_actionBarPopupTheme;
+ field public static int Theme_actionBarSize;
+ field public static int Theme_actionBarSplitStyle;
+ field public static int Theme_actionBarStyle;
+ field public static int Theme_actionBarTabBarStyle;
+ field public static int Theme_actionBarTabStyle;
+ field public static int Theme_actionBarTabTextStyle;
+ field public static int Theme_actionBarTheme;
+ field public static int Theme_actionBarWidgetTheme;
+ field public static int Theme_actionButtonStyle;
+ field public static int Theme_actionDropDownStyle;
+ field public static int Theme_actionMenuTextAppearance;
+ field public static int Theme_actionMenuTextColor;
+ field public static int Theme_actionModeBackground;
+ field public static int Theme_actionModeCloseButtonStyle;
+ field public static int Theme_actionModeCloseDrawable;
+ field public static int Theme_actionModeCopyDrawable;
+ field public static int Theme_actionModeCutDrawable;
+ field public static int Theme_actionModeFindDrawable;
+ field public static int Theme_actionModePasteDrawable;
+ field public static int Theme_actionModePopupWindowStyle;
+ field public static int Theme_actionModeSelectAllDrawable;
+ field public static int Theme_actionModeShareDrawable;
+ field public static int Theme_actionModeSplitBackground;
+ field public static int Theme_actionModeStyle;
+ field public static int Theme_actionModeWebSearchDrawable;
+ field public static int Theme_actionOverflowButtonStyle;
+ field public static int Theme_actionOverflowMenuStyle;
+ field public static int Theme_activityChooserViewStyle;
+ field public static int Theme_alertDialogButtonGroupStyle;
+ field public static int Theme_alertDialogCenterButtons;
+ field public static int Theme_alertDialogStyle;
+ field public static int Theme_alertDialogTheme;
+ field public static int Theme_android_windowAnimationStyle;
+ field public static int Theme_android_windowIsFloating;
+ field public static int Theme_autoCompleteTextViewStyle;
+ field public static int Theme_borderlessButtonStyle;
+ field public static int Theme_buttonBarButtonStyle;
+ field public static int Theme_buttonBarNegativeButtonStyle;
+ field public static int Theme_buttonBarNeutralButtonStyle;
+ field public static int Theme_buttonBarPositiveButtonStyle;
+ field public static int Theme_buttonBarStyle;
+ field public static int Theme_buttonStyle;
+ field public static int Theme_buttonStyleSmall;
+ field public static int Theme_checkboxStyle;
+ field public static int Theme_checkedTextViewStyle;
+ field public static int Theme_colorAccent;
+ field public static int Theme_colorButtonNormal;
+ field public static int Theme_colorControlActivated;
+ field public static int Theme_colorControlHighlight;
+ field public static int Theme_colorControlNormal;
+ field public static int Theme_colorPrimary;
+ field public static int Theme_colorPrimaryDark;
+ field public static int Theme_colorSwitchThumbNormal;
+ field public static int Theme_controlBackground;
+ field public static int Theme_dialogPreferredPadding;
+ field public static int Theme_dialogTheme;
+ field public static int Theme_dividerHorizontal;
+ field public static int Theme_dividerVertical;
+ field public static int Theme_dropDownListViewStyle;
+ field public static int Theme_dropdownListPreferredItemHeight;
+ field public static int Theme_editTextBackground;
+ field public static int Theme_editTextColor;
+ field public static int Theme_editTextStyle;
+ field public static int Theme_homeAsUpIndicator;
+ field public static int Theme_imageButtonStyle;
+ field public static int Theme_listChoiceBackgroundIndicator;
+ field public static int Theme_listDividerAlertDialog;
+ field public static int Theme_listPopupWindowStyle;
+ field public static int Theme_listPreferredItemHeight;
+ field public static int Theme_listPreferredItemHeightLarge;
+ field public static int Theme_listPreferredItemHeightSmall;
+ field public static int Theme_listPreferredItemPaddingLeft;
+ field public static int Theme_listPreferredItemPaddingRight;
+ field public static int Theme_panelBackground;
+ field public static int Theme_panelMenuListTheme;
+ field public static int Theme_panelMenuListWidth;
+ field public static int Theme_popupMenuStyle;
+ field public static int Theme_popupWindowStyle;
+ field public static int Theme_radioButtonStyle;
+ field public static int Theme_ratingBarStyle;
+ field public static int Theme_searchViewStyle;
+ field public static int Theme_seekBarStyle;
+ field public static int Theme_selectableItemBackground;
+ field public static int Theme_selectableItemBackgroundBorderless;
+ field public static int Theme_spinnerDropDownItemStyle;
+ field public static int Theme_spinnerStyle;
+ field public static int Theme_switchStyle;
+ field public static int Theme_textAppearanceLargePopupMenu;
+ field public static int Theme_textAppearanceListItem;
+ field public static int Theme_textAppearanceListItemSmall;
+ field public static int Theme_textAppearanceSearchResultSubtitle;
+ field public static int Theme_textAppearanceSearchResultTitle;
+ field public static int Theme_textAppearanceSmallPopupMenu;
+ field public static int Theme_textColorAlertDialogListItem;
+ field public static int Theme_textColorSearchUrl;
+ field public static int Theme_toolbarNavigationButtonStyle;
+ field public static int Theme_toolbarStyle;
+ field public static int Theme_windowActionBar;
+ field public static int Theme_windowActionBarOverlay;
+ field public static int Theme_windowActionModeOverlay;
+ field public static int Theme_windowFixedHeightMajor;
+ field public static int Theme_windowFixedHeightMinor;
+ field public static int Theme_windowFixedWidthMajor;
+ field public static int Theme_windowFixedWidthMinor;
+ field public static int Theme_windowMinWidthMajor;
+ field public static int Theme_windowMinWidthMinor;
+ field public static int Theme_windowNoTitle;
+ field public static final int[] Toolbar;
+ field public static int Toolbar_android_gravity;
+ field public static int Toolbar_android_minHeight;
+ field public static int Toolbar_collapseContentDescription;
+ field public static int Toolbar_collapseIcon;
+ field public static int Toolbar_contentInsetEnd;
+ field public static int Toolbar_contentInsetLeft;
+ field public static int Toolbar_contentInsetRight;
+ field public static int Toolbar_contentInsetStart;
+ field public static int Toolbar_logo;
+ field public static int Toolbar_logoDescription;
+ field public static int Toolbar_maxButtonHeight;
+ field public static int Toolbar_navigationContentDescription;
+ field public static int Toolbar_navigationIcon;
+ field public static int Toolbar_popupTheme;
+ field public static int Toolbar_subtitle;
+ field public static int Toolbar_subtitleTextAppearance;
+ field public static int Toolbar_subtitleTextColor;
+ field public static int Toolbar_title;
+ field public static int Toolbar_titleMarginBottom;
+ field public static int Toolbar_titleMarginEnd;
+ field public static int Toolbar_titleMarginStart;
+ field public static int Toolbar_titleMarginTop;
+ field public static int Toolbar_titleMargins;
+ field public static int Toolbar_titleTextAppearance;
+ field public static int Toolbar_titleTextColor;
+ field public static final int[] View;
+ field public static final int[] ViewBackgroundHelper;
+ field public static int ViewBackgroundHelper_android_background;
+ field public static int ViewBackgroundHelper_backgroundTint;
+ field public static int ViewBackgroundHelper_backgroundTintMode;
+ field public static final int[] ViewStubCompat;
+ field public static int ViewStubCompat_android_id;
+ field public static int ViewStubCompat_android_inflatedId;
+ field public static int ViewStubCompat_android_layout;
+ field public static int View_android_focusable;
+ field public static int View_android_theme;
+ field public static int View_paddingEnd;
+ field public static int View_paddingStart;
+ field public static int View_theme;
+ }
+
+}
+
+package android.support.v7.graphics.drawable {
+
+ public class DrawerArrowDrawable extends android.graphics.drawable.Drawable {
+ ctor public DrawerArrowDrawable(android.content.Context);
+ method public void draw(android.graphics.Canvas);
+ method public float getArrowHeadLength();
+ method public float getArrowShaftLength();
+ method public float getBarLength();
+ method public float getBarThickness();
+ method public int getColor();
+ method public int getDirection();
+ method public float getGapSize();
+ method public int getOpacity();
+ method public final android.graphics.Paint getPaint();
+ method public float getProgress();
+ method public boolean isSpinEnabled();
+ method public void setAlpha(int);
+ method public void setArrowHeadLength(float);
+ method public void setArrowShaftLength(float);
+ method public void setBarLength(float);
+ method public void setBarThickness(float);
+ method public void setColor(int);
+ method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setDirection(int);
+ method public void setGapSize(float);
+ method public void setProgress(float);
+ method public void setSpinEnabled(boolean);
+ method public void setVerticalMirror(boolean);
+ field public static final int ARROW_DIRECTION_END = 3; // 0x3
+ field public static final int ARROW_DIRECTION_LEFT = 0; // 0x0
+ field public static final int ARROW_DIRECTION_RIGHT = 1; // 0x1
+ field public static final int ARROW_DIRECTION_START = 2; // 0x2
+ }
+
+}
+
+package android.support.v7.view {
+
+ public abstract class ActionMode {
+ ctor public ActionMode();
+ method public abstract void finish();
+ method public abstract android.view.View getCustomView();
+ method public abstract android.view.Menu getMenu();
+ method public abstract android.view.MenuInflater getMenuInflater();
+ method public abstract java.lang.CharSequence getSubtitle();
+ method public java.lang.Object getTag();
+ method public abstract java.lang.CharSequence getTitle();
+ method public boolean getTitleOptionalHint();
+ method public abstract void invalidate();
+ method public boolean isTitleOptional();
+ method public abstract void setCustomView(android.view.View);
+ method public abstract void setSubtitle(java.lang.CharSequence);
+ method public abstract void setSubtitle(int);
+ method public void setTag(java.lang.Object);
+ method public abstract void setTitle(java.lang.CharSequence);
+ method public abstract void setTitle(int);
+ method public void setTitleOptionalHint(boolean);
+ }
+
+ public static abstract interface ActionMode.Callback {
+ method public abstract boolean onActionItemClicked(android.support.v7.view.ActionMode, android.view.MenuItem);
+ method public abstract boolean onCreateActionMode(android.support.v7.view.ActionMode, android.view.Menu);
+ method public abstract void onDestroyActionMode(android.support.v7.view.ActionMode);
+ method public abstract boolean onPrepareActionMode(android.support.v7.view.ActionMode, android.view.Menu);
+ }
+
+ public abstract interface CollapsibleActionView {
+ method public abstract void onActionViewCollapsed();
+ method public abstract void onActionViewExpanded();
+ }
+
+}
+
+package android.support.v7.widget {
+
+ public class ActionMenuView extends android.support.v7.widget.LinearLayoutCompat {
+ ctor public ActionMenuView(android.content.Context);
+ ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
+ method public void dismissPopupMenus();
+ method public android.view.Menu getMenu();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
+ method public int getPopupTheme();
+ method public boolean hideOverflowMenu();
+ method public boolean isOverflowMenuShowing();
+ method public void onConfigurationChanged(android.content.res.Configuration);
+ method public void onDetachedFromWindow();
+ method public void setOnMenuItemClickListener(android.support.v7.widget.ActionMenuView.OnMenuItemClickListener);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
+ method public void setPopupTheme(int);
+ method public boolean showOverflowMenu();
+ }
+
+ public static class ActionMenuView.LayoutParams extends android.support.v7.widget.LinearLayoutCompat.LayoutParams {
+ ctor public ActionMenuView.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public ActionMenuView.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public ActionMenuView.LayoutParams(android.support.v7.widget.ActionMenuView.LayoutParams);
+ ctor public ActionMenuView.LayoutParams(int, int);
+ field public int cellsUsed;
+ field public boolean expandable;
+ field public int extraPixels;
+ field public boolean isOverflowButton;
+ field public boolean preventEdgeOffset;
+ }
+
+ public static abstract interface ActionMenuView.OnMenuItemClickListener {
+ method public abstract boolean onMenuItemClick(android.view.MenuItem);
+ }
+
+ public class AppCompatAutoCompleteTextView extends android.widget.AutoCompleteTextView {
+ ctor public AppCompatAutoCompleteTextView(android.content.Context);
+ ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatButton extends android.widget.Button {
+ ctor public AppCompatButton(android.content.Context);
+ ctor public AppCompatButton(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatButton(android.content.Context, android.util.AttributeSet, int);
+ method public void setSupportAllCaps(boolean);
+ }
+
+ public class AppCompatCheckBox extends android.widget.CheckBox {
+ ctor public AppCompatCheckBox(android.content.Context);
+ ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
+ ctor public AppCompatCheckedTextView(android.content.Context);
+ ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatEditText extends android.widget.EditText {
+ ctor public AppCompatEditText(android.content.Context);
+ ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatImageButton extends android.widget.ImageButton {
+ ctor public AppCompatImageButton(android.content.Context);
+ ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatImageView extends android.widget.ImageView {
+ ctor public AppCompatImageView(android.content.Context);
+ ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView {
+ ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
+ ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatRadioButton extends android.widget.RadioButton {
+ ctor public AppCompatRadioButton(android.content.Context);
+ ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatRatingBar extends android.widget.RatingBar {
+ ctor public AppCompatRatingBar(android.content.Context);
+ ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatSeekBar extends android.widget.SeekBar {
+ ctor public AppCompatSeekBar(android.content.Context);
+ ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatSpinner extends android.widget.Spinner {
+ ctor public AppCompatSpinner(android.content.Context);
+ ctor public AppCompatSpinner(android.content.Context, int);
+ ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int);
+ ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int, android.content.res.Resources.Theme);
+ }
+
+ public class AppCompatTextView extends android.widget.TextView {
+ ctor public AppCompatTextView(android.content.Context);
+ ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class LinearLayoutCompat extends android.view.ViewGroup {
+ ctor public LinearLayoutCompat(android.content.Context);
+ ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet);
+ ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet, int);
+ method public int getBaselineAlignedChildIndex();
+ method public android.graphics.drawable.Drawable getDividerDrawable();
+ method public int getDividerPadding();
+ method public int getOrientation();
+ method public int getShowDividers();
+ method public float getWeightSum();
+ method public boolean isBaselineAligned();
+ method public boolean isMeasureWithLargestChildEnabled();
+ method protected void onLayout(boolean, int, int, int, int);
+ method public void setBaselineAligned(boolean);
+ method public void setBaselineAlignedChildIndex(int);
+ method public void setDividerDrawable(android.graphics.drawable.Drawable);
+ method public void setDividerPadding(int);
+ method public void setGravity(int);
+ method public void setHorizontalGravity(int);
+ method public void setMeasureWithLargestChildEnabled(boolean);
+ method public void setOrientation(int);
+ method public void setShowDividers(int);
+ method public void setVerticalGravity(int);
+ method public void setWeightSum(float);
+ field public static final int HORIZONTAL = 0; // 0x0
+ field public static final int SHOW_DIVIDER_BEGINNING = 1; // 0x1
+ field public static final int SHOW_DIVIDER_END = 4; // 0x4
+ field public static final int SHOW_DIVIDER_MIDDLE = 2; // 0x2
+ field public static final int SHOW_DIVIDER_NONE = 0; // 0x0
+ field public static final int VERTICAL = 1; // 0x1
+ }
+
+ public static class LinearLayoutCompat.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public LinearLayoutCompat.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public LinearLayoutCompat.LayoutParams(int, int);
+ ctor public LinearLayoutCompat.LayoutParams(int, int, float);
+ ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public LinearLayoutCompat.LayoutParams(android.support.v7.widget.LinearLayoutCompat.LayoutParams);
+ field public int gravity;
+ field public float weight;
+ }
+
+ public class ListPopupWindow {
+ ctor public ListPopupWindow(android.content.Context);
+ ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet);
+ ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int);
+ ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int, int);
+ method public void clearListSelection();
+ method public android.view.View.OnTouchListener createDragToOpenListener(android.view.View);
+ method public void dismiss();
+ method public android.view.View getAnchorView();
+ method public int getAnimationStyle();
+ method public android.graphics.drawable.Drawable getBackground();
+ method public int getHeight();
+ method public int getHorizontalOffset();
+ method public int getInputMethodMode();
+ method public android.widget.ListView getListView();
+ method public int getPromptPosition();
+ method public java.lang.Object getSelectedItem();
+ method public long getSelectedItemId();
+ method public int getSelectedItemPosition();
+ method public android.view.View getSelectedView();
+ method public int getSoftInputMode();
+ method public int getVerticalOffset();
+ method public int getWidth();
+ method public boolean isInputMethodNotNeeded();
+ method public boolean isModal();
+ method public boolean isShowing();
+ method public boolean onKeyDown(int, android.view.KeyEvent);
+ method public boolean onKeyPreIme(int, android.view.KeyEvent);
+ method public boolean onKeyUp(int, android.view.KeyEvent);
+ method public boolean performItemClick(int);
+ method public void postShow();
+ method public void setAdapter(android.widget.ListAdapter);
+ method public void setAnchorView(android.view.View);
+ method public void setAnimationStyle(int);
+ method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setContentWidth(int);
+ method public void setDropDownGravity(int);
+ method public void setHeight(int);
+ method public void setHorizontalOffset(int);
+ method public void setInputMethodMode(int);
+ method public void setListSelector(android.graphics.drawable.Drawable);
+ method public void setModal(boolean);
+ method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
+ method public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener);
+ method public void setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+ method public void setPromptPosition(int);
+ method public void setPromptView(android.view.View);
+ method public void setSelection(int);
+ method public void setSoftInputMode(int);
+ method public void setVerticalOffset(int);
+ method public void setWidth(int);
+ method public void setWindowLayoutType(int);
+ method public void show();
+ field public static final int INPUT_METHOD_FROM_FOCUSABLE = 0; // 0x0
+ field public static final int INPUT_METHOD_NEEDED = 1; // 0x1
+ field public static final int INPUT_METHOD_NOT_NEEDED = 2; // 0x2
+ field public static final int MATCH_PARENT = -1; // 0xffffffff
+ field public static final int POSITION_PROMPT_ABOVE = 0; // 0x0
+ field public static final int POSITION_PROMPT_BELOW = 1; // 0x1
+ field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+ }
+
+ public class PopupMenu {
+ ctor public PopupMenu(android.content.Context, android.view.View);
+ ctor public PopupMenu(android.content.Context, android.view.View, int);
+ ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
+ method public void dismiss();
+ method public android.view.View.OnTouchListener getDragToOpenListener();
+ method public int getGravity();
+ method public android.view.Menu getMenu();
+ method public android.view.MenuInflater getMenuInflater();
+ method public void inflate(int);
+ method public void setGravity(int);
+ method public void setOnDismissListener(android.support.v7.widget.PopupMenu.OnDismissListener);
+ method public void setOnMenuItemClickListener(android.support.v7.widget.PopupMenu.OnMenuItemClickListener);
+ method public void show();
+ }
+
+ public static abstract interface PopupMenu.OnDismissListener {
+ method public abstract void onDismiss(android.support.v7.widget.PopupMenu);
+ }
+
+ public static abstract interface PopupMenu.OnMenuItemClickListener {
+ method public abstract boolean onMenuItemClick(android.view.MenuItem);
+ }
+
+ public class SearchView extends android.support.v7.widget.LinearLayoutCompat implements android.support.v7.view.CollapsibleActionView {
+ ctor public SearchView(android.content.Context);
+ ctor public SearchView(android.content.Context, android.util.AttributeSet);
+ ctor public SearchView(android.content.Context, android.util.AttributeSet, int);
+ method public int getImeOptions();
+ method public int getInputType();
+ method public int getMaxWidth();
+ method public java.lang.CharSequence getQuery();
+ method public java.lang.CharSequence getQueryHint();
+ method public android.support.v4.widget.CursorAdapter getSuggestionsAdapter();
+ method public boolean isIconfiedByDefault();
+ method public boolean isIconified();
+ method public boolean isQueryRefinementEnabled();
+ method public boolean isSubmitButtonEnabled();
+ method public void onActionViewCollapsed();
+ method public void onActionViewExpanded();
+ method public void setIconified(boolean);
+ method public void setIconifiedByDefault(boolean);
+ method public void setImeOptions(int);
+ method public void setInputType(int);
+ method public void setMaxWidth(int);
+ method public void setOnCloseListener(android.support.v7.widget.SearchView.OnCloseListener);
+ method public void setOnQueryTextFocusChangeListener(android.view.View.OnFocusChangeListener);
+ method public void setOnQueryTextListener(android.support.v7.widget.SearchView.OnQueryTextListener);
+ method public void setOnSearchClickListener(android.view.View.OnClickListener);
+ method public void setOnSuggestionListener(android.support.v7.widget.SearchView.OnSuggestionListener);
+ method public void setQuery(java.lang.CharSequence, boolean);
+ method public void setQueryHint(java.lang.CharSequence);
+ method public void setQueryRefinementEnabled(boolean);
+ method public void setSearchableInfo(android.app.SearchableInfo);
+ method public void setSubmitButtonEnabled(boolean);
+ method public void setSuggestionsAdapter(android.support.v4.widget.CursorAdapter);
+ }
+
+ public static abstract interface SearchView.OnCloseListener {
+ method public abstract boolean onClose();
+ }
+
+ public static abstract interface SearchView.OnQueryTextListener {
+ method public abstract boolean onQueryTextChange(java.lang.String);
+ method public abstract boolean onQueryTextSubmit(java.lang.String);
+ }
+
+ public static abstract interface SearchView.OnSuggestionListener {
+ method public abstract boolean onSuggestionClick(int);
+ method public abstract boolean onSuggestionSelect(int);
+ }
+
+ public class ShareActionProvider extends android.support.v4.view.ActionProvider {
+ ctor public ShareActionProvider(android.content.Context);
+ method public android.view.View onCreateActionView();
+ method public void setOnShareTargetSelectedListener(android.support.v7.widget.ShareActionProvider.OnShareTargetSelectedListener);
+ method public void setShareHistoryFileName(java.lang.String);
+ method public void setShareIntent(android.content.Intent);
+ field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
+ }
+
+ public static abstract interface ShareActionProvider.OnShareTargetSelectedListener {
+ method public abstract boolean onShareTargetSelected(android.support.v7.widget.ShareActionProvider, android.content.Intent);
+ }
+
+ public class SwitchCompat extends android.widget.CompoundButton {
+ ctor public SwitchCompat(android.content.Context);
+ ctor public SwitchCompat(android.content.Context, android.util.AttributeSet);
+ ctor public SwitchCompat(android.content.Context, android.util.AttributeSet, int);
+ method public boolean getShowText();
+ method public boolean getSplitTrack();
+ method public int getSwitchMinWidth();
+ method public int getSwitchPadding();
+ method public java.lang.CharSequence getTextOff();
+ method public java.lang.CharSequence getTextOn();
+ method public android.graphics.drawable.Drawable getThumbDrawable();
+ method public int getThumbTextPadding();
+ method public android.graphics.drawable.Drawable getTrackDrawable();
+ method public void onMeasure(int, int);
+ method public void setShowText(boolean);
+ method public void setSplitTrack(boolean);
+ method public void setSwitchMinWidth(int);
+ method public void setSwitchPadding(int);
+ method public void setSwitchTextAppearance(android.content.Context, int);
+ method public void setSwitchTypeface(android.graphics.Typeface, int);
+ method public void setSwitchTypeface(android.graphics.Typeface);
+ method public void setTextOff(java.lang.CharSequence);
+ method public void setTextOn(java.lang.CharSequence);
+ method public void setThumbDrawable(android.graphics.drawable.Drawable);
+ method public void setThumbResource(int);
+ method public void setThumbTextPadding(int);
+ method public void setTrackDrawable(android.graphics.drawable.Drawable);
+ method public void setTrackResource(int);
+ }
+
+ public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
+ method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+ method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+ }
+
+ public static final class ThemedSpinnerAdapter.Helper {
+ ctor public ThemedSpinnerAdapter.Helper(android.content.Context);
+ method public android.view.LayoutInflater getDropDownViewInflater();
+ method public android.content.res.Resources.Theme getDropDownViewTheme();
+ method public void setDropDownViewTheme(android.content.res.Resources.Theme);
+ }
+
+ public class Toolbar extends android.view.ViewGroup {
+ ctor public Toolbar(android.content.Context);
+ ctor public Toolbar(android.content.Context, android.util.AttributeSet);
+ ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
+ method public void collapseActionView();
+ method public void dismissPopupMenus();
+ method public int getContentInsetEnd();
+ method public int getContentInsetLeft();
+ method public int getContentInsetRight();
+ method public int getContentInsetStart();
+ method public android.graphics.drawable.Drawable getLogo();
+ method public java.lang.CharSequence getLogoDescription();
+ method public android.view.Menu getMenu();
+ method public java.lang.CharSequence getNavigationContentDescription();
+ method public android.graphics.drawable.Drawable getNavigationIcon();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
+ method public int getPopupTheme();
+ method public java.lang.CharSequence getSubtitle();
+ method public java.lang.CharSequence getTitle();
+ method public boolean hasExpandedActionView();
+ method public boolean hideOverflowMenu();
+ method public void inflateMenu(int);
+ method public boolean isOverflowMenuShowing();
+ method protected void onLayout(boolean, int, int, int, int);
+ method public void setContentInsetsAbsolute(int, int);
+ method public void setContentInsetsRelative(int, int);
+ method public void setLogo(int);
+ method public void setLogo(android.graphics.drawable.Drawable);
+ method public void setLogoDescription(int);
+ method public void setLogoDescription(java.lang.CharSequence);
+ method public void setNavigationContentDescription(int);
+ method public void setNavigationContentDescription(java.lang.CharSequence);
+ method public void setNavigationIcon(int);
+ method public void setNavigationIcon(android.graphics.drawable.Drawable);
+ method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+ method public void setOnMenuItemClickListener(android.support.v7.widget.Toolbar.OnMenuItemClickListener);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
+ method public void setPopupTheme(int);
+ method public void setSubtitle(int);
+ method public void setSubtitle(java.lang.CharSequence);
+ method public void setSubtitleTextAppearance(android.content.Context, int);
+ method public void setSubtitleTextColor(int);
+ method public void setTitle(int);
+ method public void setTitle(java.lang.CharSequence);
+ method public void setTitleTextAppearance(android.content.Context, int);
+ method public void setTitleTextColor(int);
+ method public boolean showOverflowMenu();
+ }
+
+ public static class Toolbar.LayoutParams extends android.support.v7.app.ActionBar.LayoutParams {
+ ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public Toolbar.LayoutParams(int, int);
+ ctor public Toolbar.LayoutParams(int, int, int);
+ ctor public Toolbar.LayoutParams(int);
+ ctor public Toolbar.LayoutParams(android.support.v7.widget.Toolbar.LayoutParams);
+ ctor public Toolbar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+ ctor public Toolbar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
+ }
+
+ public static abstract interface Toolbar.OnMenuItemClickListener {
+ method public abstract boolean onMenuItemClick(android.view.MenuItem);
+ }
+
+ public static class Toolbar.SavedState extends android.view.View.BaseSavedState {
+ ctor public Toolbar.SavedState(android.os.Parcel);
+ ctor public Toolbar.SavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.v7.widget.Toolbar.SavedState> CREATOR;
+ }
+
+}
+
diff --git a/v7/appcompat/api/current.txt b/v7/appcompat/api/current.txt
index 336e3a7..8f35544 100644
--- a/v7/appcompat/api/current.txt
+++ b/v7/appcompat/api/current.txt
@@ -368,6 +368,7 @@
field public static int alertDialogCenterButtons;
field public static int alertDialogStyle;
field public static int alertDialogTheme;
+ field public static int allowStacking;
field public static int arrowHeadLength;
field public static int arrowShaftLength;
field public static int autoCompleteTextViewStyle;
@@ -435,6 +436,7 @@
field public static int homeLayout;
field public static int icon;
field public static int iconifiedByDefault;
+ field public static int imageButtonStyle;
field public static int indeterminateProgressStyle;
field public static int initialActivityCount;
field public static int isLightTheme;
@@ -477,6 +479,7 @@
field public static int searchHintIcon;
field public static int searchIcon;
field public static int searchViewStyle;
+ field public static int seekBarStyle;
field public static int selectableItemBackground;
field public static int selectableItemBackgroundBorderless;
field public static int showAsAction;
@@ -540,6 +543,7 @@
field public static int abc_action_bar_embed_tabs;
field public static int abc_action_bar_embed_tabs_pre_jb;
field public static int abc_action_bar_expanded_action_views_exclusive;
+ field public static int abc_allow_stacked_button_bar;
field public static int abc_config_actionMenuItemAllCaps;
field public static int abc_config_allowActionMenuItemTextWithIcon;
field public static int abc_config_closeDialogWhenTouchOutside;
@@ -646,6 +650,10 @@
field public static int abc_control_corner_material;
field public static int abc_control_inset_material;
field public static int abc_control_padding_material;
+ field public static int abc_dialog_fixed_height_major;
+ field public static int abc_dialog_fixed_height_minor;
+ field public static int abc_dialog_fixed_width_major;
+ field public static int abc_dialog_fixed_width_minor;
field public static int abc_dialog_list_padding_vertical_material;
field public static int abc_dialog_min_width_major;
field public static int abc_dialog_min_width_minor;
@@ -664,6 +672,9 @@
field public static int abc_panel_menu_list_width;
field public static int abc_search_view_preferred_width;
field public static int abc_search_view_text_min_width;
+ field public static int abc_seekbar_track_background_height_material;
+ field public static int abc_seekbar_track_progress_height_material;
+ field public static int abc_select_dialog_padding_start_material;
field public static int abc_switch_padding;
field public static int abc_text_size_body_1_material;
field public static int abc_text_size_body_2_material;
@@ -682,10 +693,6 @@
field public static int abc_text_size_subtitle_material_toolbar;
field public static int abc_text_size_title_material;
field public static int abc_text_size_title_material_toolbar;
- field public static int dialog_fixed_height_major;
- field public static int dialog_fixed_height_minor;
- field public static int dialog_fixed_width_major;
- field public static int dialog_fixed_width_minor;
field public static int disabled_alpha_material_dark;
field public static int disabled_alpha_material_light;
field public static int highlight_alpha_material_colored;
@@ -748,6 +755,13 @@
field public static int abc_menu_hardkey_panel_mtrl_mult;
field public static int abc_popup_background_mtrl_mult;
field public static int abc_ratingbar_full_material;
+ field public static int abc_scrubber_control_off_mtrl_alpha;
+ field public static int abc_scrubber_control_to_pressed_mtrl_000;
+ field public static int abc_scrubber_control_to_pressed_mtrl_005;
+ field public static int abc_scrubber_primary_mtrl_alpha;
+ field public static int abc_scrubber_track_mtrl_alpha;
+ field public static int abc_seekbar_thumb_material;
+ field public static int abc_seekbar_track_material;
field public static int abc_spinner_mtrl_am_alpha;
field public static int abc_spinner_textfield_background_material;
field public static int abc_switch_thumb_material;
@@ -821,6 +835,8 @@
field public static int progress_horizontal;
field public static int radio;
field public static int screen;
+ field public static int scrollIndicatorDown;
+ field public static int scrollIndicatorUp;
field public static int scrollView;
field public static int search_badge;
field public static int search_bar;
@@ -837,6 +853,7 @@
field public static int showCustom;
field public static int showHome;
field public static int showTitle;
+ field public static int spacer;
field public static int split_action_bar;
field public static int src_atop;
field public static int src_in;
@@ -877,6 +894,7 @@
field public static int abc_action_mode_close_item_material;
field public static int abc_activity_chooser_view;
field public static int abc_activity_chooser_view_list_item;
+ field public static int abc_alert_dialog_button_bar_material;
field public static int abc_alert_dialog_material;
field public static int abc_dialog_title_material;
field public static int abc_expanded_menu_layout;
@@ -916,6 +934,8 @@
field public static int abc_action_mode_done;
field public static int abc_activity_chooser_view_see_all;
field public static int abc_activitychooserview_choose_application;
+ field public static int abc_capital_off;
+ field public static int abc_capital_on;
field public static int abc_search_hint;
field public static int abc_searchview_description_clear;
field public static int abc_searchview_description_query;
@@ -1047,6 +1067,7 @@
field public static int Base_Widget_AppCompat_DrawerArrowToggle_Common;
field public static int Base_Widget_AppCompat_DropDownItem_Spinner;
field public static int Base_Widget_AppCompat_EditText;
+ field public static int Base_Widget_AppCompat_ImageButton;
field public static int Base_Widget_AppCompat_Light_ActionBar;
field public static int Base_Widget_AppCompat_Light_ActionBar_Solid;
field public static int Base_Widget_AppCompat_Light_ActionBar_TabBar;
@@ -1067,6 +1088,7 @@
field public static int Base_Widget_AppCompat_RatingBar;
field public static int Base_Widget_AppCompat_SearchView;
field public static int Base_Widget_AppCompat_SearchView_ActionBar;
+ field public static int Base_Widget_AppCompat_SeekBar;
field public static int Base_Widget_AppCompat_Spinner;
field public static int Base_Widget_AppCompat_Spinner_Underlined;
field public static int Base_Widget_AppCompat_TextView_SpinnerItem;
@@ -1084,7 +1106,6 @@
field public static int Platform_Widget_AppCompat_Spinner;
field public static int RtlOverlay_DialogWindowTitle_AppCompat;
field public static int RtlOverlay_Widget_AppCompat_ActionBar_TitleItem;
- field public static int RtlOverlay_Widget_AppCompat_ActionButton_Overflow;
field public static int RtlOverlay_Widget_AppCompat_DialogTitle_Icon;
field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem;
field public static int RtlOverlay_Widget_AppCompat_PopupMenuItem_InternalGroup;
@@ -1095,6 +1116,8 @@
field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Icon2;
field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Query;
field public static int RtlOverlay_Widget_AppCompat_Search_DropDown_Text;
+ field public static int RtlUnderlay_Widget_AppCompat_ActionButton;
+ field public static int RtlUnderlay_Widget_AppCompat_ActionButton_Overflow;
field public static int TextAppearance_AppCompat;
field public static int TextAppearance_AppCompat_Body1;
field public static int TextAppearance_AppCompat_Body2;
@@ -1191,6 +1214,7 @@
field public static int Widget_AppCompat_DrawerArrowToggle;
field public static int Widget_AppCompat_DropDownItem_Spinner;
field public static int Widget_AppCompat_EditText;
+ field public static int Widget_AppCompat_ImageButton;
field public static int Widget_AppCompat_Light_ActionBar;
field public static int Widget_AppCompat_Light_ActionBar_Solid;
field public static int Widget_AppCompat_Light_ActionBar_Solid_Inverse;
@@ -1225,6 +1249,7 @@
field public static int Widget_AppCompat_RatingBar;
field public static int Widget_AppCompat_SearchView;
field public static int Widget_AppCompat_SearchView_ActionBar;
+ field public static int Widget_AppCompat_SeekBar;
field public static int Widget_AppCompat_Spinner;
field public static int Widget_AppCompat_Spinner_DropDown;
field public static int Widget_AppCompat_Spinner_DropDown_ActionBar;
@@ -1289,6 +1314,7 @@
field public static final int[] AppCompatTextView;
field public static int AppCompatTextView_android_textAppearance;
field public static int AppCompatTextView_textAllCaps;
+ field public static int ButtonBarLayout_allowStacking;
field public static final int[] CompoundButton;
field public static int CompoundButton_android_button;
field public static int CompoundButton_buttonTint;
@@ -1379,6 +1405,7 @@
field public static int SearchView_voiceIcon;
field public static final int[] Spinner;
field public static int Spinner_android_dropDownWidth;
+ field public static int Spinner_android_entries;
field public static int Spinner_android_popupBackground;
field public static int Spinner_android_prompt;
field public static int Spinner_popupTheme;
@@ -1394,6 +1421,10 @@
field public static int SwitchCompat_thumbTextPadding;
field public static int SwitchCompat_track;
field public static final int[] TextAppearance;
+ field public static int TextAppearance_android_shadowColor;
+ field public static int TextAppearance_android_shadowDx;
+ field public static int TextAppearance_android_shadowDy;
+ field public static int TextAppearance_android_shadowRadius;
field public static int TextAppearance_android_textColor;
field public static int TextAppearance_android_textSize;
field public static int TextAppearance_android_textStyle;
@@ -1467,6 +1498,7 @@
field public static int Theme_editTextColor;
field public static int Theme_editTextStyle;
field public static int Theme_homeAsUpIndicator;
+ field public static int Theme_imageButtonStyle;
field public static int Theme_listChoiceBackgroundIndicator;
field public static int Theme_listDividerAlertDialog;
field public static int Theme_listPopupWindowStyle;
@@ -1483,6 +1515,7 @@
field public static int Theme_radioButtonStyle;
field public static int Theme_ratingBarStyle;
field public static int Theme_searchViewStyle;
+ field public static int Theme_seekBarStyle;
field public static int Theme_selectableItemBackground;
field public static int Theme_selectableItemBackgroundBorderless;
field public static int Theme_spinnerDropDownItemStyle;
@@ -1565,6 +1598,7 @@
method public int getDirection();
method public float getGapSize();
method public int getOpacity();
+ method public final android.graphics.Paint getPaint();
method public float getProgress();
method public boolean isSpinEnabled();
method public void setAlpha(int);
@@ -1690,6 +1724,18 @@
ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
}
+ public class AppCompatImageButton extends android.widget.ImageButton {
+ ctor public AppCompatImageButton(android.content.Context);
+ ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
+ }
+
+ public class AppCompatImageView extends android.widget.ImageView {
+ ctor public AppCompatImageView(android.content.Context);
+ ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
+ }
+
public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView {
ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
@@ -1708,6 +1754,12 @@
ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet, int);
}
+ public class AppCompatSeekBar extends android.widget.SeekBar {
+ ctor public AppCompatSeekBar(android.content.Context);
+ ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet);
+ ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet, int);
+ }
+
public class AppCompatSpinner extends android.widget.Spinner {
ctor public AppCompatSpinner(android.content.Context);
ctor public AppCompatSpinner(android.content.Context, int);
@@ -1817,6 +1869,7 @@
method public void setSoftInputMode(int);
method public void setVerticalOffset(int);
method public void setWidth(int);
+ method public void setWindowLayoutType(int);
method public void show();
field public static final int INPUT_METHOD_FROM_FOCUSABLE = 0; // 0x0
field public static final int INPUT_METHOD_NEEDED = 1; // 0x1
diff --git a/v7/appcompat/res-public/values/public_attrs.xml b/v7/appcompat/res-public/values/public_attrs.xml
index f8fae53..3c812d7 100644
--- a/v7/appcompat/res-public/values/public_attrs.xml
+++ b/v7/appcompat/res-public/values/public_attrs.xml
@@ -99,8 +99,6 @@
<public type="attr" name="dividerVertical"/>
<public type="attr" name="drawableSize"/>
<public type="attr" name="drawerArrowStyle"/>
- <public type="attr" name="dropdownListPreferredItemHeight"/>
- <public type="attr" name="dropDownListViewStyle"/>
<public type="attr" name="editTextBackground"/>
<public type="attr" name="editTextColor"/>
<public type="attr" name="editTextStyle"/>
@@ -115,6 +113,7 @@
<public type="attr" name="iconifiedByDefault"/>
<public type="attr" name="indeterminateProgressStyle"/>
<public type="attr" name="isLightTheme"/>
+ <public type="attr" name="imageButtonStyle"/>
<public type="attr" name="itemPadding"/>
<public type="attr" name="layout"/>
<public type="attr" name="listChoiceBackgroundIndicator"/>
diff --git a/v7/appcompat/res-public/values/public_styles.xml b/v7/appcompat/res-public/values/public_styles.xml
index 4b42d0f..991ab54 100644
--- a/v7/appcompat/res-public/values/public_styles.xml
+++ b/v7/appcompat/res-public/values/public_styles.xml
@@ -102,6 +102,7 @@
<public type="style" name="Widget.AppCompat.DrawerArrowToggle"/>
<public type="style" name="Widget.AppCompat.DropDownItem.Spinner"/>
<public type="style" name="Widget.AppCompat.EditText"/>
+ <public type="style" name="Widget.AppCompat.ImageButton"/>
<public type="style" name="Widget.AppCompat.Light.ActionBar"/>
<public type="style" name="Widget.AppCompat.Light.ActionBar.Solid"/>
<public type="style" name="Widget.AppCompat.Light.ActionBar.Solid.Inverse"/>
@@ -135,6 +136,7 @@
<public type="style" name="Widget.AppCompat.RatingBar"/>
<public type="style" name="Widget.AppCompat.SearchView"/>
<public type="style" name="Widget.AppCompat.SearchView.ActionBar"/>
+ <public type="style" name="Widget.AppCompat.SeekBar"/>
<public type="style" name="Widget.AppCompat.Spinner"/>
<public type="style" name="Widget.AppCompat.Spinner.DropDown"/>
<public type="style" name="Widget.AppCompat.Spinner.DropDown.ActionBar"/>
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_off_mtrl_alpha.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_off_mtrl_alpha.png
new file mode 100644
index 0000000..4efe298
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..543dec3
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..9930b3a
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_primary_mtrl_alpha.9.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_primary_mtrl_alpha.9.png
new file mode 100644
index 0000000..4cfb1a7
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_scrubber_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-hdpi/abc_scrubber_track_mtrl_alpha.9.png
new file mode 100644
index 0000000..32ddf7a
--- /dev/null
+++ b/v7/appcompat/res/drawable-hdpi/abc_scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-hdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-hdpi/abc_switch_track_mtrl_alpha.9.png
index 56436a1..6ad9b1d 100644
--- a/v7/appcompat/res/drawable-hdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-hdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_off_mtrl_alpha.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_off_mtrl_alpha.png
new file mode 100644
index 0000000..10df639
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..f83b1ef
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..e9efb20f
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_primary_mtrl_alpha.9.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_primary_mtrl_alpha.9.png
new file mode 100644
index 0000000..a4ab0a1
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_scrubber_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-mdpi/abc_scrubber_track_mtrl_alpha.9.png
new file mode 100644
index 0000000..db9e172
--- /dev/null
+++ b/v7/appcompat/res/drawable-mdpi/abc_scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-mdpi/abc_switch_track_mtrl_alpha.9.png
index fcd81de..00c81fc 100644
--- a/v7/appcompat/res/drawable-mdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-mdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_off_mtrl_alpha.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_off_mtrl_alpha.png
new file mode 100644
index 0000000..138f643
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..cd41d74
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..8d67525
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_primary_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_primary_mtrl_alpha.9.png
new file mode 100644
index 0000000..2b4734d
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_scrubber_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_track_mtrl_alpha.9.png
new file mode 100644
index 0000000..805cb29
--- /dev/null
+++ b/v7/appcompat/res/drawable-xhdpi/abc_scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xhdpi/abc_switch_track_mtrl_alpha.9.png
index cd1396b..f0752d2 100644
--- a/v7/appcompat/res/drawable-xhdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-xhdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_off_mtrl_alpha.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_off_mtrl_alpha.png
new file mode 100644
index 0000000..5268745
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..adffc14
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..f3d16d5
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_primary_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_primary_mtrl_alpha.9.png
new file mode 100644
index 0000000..6a82af5
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_track_mtrl_alpha.9.png
new file mode 100644
index 0000000..c3791fc
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxhdpi/abc_switch_track_mtrl_alpha.9.png
index 96bec46..c74b3fc 100644
--- a/v7/appcompat/res/drawable-xxhdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-xxhdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png b/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
new file mode 100644
index 0000000..e5a43bb
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png b/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
new file mode 100644
index 0000000..eeb37c1
--- /dev/null
+++ b/v7/appcompat/res/drawable-xxxhdpi/abc_scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxxhdpi/abc_switch_track_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxxhdpi/abc_switch_track_mtrl_alpha.9.png
index c2393ab..85c81c1 100644
--- a/v7/appcompat/res/drawable-xxxhdpi/abc_switch_track_mtrl_alpha.9.png
+++ b/v7/appcompat/res/drawable-xxxhdpi/abc_switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/v7/appcompat/res/drawable/abc_seekbar_thumb_material.xml b/v7/appcompat/res/drawable/abc_seekbar_thumb_material.xml
new file mode 100644
index 0000000..7fea83bc
--- /dev/null
+++ b/v7/appcompat/res/drawable/abc_seekbar_thumb_material.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:constantSize="true">
+ <item android:state_enabled="false" android:state_pressed="true">
+ <bitmap android:src="@drawable/abc_scrubber_control_off_mtrl_alpha"
+ android:gravity="center"/>
+ </item>
+ <item android:state_enabled="false">
+ <bitmap android:src="@drawable/abc_scrubber_control_off_mtrl_alpha"
+ android:gravity="center"/>
+ </item>
+ <item android:state_pressed="true">
+ <bitmap android:src="@drawable/abc_scrubber_control_to_pressed_mtrl_005"
+ android:gravity="center"/>
+ </item>
+ <item>
+ <bitmap android:src="@drawable/abc_scrubber_control_to_pressed_mtrl_000"
+ android:gravity="center"/>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/abc_seekbar_track_material.xml b/v7/appcompat/res/drawable/abc_seekbar_track_material.xml
new file mode 100644
index 0000000..e68ac03
--- /dev/null
+++ b/v7/appcompat/res/drawable/abc_seekbar_track_material.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@android:id/background"
+ android:drawable="@drawable/abc_scrubber_track_mtrl_alpha"/>
+ <item android:id="@android:id/secondaryProgress">
+ <scale android:scaleWidth="100%">
+ <selector>
+ <item android:state_enabled="false">
+ <color android:color="@android:color/transparent"/>
+ </item>
+ <item android:drawable="@drawable/abc_scrubber_primary_mtrl_alpha"/>
+ </selector>
+ </scale>
+ </item>
+ <item android:id="@android:id/progress">
+ <scale android:scaleWidth="100%">
+ <selector>
+ <item android:state_enabled="false">
+ <color android:color="@android:color/transparent"/>
+ </item>
+ <item android:drawable="@drawable/abc_scrubber_primary_mtrl_alpha"/>
+ </selector>
+ </scale>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_action_menu_item_layout.xml b/v7/appcompat/res/layout/abc_action_menu_item_layout.xml
index 150ea50..283358a 100644
--- a/v7/appcompat/res/layout/abc_action_menu_item_layout.xml
+++ b/v7/appcompat/res/layout/abc_action_menu_item_layout.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<android.support.v7.internal.view.menu.ActionMenuItemView
+<android.support.v7.view.menu.ActionMenuItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/v7/appcompat/res/layout/abc_action_mode_bar.xml b/v7/appcompat/res/layout/abc_action_mode_bar.xml
index 34b56a1..dc1f1ba 100644
--- a/v7/appcompat/res/layout/abc_action_mode_bar.xml
+++ b/v7/appcompat/res/layout/abc_action_mode_bar.xml
@@ -16,7 +16,7 @@
** limitations under the License.
*/
-->
-<android.support.v7.internal.widget.ActionBarContextView
+<android.support.v7.widget.ActionBarContextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml b/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
index dfc4deb..2944d983 100644
--- a/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
+++ b/v7/appcompat/res/layout/abc_action_mode_close_item_material.xml
@@ -14,13 +14,13 @@
limitations under the License.
-->
-<android.support.v7.internal.widget.TintImageView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/action_mode_close_button"
- android:contentDescription="@string/abc_action_mode_done"
- android:focusable="true"
- android:clickable="true"
- android:src="?attr/actionModeCloseDrawable"
- style="?attr/actionModeCloseButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="match_parent" />
\ No newline at end of file
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/action_mode_close_button"
+ android:contentDescription="@string/abc_action_mode_done"
+ android:focusable="true"
+ android:clickable="true"
+ android:src="?attr/actionModeCloseDrawable"
+ style="?attr/actionModeCloseButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_activity_chooser_view.xml b/v7/appcompat/res/layout/abc_activity_chooser_view.xml
index 85fd94e..2522f1a 100644
--- a/v7/appcompat/res/layout/abc_activity_chooser_view.xml
+++ b/v7/appcompat/res/layout/abc_activity_chooser_view.xml
@@ -17,7 +17,7 @@
*/
-->
<view xmlns:android="http://schemas.android.com/apk/res/android"
- class="android.support.v7.internal.widget.ActivityChooserView$InnerLayout"
+ class="android.support.v7.widget.ActivityChooserView$InnerLayout"
android:id="@+id/activity_chooser_view_content"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/v7/appcompat/res/layout/abc_alert_dialog_button_bar_material.xml b/v7/appcompat/res/layout/abc_alert_dialog_button_bar_material.xml
new file mode 100644
index 0000000..d32ad10
--- /dev/null
+++ b/v7/appcompat/res/layout/abc_alert_dialog_button_bar_material.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<android.support.v7.widget.ButtonBarLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/buttonPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layoutDirection="locale"
+ android:orientation="horizontal"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:gravity="bottom"
+ app:allowStacking="@bool/abc_allow_stacked_button_bar"
+ style="?attr/buttonBarStyle">
+
+ <Button
+ android:id="@android:id/button3"
+ style="?attr/buttonBarNeutralButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <android.support.v4.widget.Space
+ android:id="@+id/spacer"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="invisible" />
+
+ <Button
+ android:id="@android:id/button2"
+ style="?attr/buttonBarNegativeButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button
+ android:id="@android:id/button1"
+ style="?attr/buttonBarPositiveButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</android.support.v7.widget.ButtonBarLayout>
diff --git a/v7/appcompat/res/layout/abc_alert_dialog_material.xml b/v7/appcompat/res/layout/abc_alert_dialog_material.xml
index 9ba81fd..3237533 100644
--- a/v7/appcompat/res/layout/abc_alert_dialog_material.xml
+++ b/v7/appcompat/res/layout/abc_alert_dialog_material.xml
@@ -45,7 +45,7 @@
android:src="@null"
style="@style/RtlOverlay.Widget.AppCompat.DialogTitle.Icon"/>
- <android.support.v7.internal.widget.DialogTitle
+ <android.support.v7.widget.DialogTitle
android:id="@+id/alertTitle"
style="?attr/android:windowTitleStyle"
android:singleLine="true"
@@ -65,7 +65,14 @@
android:layout_weight="1"
android:minHeight="48dp">
- <ScrollView
+ <View android:id="@+id/scrollIndicatorUp"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_gravity="top"
+ android:background="?attr/colorControlHighlight"/>
+
+ <android.support.v4.widget.NestedScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -91,7 +98,14 @@
android:layout_width="0dp"
android:layout_height="@dimen/abc_dialog_padding_top_material"/>
</LinearLayout>
- </ScrollView>
+ </android.support.v4.widget.NestedScrollView>
+
+ <View android:id="@+id/scrollIndicatorDown"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_gravity="bottom"
+ android:background="?attr/colorControlHighlight"/>
</FrameLayout>
@@ -108,41 +122,6 @@
android:layout_height="wrap_content"/>
</FrameLayout>
- <LinearLayout
- android:id="@+id/buttonPanel"
- style="?attr/buttonBarStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layoutDirection="locale"
- android:orientation="horizontal"
- android:paddingLeft="12dp"
- android:paddingRight="12dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:gravity="bottom">
+ <include layout="@layout/abc_alert_dialog_button_bar_material" />
- <Button
- android:id="@android:id/button3"
- style="?attr/buttonBarNeutralButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <android.support.v4.widget.Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:visibility="invisible"/>
-
- <Button
- android:id="@android:id/button2"
- style="?attr/buttonBarNegativeButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <Button
- android:id="@android:id/button1"
- style="?attr/buttonBarPositiveButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
- </LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_dialog_title_material.xml b/v7/appcompat/res/layout/abc_dialog_title_material.xml
index 068b9e9..1ea20c5 100644
--- a/v7/appcompat/res/layout/abc_dialog_title_material.xml
+++ b/v7/appcompat/res/layout/abc_dialog_title_material.xml
@@ -19,7 +19,7 @@
enabled.
-->
-<android.support.v7.internal.widget.FitWindowsLinearLayout
+<android.support.v7.widget.FitWindowsLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
@@ -44,4 +44,4 @@
android:layout_height="wrap_content"
android:layout_weight="1"/>
-</android.support.v7.internal.widget.FitWindowsLinearLayout>
\ No newline at end of file
+</android.support.v7.widget.FitWindowsLinearLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_expanded_menu_layout.xml b/v7/appcompat/res/layout/abc_expanded_menu_layout.xml
index 371151f..560ada6 100644
--- a/v7/appcompat/res/layout/abc_expanded_menu_layout.xml
+++ b/v7/appcompat/res/layout/abc_expanded_menu_layout.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<android.support.v7.internal.view.menu.ExpandedMenuView
+<android.support.v7.view.menu.ExpandedMenuView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/expanded_menu"
android:layout_width="?attr/panelMenuListWidth"
diff --git a/v7/appcompat/res/layout/abc_list_menu_item_layout.xml b/v7/appcompat/res/layout/abc_list_menu_item_layout.xml
index 1cee43e..c85469d 100644
--- a/v7/appcompat/res/layout/abc_list_menu_item_layout.xml
+++ b/v7/appcompat/res/layout/abc_list_menu_item_layout.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<android.support.v7.internal.view.menu.ListMenuItemView
+<android.support.v7.view.menu.ListMenuItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeightSmall">
@@ -57,4 +57,4 @@
<!-- Checkbox, and/or radio button will be inserted here. -->
-</android.support.v7.internal.view.menu.ListMenuItemView>
+</android.support.v7.view.menu.ListMenuItemView>
diff --git a/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml b/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
index 76820e0..47125fe 100644
--- a/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
+++ b/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<android.support.v7.internal.view.menu.ListMenuItemView
+<android.support.v7.view.menu.ListMenuItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/dropdownListPreferredItemHeight"
@@ -58,4 +58,4 @@
<!-- Checkbox, and/or radio button will be inserted here. -->
-</android.support.v7.internal.view.menu.ListMenuItemView>
+</android.support.v7.view.menu.ListMenuItemView>
diff --git a/v7/appcompat/res/layout/abc_screen_content_include.xml b/v7/appcompat/res/layout/abc_screen_content_include.xml
index 6e21f2e..1c30338 100644
--- a/v7/appcompat/res/layout/abc_screen_content_include.xml
+++ b/v7/appcompat/res/layout/abc_screen_content_include.xml
@@ -16,7 +16,7 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <android.support.v7.internal.widget.ContentFrameLayout
+ <android.support.v7.widget.ContentFrameLayout
android:id="@id/action_bar_activity_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/v7/appcompat/res/layout/abc_screen_simple.xml b/v7/appcompat/res/layout/abc_screen_simple.xml
index 426851c..2783187 100644
--- a/v7/appcompat/res/layout/abc_screen_simple.xml
+++ b/v7/appcompat/res/layout/abc_screen_simple.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<android.support.v7.internal.widget.FitWindowsLinearLayout
+<android.support.v7.widget.FitWindowsLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/action_bar_root"
android:layout_width="match_parent"
@@ -22,7 +22,7 @@
android:orientation="vertical"
android:fitsSystemWindows="true">
- <android.support.v7.internal.widget.ViewStubCompat
+ <android.support.v7.widget.ViewStubCompat
android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/abc_action_mode_bar"
@@ -31,4 +31,4 @@
<include layout="@layout/abc_screen_content_include" />
-</android.support.v7.internal.widget.FitWindowsLinearLayout>
+</android.support.v7.widget.FitWindowsLinearLayout>
diff --git a/v7/appcompat/res/layout/abc_screen_simple_overlay_action_mode.xml b/v7/appcompat/res/layout/abc_screen_simple_overlay_action_mode.xml
index ac399c1..c02c2aa 100644
--- a/v7/appcompat/res/layout/abc_screen_simple_overlay_action_mode.xml
+++ b/v7/appcompat/res/layout/abc_screen_simple_overlay_action_mode.xml
@@ -20,7 +20,7 @@
enabled.
-->
-<android.support.v7.internal.widget.FitWindowsFrameLayout
+<android.support.v7.widget.FitWindowsFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/action_bar_root"
android:layout_width="match_parent"
@@ -29,11 +29,11 @@
<include layout="@layout/abc_screen_content_include" />
- <android.support.v7.internal.widget.ViewStubCompat
+ <android.support.v7.widget.ViewStubCompat
android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/abc_action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
-</android.support.v7.internal.widget.FitWindowsFrameLayout>
\ No newline at end of file
+</android.support.v7.widget.FitWindowsFrameLayout>
\ No newline at end of file
diff --git a/v7/appcompat/res/layout/abc_screen_toolbar.xml b/v7/appcompat/res/layout/abc_screen_toolbar.xml
index 572ec34..96412c1 100644
--- a/v7/appcompat/res/layout/abc_screen_toolbar.xml
+++ b/v7/appcompat/res/layout/abc_screen_toolbar.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<android.support.v7.internal.widget.ActionBarOverlayLayout
+<android.support.v7.widget.ActionBarOverlayLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/decor_content_parent"
@@ -24,7 +24,7 @@
<include layout="@layout/abc_screen_content_include"/>
- <android.support.v7.internal.widget.ActionBarContainer
+ <android.support.v7.widget.ActionBarContainer
android:id="@+id/action_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -40,7 +40,7 @@
app:navigationContentDescription="@string/abc_action_bar_up_description"
style="?attr/toolbarStyle"/>
- <android.support.v7.internal.widget.ActionBarContextView
+ <android.support.v7.widget.ActionBarContextView
android:id="@+id/action_context_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -48,6 +48,6 @@
android:theme="?attr/actionBarTheme"
style="?attr/actionModeStyle"/>
- </android.support.v7.internal.widget.ActionBarContainer>
+ </android.support.v7.widget.ActionBarContainer>
-</android.support.v7.internal.widget.ActionBarOverlayLayout>
+</android.support.v7.widget.ActionBarOverlayLayout>
diff --git a/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml b/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
index 7407498..b81d5d8 100644
--- a/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
+++ b/v7/appcompat/res/layout/abc_search_dropdown_item_icons_2line.xml
@@ -24,7 +24,7 @@
<!-- Icons come first in the layout, since their placement doesn't depend on
the placement of the text views. -->
- <android.support.v7.internal.widget.TintImageView
+ <ImageView
android:id="@android:id/icon1"
android:layout_width="@dimen/abc_dropdownitem_icon_width"
android:layout_height="48dip"
@@ -34,7 +34,7 @@
android:visibility="invisible"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon1" />
- <android.support.v7.internal.widget.TintImageView
+ <ImageView
android:id="@+id/edit_query"
android:layout_width="48dip"
android:layout_height="48dip"
@@ -45,7 +45,7 @@
android:visibility="gone"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Query" />
- <android.support.v7.internal.widget.TintImageView
+ <ImageView
android:id="@id/android:icon2"
android:layout_width="48dip"
android:layout_height="48dip"
diff --git a/v7/appcompat/res/layout/abc_search_view.xml b/v7/appcompat/res/layout/abc_search_view.xml
index ff9361dc..a7446e3 100644
--- a/v7/appcompat/res/layout/abc_search_view.xml
+++ b/v7/appcompat/res/layout/abc_search_view.xml
@@ -35,7 +35,7 @@
android:textColor="?android:attr/textColorPrimary"
android:visibility="gone" />
- <android.support.v7.internal.widget.TintImageView
+ <ImageView
android:id="@+id/search_button"
style="?attr/actionButtonStyle"
android:layout_width="wrap_content"
@@ -57,7 +57,7 @@
android:orientation="horizontal"
android:layoutDirection="locale">
- <android.support.v7.internal.widget.TintImageView
+ <ImageView
android:id="@+id/search_mag_icon"
android:layout_width="@dimen/abc_dropdownitem_icon_width"
android:layout_height="wrap_content"
@@ -94,7 +94,7 @@
android:dropDownVerticalOffset="0dip"
android:dropDownHorizontalOffset="0dip" />
- <android.support.v7.internal.widget.TintImageView
+ <ImageView
android:id="@+id/search_close_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
@@ -113,7 +113,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent">
- <android.support.v7.internal.widget.TintImageView
+ <ImageView
android:id="@+id/search_go_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
@@ -125,7 +125,7 @@
android:focusable="true"
android:contentDescription="@string/abc_searchview_description_submit" />
- <android.support.v7.internal.widget.TintImageView
+ <ImageView
android:id="@+id/search_voice_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/v7/appcompat/res/layout/select_dialog_multichoice_material.xml b/v7/appcompat/res/layout/select_dialog_multichoice_material.xml
index 8f75bd3..60f3576 100644
--- a/v7/appcompat/res/layout/select_dialog_multichoice_material.xml
+++ b/v7/appcompat/res/layout/select_dialog_multichoice_material.xml
@@ -16,14 +16,18 @@
-->
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?attr/listPreferredItemHeightSmall"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?attr/textColorAlertDialogListItem"
- android:gravity="center_vertical"
- android:paddingLeft="?attr/dialogPreferredPadding"
- android:paddingRight="?attr/dialogPreferredPadding"
- android:checkMark="?android:attr/listChoiceIndicatorMultiple"
- android:ellipsize="marquee" />
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingLeft="@dimen/abc_select_dialog_padding_start_material"
+ android:paddingRight="?attr/dialogPreferredPadding"
+ android:paddingStart="@dimen/abc_select_dialog_padding_start_material"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:drawableLeft="?android:attr/listChoiceIndicatorMultiple"
+ android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
+ android:drawablePadding="20dp"
+ android:ellipsize="marquee" />
diff --git a/v7/appcompat/res/layout/select_dialog_singlechoice_material.xml b/v7/appcompat/res/layout/select_dialog_singlechoice_material.xml
index 3c2264c..4d10fc7 100644
--- a/v7/appcompat/res/layout/select_dialog_singlechoice_material.xml
+++ b/v7/appcompat/res/layout/select_dialog_singlechoice_material.xml
@@ -16,14 +16,18 @@
-->
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?attr/listPreferredItemHeightSmall"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?attr/textColorAlertDialogListItem"
- android:gravity="center_vertical"
- android:paddingLeft="?attr/dialogPreferredPadding"
- android:paddingRight="?attr/dialogPreferredPadding"
- android:checkMark="?android:attr/listChoiceIndicatorSingle"
- android:ellipsize="marquee" />
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingLeft="@dimen/abc_select_dialog_padding_start_material"
+ android:paddingRight="?attr/dialogPreferredPadding"
+ android:paddingStart="@dimen/abc_select_dialog_padding_start_material"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:drawableLeft="?android:attr/listChoiceIndicatorSingle"
+ android:drawableStart="?android:attr/listChoiceIndicatorSingle"
+ android:drawablePadding="20dp"
+ android:ellipsize="marquee" />
diff --git a/v7/appcompat/res/values-af/strings.xml b/v7/appcompat/res/values-af/strings.xml
index 4bb50b0..39649091 100644
--- a/v7/appcompat/res/values-af/strings.xml
+++ b/v7/appcompat/res/values-af/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Deel met %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Deel met"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"AAN"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"AF"</string>
</resources>
diff --git a/v7/appcompat/res/values-am/strings.xml b/v7/appcompat/res/values-am/strings.xml
index a76c931..ae720f8 100644
--- a/v7/appcompat/res/values-am/strings.xml
+++ b/v7/appcompat/res/values-am/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ከ%s ጋር ያጋሩ"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ከሚከተለው ጋር ያጋሩ"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"በርቷል"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ጠፍቷል"</string>
</resources>
diff --git a/v7/appcompat/res/values-ar/strings.xml b/v7/appcompat/res/values-ar/strings.xml
index f0046a9..313daf8 100644
--- a/v7/appcompat/res/values-ar/strings.xml
+++ b/v7/appcompat/res/values-ar/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"مشاركة مع %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"مشاركة مع"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"تشغيل"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"إيقاف"</string>
</resources>
diff --git a/v7/appcompat/res/values-az-rAZ/strings.xml b/v7/appcompat/res/values-az-rAZ/strings.xml
index a39f5f4..37d2399 100644
--- a/v7/appcompat/res/values-az-rAZ/strings.xml
+++ b/v7/appcompat/res/values-az-rAZ/strings.xml
@@ -36,4 +36,6 @@
<skip />
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bununla paylaşın"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"AKTİV"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DEAKTİV"</string>
</resources>
diff --git a/v7/appcompat/res/values-bg/strings.xml b/v7/appcompat/res/values-bg/strings.xml
index d8cbcd0..c71fd6c 100644
--- a/v7/appcompat/res/values-bg/strings.xml
+++ b/v7/appcompat/res/values-bg/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Споделяне със: %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Споделяне със:"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛ."</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ИЗКЛ."</string>
</resources>
diff --git a/v7/appcompat/res/values-bn-rBD/strings.xml b/v7/appcompat/res/values-bn-rBD/strings.xml
index 872d425..6be164f 100644
--- a/v7/appcompat/res/values-bn-rBD/strings.xml
+++ b/v7/appcompat/res/values-bn-rBD/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s এর সাথে ভাগ করুন"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"এর সাথে ভাগ করুন"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"৯৯৯+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"চালু"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"বন্ধ"</string>
</resources>
diff --git a/v7/appcompat/res/values-ca/strings.xml b/v7/appcompat/res/values-ca/strings.xml
index 863e69f..2613ea6 100644
--- a/v7/appcompat/res/values-ca/strings.xml
+++ b/v7/appcompat/res/values-ca/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Comparteix amb %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Comparteix amb"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAT"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVAT"</string>
</resources>
diff --git a/v7/appcompat/res/values-cs/strings.xml b/v7/appcompat/res/values-cs/strings.xml
index cba91eb..c8e1921 100644
--- a/v7/appcompat/res/values-cs/strings.xml
+++ b/v7/appcompat/res/values-cs/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Sdílet pomocí %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Sdílet pomocí"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ZAPNUTO"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"VYPNUTO"</string>
</resources>
diff --git a/v7/appcompat/res/values-da/strings.xml b/v7/appcompat/res/values-da/strings.xml
index bda45791..e7ac13f 100644
--- a/v7/appcompat/res/values-da/strings.xml
+++ b/v7/appcompat/res/values-da/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Del med %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Del med"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"TIL"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"FRA"</string>
</resources>
diff --git a/v7/appcompat/res/values-de/strings.xml b/v7/appcompat/res/values-de/strings.xml
index b5a74e9..06a18b5 100644
--- a/v7/appcompat/res/values-de/strings.xml
+++ b/v7/appcompat/res/values-de/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Freigeben für %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Freigeben für"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"An"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"Aus"</string>
</resources>
diff --git a/v7/appcompat/res/values-el/strings.xml b/v7/appcompat/res/values-el/strings.xml
index 1ecc119..5309082 100644
--- a/v7/appcompat/res/values-el/strings.xml
+++ b/v7/appcompat/res/values-el/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Κοινή χρήση με %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Κοινή χρήση με"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ΑΠΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
</resources>
diff --git a/v7/appcompat/res/values-en-rAU/strings.xml b/v7/appcompat/res/values-en-rAU/strings.xml
index 4db58a9..ab73cfd 100644
--- a/v7/appcompat/res/values-en-rAU/strings.xml
+++ b/v7/appcompat/res/values-en-rAU/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Share with %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Share with"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
</resources>
diff --git a/v7/appcompat/res/values-en-rGB/strings.xml b/v7/appcompat/res/values-en-rGB/strings.xml
index 4db58a9..ab73cfd 100644
--- a/v7/appcompat/res/values-en-rGB/strings.xml
+++ b/v7/appcompat/res/values-en-rGB/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Share with %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Share with"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
</resources>
diff --git a/v7/appcompat/res/values-en-rIN/strings.xml b/v7/appcompat/res/values-en-rIN/strings.xml
index 4db58a9..ab73cfd 100644
--- a/v7/appcompat/res/values-en-rIN/strings.xml
+++ b/v7/appcompat/res/values-en-rIN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Share with %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Share with"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
</resources>
diff --git a/v7/appcompat/res/values-es-rUS/strings.xml b/v7/appcompat/res/values-es-rUS/strings.xml
index 043c6ae..f1e3dbb 100644
--- a/v7/appcompat/res/values-es-rUS/strings.xml
+++ b/v7/appcompat/res/values-es-rUS/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartir con %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartir con"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAR"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVAR"</string>
</resources>
diff --git a/v7/appcompat/res/values-es/strings.xml b/v7/appcompat/res/values-es/strings.xml
index 8f6ea4b..d8e7d39 100644
--- a/v7/appcompat/res/values-es/strings.xml
+++ b/v7/appcompat/res/values-es/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartir con %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartir con"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"SÍ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"NO"</string>
</resources>
diff --git a/v7/appcompat/res/values-et-rEE/strings.xml b/v7/appcompat/res/values-et-rEE/strings.xml
index b8c7f16..03091c4 100644
--- a/v7/appcompat/res/values-et-rEE/strings.xml
+++ b/v7/appcompat/res/values-et-rEE/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Jagamine kasutajaga %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Jagamine:"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"SEES"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"VÄLJAS"</string>
</resources>
diff --git a/v7/appcompat/res/values-eu-rES/strings.xml b/v7/appcompat/res/values-eu-rES/strings.xml
index 3b0fb90..92bda4a 100644
--- a/v7/appcompat/res/values-eu-rES/strings.xml
+++ b/v7/appcompat/res/values-eu-rES/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partekatu %s erabiltzailearekin"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partekatu hauekin"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"AKTIBATUTA"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DESAKTIBATUTA"</string>
</resources>
diff --git a/v7/appcompat/res/values-fa/strings.xml b/v7/appcompat/res/values-fa/strings.xml
index 28c76b4..97d6ea7 100644
--- a/v7/appcompat/res/values-fa/strings.xml
+++ b/v7/appcompat/res/values-fa/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"اشتراکگذاری با %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"اشتراکگذاری با"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"۹۹۹+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"روشن"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"خاموش"</string>
</resources>
diff --git a/v7/appcompat/res/values-fi/strings.xml b/v7/appcompat/res/values-fi/strings.xml
index 4b3e728..77a4a98 100644
--- a/v7/appcompat/res/values-fi/strings.xml
+++ b/v7/appcompat/res/values-fi/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Jakaminen: %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Jakaminen:"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"KÄYTÖSSÄ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"POIS KÄYTÖSTÄ"</string>
</resources>
diff --git a/v7/appcompat/res/values-fr-rCA/strings.xml b/v7/appcompat/res/values-fr-rCA/strings.xml
index 291bd4e..1f636fb 100644
--- a/v7/appcompat/res/values-fr-rCA/strings.xml
+++ b/v7/appcompat/res/values-fr-rCA/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partager avec %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partager"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">">999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVÉ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DÉSACTIVÉ"</string>
</resources>
diff --git a/v7/appcompat/res/values-fr/strings.xml b/v7/appcompat/res/values-fr/strings.xml
index b7f5604..8fc4240 100644
--- a/v7/appcompat/res/values-fr/strings.xml
+++ b/v7/appcompat/res/values-fr/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partager avec %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partager avec"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">">999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVÉ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DÉSACTIVÉ"</string>
</resources>
diff --git a/v7/appcompat/res/values-gl-rES/strings.xml b/v7/appcompat/res/values-gl-rES/strings.xml
index b6b11be..ee1e7d5 100644
--- a/v7/appcompat/res/values-gl-rES/strings.xml
+++ b/v7/appcompat/res/values-gl-rES/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartir con %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartir con"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">">999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAR"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVAR"</string>
</resources>
diff --git a/v7/appcompat/res/values-gu-rIN/strings.xml b/v7/appcompat/res/values-gu-rIN/strings.xml
index b77acd3..6fea9bb 100644
--- a/v7/appcompat/res/values-gu-rIN/strings.xml
+++ b/v7/appcompat/res/values-gu-rIN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s સાથે શેર કરો"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"આની સાથે શેર કરો"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ચાલુ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"બંધ"</string>
</resources>
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v7/appcompat/res/values-h320dp/bools.xml
similarity index 75%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to v7/appcompat/res/values-h320dp/bools.xml
index a4614f6..5576c18 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v7/appcompat/res/values-h320dp/bools.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -14,6 +14,6 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_setting_light" />
-</selector>
+<resources>
+ <bool name="abc_allow_stacked_button_bar">true</bool>
+</resources>
diff --git a/v7/appcompat/res/values-hi/strings.xml b/v7/appcompat/res/values-hi/strings.xml
index 95daa34..17d3d7b 100644
--- a/v7/appcompat/res/values-hi/strings.xml
+++ b/v7/appcompat/res/values-hi/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s के साथ साझा करें"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"इसके द्वारा साझा करें"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"चालू"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"बंद"</string>
</resources>
diff --git a/v7/appcompat/res/values-hr/strings.xml b/v7/appcompat/res/values-hr/strings.xml
index da68332..6467bfa 100644
--- a/v7/appcompat/res/values-hr/strings.xml
+++ b/v7/appcompat/res/values-hr/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Dijeljenje sa: %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Dijeljenje sa"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"UKLJUČENO"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ISKLJUČENO"</string>
</resources>
diff --git a/v7/appcompat/res/values-hu/strings.xml b/v7/appcompat/res/values-hu/strings.xml
index 57ab85b..1cb4fe5 100644
--- a/v7/appcompat/res/values-hu/strings.xml
+++ b/v7/appcompat/res/values-hu/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Megosztás a következővel: %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Megosztás a következővel:"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"BE"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"KI"</string>
</resources>
diff --git a/v7/appcompat/res/values-hy-rAM/strings.xml b/v7/appcompat/res/values-hy-rAM/strings.xml
index 903fa43..708275a 100644
--- a/v7/appcompat/res/values-hy-rAM/strings.xml
+++ b/v7/appcompat/res/values-hy-rAM/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Տարածել ըստ %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Տարածել"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ՄԻԱՑՎԱԾ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ԱՆՋԱՏՎԱԾ"</string>
</resources>
diff --git a/v7/appcompat/res/values-in/strings.xml b/v7/appcompat/res/values-in/strings.xml
index 0e7003c..d2d0ecc 100644
--- a/v7/appcompat/res/values-in/strings.xml
+++ b/v7/appcompat/res/values-in/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Bagikan dengan %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bagikan dengan"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"AKTIF"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"NONAKTIF"</string>
</resources>
diff --git a/v7/appcompat/res/values-is-rIS/strings.xml b/v7/appcompat/res/values-is-rIS/strings.xml
index fb305b2..c8ded4d 100644
--- a/v7/appcompat/res/values-is-rIS/strings.xml
+++ b/v7/appcompat/res/values-is-rIS/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Deila með %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Deila með"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"KVEIKT"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"SLÖKKT"</string>
</resources>
diff --git a/v7/appcompat/res/values-it/strings.xml b/v7/appcompat/res/values-it/strings.xml
index a2d9bee..31bff55 100644
--- a/v7/appcompat/res/values-it/strings.xml
+++ b/v7/appcompat/res/values-it/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Condividi con %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Condividi con"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
</resources>
diff --git a/v7/appcompat/res/values-iw/strings.xml b/v7/appcompat/res/values-iw/strings.xml
index 329d0ec..6b834d9 100644
--- a/v7/appcompat/res/values-iw/strings.xml
+++ b/v7/appcompat/res/values-iw/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"שתף עם %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"שתף עם"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"פועל"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"כבוי"</string>
</resources>
diff --git a/v7/appcompat/res/values-ja/strings.xml b/v7/appcompat/res/values-ja/strings.xml
index fa55b08..45fb2c0 100644
--- a/v7/appcompat/res/values-ja/strings.xml
+++ b/v7/appcompat/res/values-ja/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%sと共有"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"共有"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
</resources>
diff --git a/v7/appcompat/res/values-ka-rGE/strings.xml b/v7/appcompat/res/values-ka-rGE/strings.xml
index b14bcb7..91c31fb 100644
--- a/v7/appcompat/res/values-ka-rGE/strings.xml
+++ b/v7/appcompat/res/values-ka-rGE/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s-თან გაზიარება"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"გაზიარება:"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ჩართულია"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"გამორთულია"</string>
</resources>
diff --git a/v7/appcompat/res/values-kk-rKZ/strings.xml b/v7/appcompat/res/values-kk-rKZ/strings.xml
index 2ce080f..81fcfa9 100644
--- a/v7/appcompat/res/values-kk-rKZ/strings.xml
+++ b/v7/appcompat/res/values-kk-rKZ/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s бөлісу"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Бөлісу"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ҚОСУЛЫ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ӨШІРУЛІ"</string>
</resources>
diff --git a/v7/appcompat/res/values-km-rKH/strings.xml b/v7/appcompat/res/values-km-rKH/strings.xml
index aa81b7d..ee4bcbe 100644
--- a/v7/appcompat/res/values-km-rKH/strings.xml
+++ b/v7/appcompat/res/values-km-rKH/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ចែករំលែកជាមួយ %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ចែករំលែកជាមួយ"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"បើក"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"បិទ"</string>
</resources>
diff --git a/v7/appcompat/res/values-kn-rIN/strings.xml b/v7/appcompat/res/values-kn-rIN/strings.xml
index 7ef7572..abd409e 100644
--- a/v7/appcompat/res/values-kn-rIN/strings.xml
+++ b/v7/appcompat/res/values-kn-rIN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ಇವರೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ಆನ್"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ಆಫ್"</string>
</resources>
diff --git a/v7/appcompat/res/values-ko/strings.xml b/v7/appcompat/res/values-ko/strings.xml
index 7c158f9..262f543 100644
--- a/v7/appcompat/res/values-ko/strings.xml
+++ b/v7/appcompat/res/values-ko/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s와(과) 공유"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"공유 대상"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"사용"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"사용 안함"</string>
</resources>
diff --git a/v7/appcompat/res/values-ky-rKG/strings.xml b/v7/appcompat/res/values-ky-rKG/strings.xml
index a758b96..3176cc6 100644
--- a/v7/appcompat/res/values-ky-rKG/strings.xml
+++ b/v7/appcompat/res/values-ky-rKG/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s аркылуу бөлүшүү"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Бөлүшүү"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"КҮЙҮК"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ӨЧҮК"</string>
</resources>
diff --git a/v7/appcompat/res/values-large/dimens.xml b/v7/appcompat/res/values-large/dimens.xml
index de1cefc..16bb4f6 100644
--- a/v7/appcompat/res/values-large/dimens.xml
+++ b/v7/appcompat/res/values-large/dimens.xml
@@ -22,17 +22,12 @@
showAsAction="ifRoom" items can fit. "always" items can override this. -->
<integer name="abc_max_action_buttons">4</integer>
- <!-- The platform's desired fixed width for a dialog along the major axis
- (the screen is in landscape). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_width_major">60%</item>
- <!-- The platform's desired fixed width for a dialog along the minor axis
- (the screen is in portrait). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_width_minor">90%</item>
- <!-- The platform's desired fixed height for a dialog along the major axis
- (the screen is in portrait). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_height_major">60%</item>
- <!-- The platform's desired fixed height for a dialog along the minor axis
- (the screen is in landscape). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_height_minor">90%</item>
+ <item type="dimen" name="abc_dialog_fixed_width_major">60%</item>
+ <item type="dimen" name="abc_dialog_fixed_width_minor">90%</item>
+ <item type="dimen" name="abc_dialog_fixed_height_major">60%</item>
+ <item type="dimen" name="abc_dialog_fixed_height_minor">90%</item>
+
+ <item type="dimen" name="abc_dialog_min_width_major">55%</item>
+ <item type="dimen" name="abc_dialog_min_width_minor">80%</item>
</resources>
diff --git a/v7/appcompat/res/values-ldltr-v21/styles_base.xml b/v7/appcompat/res/values-ldltr-v21/styles_base.xml
new file mode 100644
index 0000000..57ebdba
--- /dev/null
+++ b/v7/appcompat/res/values-ldltr-v21/styles_base.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<resources>
+
+ <!-- Like in themes_base.xml, the namespace "*.AppCompat.Base" is used to
+ define base styles for the platform version. The "*.AppCompat"
+ variants are for direct use or use as parent styles by the app. -->
+ <eat-comment/>
+
+ <!-- The platform Underlined style only works in LTR in v21-22 -->
+ <style name="Base.Widget.AppCompat.Spinner.Underlined" parent="android:Widget.Material.Spinner.Underlined" />
+
+</resources>
diff --git a/v17/leanback/res/layout/lb_card_color_overlay.xml b/v7/appcompat/res/values-ldrtl-v23/styles_base.xml
similarity index 80%
rename from v17/leanback/res/layout/lb_card_color_overlay.xml
rename to v7/appcompat/res/values-ldrtl-v23/styles_base.xml
index 45a40e1..cba56bd 100644
--- a/v17/leanback/res/layout/lb_card_color_overlay.xml
+++ b/v7/appcompat/res/values-ldrtl-v23/styles_base.xml
@@ -15,7 +15,8 @@
limitations under the License.
-->
-<View
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+<resources>
+
+ <style name="Base.Widget.AppCompat.Spinner.Underlined" parent="android:Widget.Material.Spinner.Underlined" />
+
+</resources>
diff --git a/v7/appcompat/res/values-lo-rLA/strings.xml b/v7/appcompat/res/values-lo-rLA/strings.xml
index 3b93232..c95fd60 100644
--- a/v7/appcompat/res/values-lo-rLA/strings.xml
+++ b/v7/appcompat/res/values-lo-rLA/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"ແບ່ງປັນກັບ %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ແບ່ງປັນກັບ"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ເປີດ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ປິດ"</string>
</resources>
diff --git a/v7/appcompat/res/values-lt/strings.xml b/v7/appcompat/res/values-lt/strings.xml
index b070a2f..992910c 100644
--- a/v7/appcompat/res/values-lt/strings.xml
+++ b/v7/appcompat/res/values-lt/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Bendrinti naudojant „%s“"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bendrinti naudojant"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ĮJUNGTI"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"IŠJUNGTI"</string>
</resources>
diff --git a/v7/appcompat/res/values-lv/strings.xml b/v7/appcompat/res/values-lv/strings.xml
index 7c4ef4f..6700c87 100644
--- a/v7/appcompat/res/values-lv/strings.xml
+++ b/v7/appcompat/res/values-lv/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Kopīgot ar %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Kopīgot ar:"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"IESLĒGTS"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"IZSLĒGTS"</string>
</resources>
diff --git a/v7/appcompat/res/values-mk-rMK/strings.xml b/v7/appcompat/res/values-mk-rMK/strings.xml
index ac2b03e..a386996 100644
--- a/v7/appcompat/res/values-mk-rMK/strings.xml
+++ b/v7/appcompat/res/values-mk-rMK/strings.xml
@@ -38,4 +38,6 @@
<skip />
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Сподели со"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛУЧЕНО"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ИСКЛУЧЕНО"</string>
</resources>
diff --git a/v7/appcompat/res/values-ml-rIN/strings.xml b/v7/appcompat/res/values-ml-rIN/strings.xml
index 53f8e4b..292fcc0 100644
--- a/v7/appcompat/res/values-ml-rIN/strings.xml
+++ b/v7/appcompat/res/values-ml-rIN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s എന്നതുമായി പങ്കിടുക"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ഇവരുമായി പങ്കിടുക"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ഓൺ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ഓഫ്"</string>
</resources>
diff --git a/v7/appcompat/res/values-mn-rMN/strings.xml b/v7/appcompat/res/values-mn-rMN/strings.xml
index a89dc4d..75a9724 100644
--- a/v7/appcompat/res/values-mn-rMN/strings.xml
+++ b/v7/appcompat/res/values-mn-rMN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s-тай хуваалцах"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Хуваалцах"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ИДЭВХТЭЙ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ИДЭВХГҮЙ"</string>
</resources>
diff --git a/v7/appcompat/res/values-mr-rIN/strings.xml b/v7/appcompat/res/values-mr-rIN/strings.xml
index 1afbd81..76d42a9 100644
--- a/v7/appcompat/res/values-mr-rIN/strings.xml
+++ b/v7/appcompat/res/values-mr-rIN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s सह सामायिक करा"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"यांच्यासह सामायिक करा"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"चालू"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"बंद"</string>
</resources>
diff --git a/v7/appcompat/res/values-ms-rMY/strings.xml b/v7/appcompat/res/values-ms-rMY/strings.xml
index 9763618..75ffefb 100644
--- a/v7/appcompat/res/values-ms-rMY/strings.xml
+++ b/v7/appcompat/res/values-ms-rMY/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Kongsi dengan %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Kongsi dengan"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"HIDUP"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"MATI"</string>
</resources>
diff --git a/v7/appcompat/res/values-my-rMM/strings.xml b/v7/appcompat/res/values-my-rMM/strings.xml
index 936ac99..f8690aa 100644
--- a/v7/appcompat/res/values-my-rMM/strings.xml
+++ b/v7/appcompat/res/values-my-rMM/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ကို မျှဝေပါရန်"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"မျှဝေဖို့ ရွေးပါ"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"၉၉၉+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ဖွင့်"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ပိတ်"</string>
</resources>
diff --git a/v7/appcompat/res/values-nb/strings.xml b/v7/appcompat/res/values-nb/strings.xml
index 483f7077..10f3024 100644
--- a/v7/appcompat/res/values-nb/strings.xml
+++ b/v7/appcompat/res/values-nb/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Del med %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Del med"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"PÅ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"AV"</string>
</resources>
diff --git a/v7/appcompat/res/values-ne-rNP/strings.xml b/v7/appcompat/res/values-ne-rNP/strings.xml
index 4a08778..a841f21 100644
--- a/v7/appcompat/res/values-ne-rNP/strings.xml
+++ b/v7/appcompat/res/values-ne-rNP/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s सँग साझेदारी गर्नुहोस्"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"साझेदारी गर्नुहोस्..."</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"९९९+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"सक्रिय गर्नुहोस्"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"निष्क्रिय पार्नुहोस्"</string>
</resources>
diff --git a/v7/appcompat/res/values-nl/strings.xml b/v7/appcompat/res/values-nl/strings.xml
index 38a7607..adb0f0e 100644
--- a/v7/appcompat/res/values-nl/strings.xml
+++ b/v7/appcompat/res/values-nl/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Delen met %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Delen met"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"AAN"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"UIT"</string>
</resources>
diff --git a/v7/appcompat/res/values-pa-rIN/strings.xml b/v7/appcompat/res/values-pa-rIN/strings.xml
index af87fdf..45b703a 100644
--- a/v7/appcompat/res/values-pa-rIN/strings.xml
+++ b/v7/appcompat/res/values-pa-rIN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ਨਾਲ ਸ਼ੇਅਰ ਕਰੋ"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ਇਸ ਨਾਲ ਸ਼ੇਅਰ ਕਰੋ"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ਤੇ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ਬੰਦ"</string>
</resources>
diff --git a/v7/appcompat/res/values-pl/strings.xml b/v7/appcompat/res/values-pl/strings.xml
index 72fa439..166986a 100644
--- a/v7/appcompat/res/values-pl/strings.xml
+++ b/v7/appcompat/res/values-pl/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Udostępnij dla %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Udostępnij dla"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"WŁ."</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"WYŁ."</string>
</resources>
diff --git a/v7/appcompat/res/values-pt-rBR/strings.xml b/v7/appcompat/res/values-pt-rBR/strings.xml
index dfcfce8..06cf8d9 100644
--- a/v7/appcompat/res/values-pt-rBR/strings.xml
+++ b/v7/appcompat/res/values-pt-rBR/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartilhar com %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartilhar com"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ATIVAR"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DESATIVAR"</string>
</resources>
diff --git a/v7/appcompat/res/values-pt-rPT/strings.xml b/v7/appcompat/res/values-pt-rPT/strings.xml
index d76c5c8..176aade 100644
--- a/v7/appcompat/res/values-pt-rPT/strings.xml
+++ b/v7/appcompat/res/values-pt-rPT/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Partilhar com %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Partilhar com"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"+999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ATIVADO"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DESATIVADO"</string>
</resources>
diff --git a/v7/appcompat/res/values-pt/strings.xml b/v7/appcompat/res/values-pt/strings.xml
index dfcfce8..06cf8d9 100644
--- a/v7/appcompat/res/values-pt/strings.xml
+++ b/v7/appcompat/res/values-pt/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Compartilhar com %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Compartilhar com"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ATIVAR"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DESATIVAR"</string>
</resources>
diff --git a/v7/appcompat/res/values-ro/strings.xml b/v7/appcompat/res/values-ro/strings.xml
index 55538ee..9879823 100644
--- a/v7/appcompat/res/values-ro/strings.xml
+++ b/v7/appcompat/res/values-ro/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Trimiteți la %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Trimiteți la"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"˃999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAȚI"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"DEZACTIVAȚI"</string>
</resources>
diff --git a/v7/appcompat/res/values-ru/strings.xml b/v7/appcompat/res/values-ru/strings.xml
index 03a2c8f..08ed085 100644
--- a/v7/appcompat/res/values-ru/strings.xml
+++ b/v7/appcompat/res/values-ru/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Открыть доступ пользователю %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Открыть доступ"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">">999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛ."</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ОТКЛ."</string>
</resources>
diff --git a/v7/appcompat/res/values-si-rLK/strings.xml b/v7/appcompat/res/values-si-rLK/strings.xml
index a03b5bd..47d7dc6 100644
--- a/v7/appcompat/res/values-si-rLK/strings.xml
+++ b/v7/appcompat/res/values-si-rLK/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s සමඟ බෙදාගන්න"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"සමඟ බෙදාගන්න"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ක්රියාත්මකයි"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ක්රියාවිරහිතයි"</string>
</resources>
diff --git a/v7/appcompat/res/values-sk/strings.xml b/v7/appcompat/res/values-sk/strings.xml
index f7f0b81..b7a2dc0 100644
--- a/v7/appcompat/res/values-sk/strings.xml
+++ b/v7/appcompat/res/values-sk/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Zdieľať pomocou %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Zdieľať pomocou"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ZAP."</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"VYP."</string>
</resources>
diff --git a/v7/appcompat/res/values-sl/strings.xml b/v7/appcompat/res/values-sl/strings.xml
index 7d5f0bf..173180f 100644
--- a/v7/appcompat/res/values-sl/strings.xml
+++ b/v7/appcompat/res/values-sl/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Deljenje z:"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Deljenje z"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"VKLOPLJENO"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"IZKLOPLJENO"</string>
</resources>
diff --git a/v7/appcompat/res/values-sq-rAL/strings.xml b/v7/appcompat/res/values-sq-rAL/strings.xml
index 68689a6..758d941 100644
--- a/v7/appcompat/res/values-sq-rAL/strings.xml
+++ b/v7/appcompat/res/values-sq-rAL/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Shpërnda publikisht me %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Shpërnda publikisht me"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"AKTIV"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"JOAKTIV"</string>
</resources>
diff --git a/v7/appcompat/res/values-sr/strings.xml b/v7/appcompat/res/values-sr/strings.xml
index e147d75..a54af9b 100644
--- a/v7/appcompat/res/values-sr/strings.xml
+++ b/v7/appcompat/res/values-sr/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Дели са апликацијом %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Дели са"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">">999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"УКЉУЧИ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ИСКЉУЧИ"</string>
</resources>
diff --git a/v7/appcompat/res/values-sv/strings.xml b/v7/appcompat/res/values-sv/strings.xml
index feebdb2ba..a0c9cc0 100644
--- a/v7/appcompat/res/values-sv/strings.xml
+++ b/v7/appcompat/res/values-sv/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Dela med %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Dela med"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">">999"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"PÅ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"AV"</string>
</resources>
diff --git a/v7/appcompat/res/values-sw/strings.xml b/v7/appcompat/res/values-sw/strings.xml
index 25c4039..f1382ba 100644
--- a/v7/appcompat/res/values-sw/strings.xml
+++ b/v7/appcompat/res/values-sw/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Shiriki na %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Shiriki na:"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"IMEWASHWA"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"IMEZIMWA"</string>
</resources>
diff --git a/v7/appcompat/res/values-ta-rIN/strings.xml b/v7/appcompat/res/values-ta-rIN/strings.xml
index 099526b..a31eb25 100644
--- a/v7/appcompat/res/values-ta-rIN/strings.xml
+++ b/v7/appcompat/res/values-ta-rIN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s உடன் பகிர்"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"இதனுடன் பகிர்"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"இயக்கு"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"முடக்கு"</string>
</resources>
diff --git a/v7/appcompat/res/values-te-rIN/strings.xml b/v7/appcompat/res/values-te-rIN/strings.xml
index 8ea231a4..2f6695d 100644
--- a/v7/appcompat/res/values-te-rIN/strings.xml
+++ b/v7/appcompat/res/values-te-rIN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%sతో భాగస్వామ్యం చేయి"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"వీరితో భాగస్వామ్యం చేయి"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"ఆన్ చేయి"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ఆఫ్ చేయి"</string>
</resources>
diff --git a/v7/appcompat/res/values-th/strings.xml b/v7/appcompat/res/values-th/strings.xml
index cc5ab0a..b77ee55 100644
--- a/v7/appcompat/res/values-th/strings.xml
+++ b/v7/appcompat/res/values-th/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"แชร์กับ %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"แชร์กับ"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"เปิด"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ปิด"</string>
</resources>
diff --git a/v7/appcompat/res/values-tl/strings.xml b/v7/appcompat/res/values-tl/strings.xml
index aa7169f..73e1b2f 100644
--- a/v7/appcompat/res/values-tl/strings.xml
+++ b/v7/appcompat/res/values-tl/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Ibahagi sa/kay %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Ibahagi sa/kay"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"I-ON"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"I-OFF"</string>
</resources>
diff --git a/v7/appcompat/res/values-tr/strings.xml b/v7/appcompat/res/values-tr/strings.xml
index b111b6a..56aecf6 100644
--- a/v7/appcompat/res/values-tr/strings.xml
+++ b/v7/appcompat/res/values-tr/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="abc_action_mode_done" msgid="4076576682505996667">"Bitti"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Tamamlandı"</string>
<string name="abc_action_bar_home_description" msgid="4600421777120114993">"Ana ekrana git"</string>
<string name="abc_action_bar_up_description" msgid="1594238315039666878">"Yukarı git"</string>
<string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Diğer seçenekler"</string>
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ile paylaş"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Şununla paylaş"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"AÇ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"KAPAT"</string>
</resources>
diff --git a/v7/appcompat/res/values-uk/strings.xml b/v7/appcompat/res/values-uk/strings.xml
index ff08b47..5e81c70 100644
--- a/v7/appcompat/res/values-uk/strings.xml
+++ b/v7/appcompat/res/values-uk/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Надіслати через %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Надіслати через"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"УВІМК."</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"ВИМК."</string>
</resources>
diff --git a/v7/appcompat/res/values-ur-rPK/strings.xml b/v7/appcompat/res/values-ur-rPK/strings.xml
index 5196476..7972fe6 100644
--- a/v7/appcompat/res/values-ur-rPK/strings.xml
+++ b/v7/appcompat/res/values-ur-rPK/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s کے ساتھ اشتراک کریں"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"اشتراک کریں مع"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"آن"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"آف"</string>
</resources>
diff --git a/v7/appcompat/res/values-uz-rUZ/strings.xml b/v7/appcompat/res/values-uz-rUZ/strings.xml
index aa222b6..4a713a9 100644
--- a/v7/appcompat/res/values-uz-rUZ/strings.xml
+++ b/v7/appcompat/res/values-uz-rUZ/strings.xml
@@ -36,4 +36,6 @@
<skip />
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bo‘lishish:"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"YONIQ"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"O‘CHIQ"</string>
</resources>
diff --git a/v7/appcompat/res/values-v17/styles_rtl.xml b/v7/appcompat/res/values-v17/styles_rtl.xml
index 85d1bd4..b3753b7 100644
--- a/v7/appcompat/res/values-v17/styles_rtl.xml
+++ b/v7/appcompat/res/values-v17/styles_rtl.xml
@@ -47,7 +47,12 @@
<item name="android:paddingEnd">8dp</item>
</style>
- <style name="RtlOverlay.Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton.Overflow">
+ <style name="RtlUnderlay.Widget.AppCompat.ActionButton" parent="android:Widget">
+ <item name="android:paddingStart">12dp</item>
+ <item name="android:paddingEnd">12dp</item>
+ </style>
+
+ <style name="RtlUnderlay.Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton">
<item name="android:paddingStart">@dimen/abc_action_bar_overflow_padding_start_material</item>
<item name="android:paddingEnd">@dimen/abc_action_bar_overflow_padding_end_material</item>
</style>
@@ -73,4 +78,4 @@
<item name="android:textAlignment">viewStart</item>
</style>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/v7/appcompat/res/values-v21/styles_base.xml b/v7/appcompat/res/values-v21/styles_base.xml
index 47681f2..bf21d77 100644
--- a/v7/appcompat/res/values-v21/styles_base.xml
+++ b/v7/appcompat/res/values-v21/styles_base.xml
@@ -113,7 +113,7 @@
<style name="Base.Widget.AppCompat.Spinner" parent="android:Widget.Material.Spinner" />
- <style name="Base.Widget.AppCompat.Spinner.Underlined" parent="android:Widget.Material.Spinner.Underlined" />
+ <!-- Base.Widget.AppCompat.Spinner.Underlined is overridden in ldltr-v21 and v23 -->
<style name="Base.Widget.AppCompat.ListView" parent="android:Widget.Material.ListView" />
<style name="Base.Widget.AppCompat.ListView.Menu" />
@@ -166,12 +166,18 @@
parent="android:TextAppearance.Material.SearchResult.Subtitle">
</style>
- <style name="Base.Widget.AppCompat.AutoCompleteTextView" parent="android:Widget.Material.AutoCompleteTextView" />
+ <style name="Base.Widget.AppCompat.AutoCompleteTextView" parent="android:Widget.Material.AutoCompleteTextView">
+ <item name="android:background">?attr/editTextBackground</item>
+ </style>
- <style name="Base.Widget.AppCompat.EditText" parent="android:Widget.Material.EditText" />
+ <style name="Base.Widget.AppCompat.EditText" parent="android:Widget.Material.EditText">
+ <item name="android:background">?attr/editTextBackground</item>
+ </style>
<style name="Base.Widget.AppCompat.RatingBar" parent="android:Widget.Material.RatingBar" />
+ <style name="Base.Widget.AppCompat.SeekBar" parent="android:Widget.Material.SeekBar" />
+
<style name="Base.Widget.AppCompat.Button" parent="android:Widget.Material.Button" />
<style name="Base.Widget.AppCompat.Button.Small" parent="android:Widget.Material.Button.Small" />
@@ -186,6 +192,8 @@
<style name="Base.Widget.AppCompat.CompoundButton.RadioButton" parent="android:Widget.Material.CompoundButton.RadioButton" />
+ <style name="Base.Widget.AppCompat.ImageButton" parent="android:Widget.Material.ImageButton" />
+
<!-- Progress Bar -->
<style name="Base.Widget.AppCompat.ProgressBar.Horizontal"
diff --git a/v7/appcompat/res/values-v21/themes_base.xml b/v7/appcompat/res/values-v21/themes_base.xml
index 9d193d5..6c2aa26 100644
--- a/v7/appcompat/res/values-v21/themes_base.xml
+++ b/v7/appcompat/res/values-v21/themes_base.xml
@@ -48,8 +48,6 @@
<item name="actionBarDivider">?android:attr/actionBarDivider</item>
<item name="actionBarItemBackground">@drawable/abc_action_bar_item_background_material</item>
<item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
- <item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
- <item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
<item name="actionModeBackground">?android:attr/actionModeBackground</item>
<item name="actionModeCloseDrawable">?android:attr/actionModeCloseDrawable</item>
<item name="actionOverflowButtonStyle">?android:attr/actionOverflowButtonStyle</item>
@@ -71,12 +69,10 @@
<item name="listChoiceBackgroundIndicator">?android:attr/listChoiceBackgroundIndicator</item>
<!-- Copy the platform default styles for the AppCompat widgets -->
- <item name="autoCompleteTextViewStyle">?android:attr/autoCompleteTextViewStyle</item>
<item name="buttonStyle">?android:attr/buttonStyle</item>
<item name="buttonStyleSmall">?android:attr/buttonStyleSmall</item>
<item name="checkboxStyle">?android:attr/checkboxStyle</item>
<item name="checkedTextViewStyle">?android:attr/checkedTextViewStyle</item>
- <item name="editTextStyle">?android:attr/editTextStyle</item>
<item name="radioButtonStyle">?android:attr/radioButtonStyle</item>
<item name="ratingBarStyle">?android:attr/ratingBarStyle</item>
<item name="spinnerStyle">?android:attr/spinnerStyle</item>
@@ -97,8 +93,6 @@
<item name="actionBarDivider">?android:attr/actionBarDivider</item>
<item name="actionBarItemBackground">@drawable/abc_action_bar_item_background_material</item>
<item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
- <item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
- <item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
<item name="actionModeBackground">?android:attr/actionModeBackground</item>
<item name="actionModeCloseDrawable">?android:attr/actionModeCloseDrawable</item>
<item name="actionOverflowButtonStyle">?android:attr/actionOverflowButtonStyle</item>
@@ -120,12 +114,10 @@
<item name="listChoiceBackgroundIndicator">?android:attr/listChoiceBackgroundIndicator</item>
<!-- Copy the platform default styles for the AppCompat widgets -->
- <item name="autoCompleteTextViewStyle">?android:attr/autoCompleteTextViewStyle</item>
<item name="buttonStyle">?android:attr/buttonStyle</item>
<item name="buttonStyleSmall">?android:attr/buttonStyleSmall</item>
<item name="checkboxStyle">?android:attr/checkboxStyle</item>
<item name="checkedTextViewStyle">?android:attr/checkedTextViewStyle</item>
- <item name="editTextStyle">?android:attr/editTextStyle</item>
<item name="radioButtonStyle">?android:attr/radioButtonStyle</item>
<item name="ratingBarStyle">?android:attr/ratingBarStyle</item>
<item name="spinnerStyle">?android:attr/spinnerStyle</item>
diff --git a/v7/appcompat/res/values-v23/themes_base.xml b/v7/appcompat/res/values-v23/themes_base.xml
index becb1f2..276a3c6 100644
--- a/v7/appcompat/res/values-v23/themes_base.xml
+++ b/v7/appcompat/res/values-v23/themes_base.xml
@@ -23,6 +23,9 @@
<style name="Base.V23.Theme.AppCompat" parent="Base.V22.Theme.AppCompat">
<!-- We can use the platform drawable on v23+ -->
<item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <!-- We can use the platform styles on v23+ -->
+ <item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
+ <item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
<item name="controlBackground">@drawable/abc_control_background_material</item>
</style>
@@ -30,6 +33,9 @@
<style name="Base.V23.Theme.AppCompat.Light" parent="Base.V22.Theme.AppCompat.Light">
<!-- We can use the platform drawable on v23+ -->
<item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <!-- We can use the platform styles on v23+ -->
+ <item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
+ <item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
<item name="controlBackground">@drawable/abc_control_background_material</item>
</style>
diff --git a/v7/appcompat/res/values-vi/strings.xml b/v7/appcompat/res/values-vi/strings.xml
index 8190bc0..ec24827 100644
--- a/v7/appcompat/res/values-vi/strings.xml
+++ b/v7/appcompat/res/values-vi/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Chia sẻ với %s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Chia sẻ với"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"BẬT"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"TẮT"</string>
</resources>
diff --git a/v7/appcompat/res/values-xlarge/dimens.xml b/v7/appcompat/res/values-xlarge/dimens.xml
index 3eb2962..0dd244a 100644
--- a/v7/appcompat/res/values-xlarge/dimens.xml
+++ b/v7/appcompat/res/values-xlarge/dimens.xml
@@ -24,17 +24,12 @@
<!-- Minimum width of the search view text entry area. -->
<dimen name="abc_search_view_text_min_width">192dip</dimen>
- <!-- The platform's desired fixed width for a dialog along the major axis
- (the screen is in landscape). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_width_major">50%</item>
- <!-- The platform's desired fixed width for a dialog along the minor axis
- (the screen is in portrait). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_width_minor">70%</item>
- <!-- The platform's desired fixed height for a dialog along the major axis
- (the screen is in portrait). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_height_major">60%</item>
- <!-- The platform's desired fixed height for a dialog along the minor axis
- (the screen is in landscape). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_height_minor">90%</item>
+ <item type="dimen" name="abc_dialog_fixed_width_major">50%</item>
+ <item type="dimen" name="abc_dialog_fixed_width_minor">70%</item>
+ <item type="dimen" name="abc_dialog_fixed_height_major">60%</item>
+ <item type="dimen" name="abc_dialog_fixed_height_minor">90%</item>
+
+ <item type="dimen" name="abc_dialog_min_width_major">45%</item>
+ <item type="dimen" name="abc_dialog_min_width_minor">72%</item>
</resources>
diff --git a/v7/appcompat/res/values-zh-rCN/strings.xml b/v7/appcompat/res/values-zh-rCN/strings.xml
index b0fbc2f..8ac28b7 100644
--- a/v7/appcompat/res/values-zh-rCN/strings.xml
+++ b/v7/appcompat/res/values-zh-rCN/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"通过%s分享"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"分享方式"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"开启"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"关闭"</string>
</resources>
diff --git a/v7/appcompat/res/values-zh-rHK/strings.xml b/v7/appcompat/res/values-zh-rHK/strings.xml
index 2c46334..91d3289 100644
--- a/v7/appcompat/res/values-zh-rHK/strings.xml
+++ b/v7/appcompat/res/values-zh-rHK/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"與「%s」分享"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"分享對象"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999 +"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"開啟"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"關閉"</string>
</resources>
diff --git a/v7/appcompat/res/values-zh-rTW/strings.xml b/v7/appcompat/res/values-zh-rTW/strings.xml
index bfabf5a..45fea16 100644
--- a/v7/appcompat/res/values-zh-rTW/strings.xml
+++ b/v7/appcompat/res/values-zh-rTW/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"與「%s」分享"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"選擇分享對象"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"開啟"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"關閉"</string>
</resources>
diff --git a/v7/appcompat/res/values-zu/strings.xml b/v7/appcompat/res/values-zu/strings.xml
index edc265d..932624f 100644
--- a/v7/appcompat/res/values-zu/strings.xml
+++ b/v7/appcompat/res/values-zu/strings.xml
@@ -34,4 +34,6 @@
<string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Yabelana no-%s"</string>
<string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Yabelana no-"</string>
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+ <string name="abc_capital_on" msgid="3405795526292276155">"VULIWE"</string>
+ <string name="abc_capital_off" msgid="121134116657445385">"VALIWE"</string>
</resources>
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index 040bea1..83cb1b2 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -239,6 +239,9 @@
<!-- EditText background drawable. -->
<attr name="editTextBackground" format="reference" />
+ <!-- ImageButton background drawable. -->
+ <attr name="imageButtonStyle" format="reference" />
+
<!-- ============================ -->
<!-- SearchView styles and assets -->
<!-- ============================ -->
@@ -371,6 +374,8 @@
<attr name="radioButtonStyle" format="reference" />
<!-- Default RatingBar style. -->
<attr name="ratingBarStyle" format="reference" />
+ <!-- Default SeekBar style. -->
+ <attr name="seekBarStyle" format="reference" />
<!-- Default Spinner style. -->
<attr name="spinnerStyle" format="reference" />
<!-- Default style for the Switch widget. -->
@@ -681,6 +686,8 @@
<attr name="android:popupBackground" />
<!-- Width of the dropdown in spinnerMode="dropdown". -->
<attr name="android:dropDownWidth" />
+ <!-- Reference to an array resource that will populate the Spinner. -->
+ <attr name="android:entries" />
</declare-styleable>
<declare-styleable name="SearchView">
@@ -931,6 +938,10 @@
<attr name="android:textStyle" />
<attr name="android:typeface" />
<attr name="textAllCaps" />
+ <attr name="android:shadowColor"/>
+ <attr name="android:shadowDy"/>
+ <attr name="android:shadowDx"/>
+ <attr name="android:shadowRadius"/>
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -943,4 +954,11 @@
<attr name="listItemLayout" format="reference" />
</declare-styleable>
+ <!-- @hide -->
+ <declare-styleable name="ButtonBarLayout">
+ <!-- Whether to automatically stack the buttons when there is not
+ enough space to lay them out side-by-side. -->
+ <attr name="allowStacking" format="boolean" />
+ </declare-styleable>
+
</resources>
diff --git a/v7/appcompat/res/values/bools.xml b/v7/appcompat/res/values/bools.xml
index 79a5035..3508cf3 100644
--- a/v7/appcompat/res/values/bools.xml
+++ b/v7/appcompat/res/values/bools.xml
@@ -21,4 +21,8 @@
<bool name="abc_action_bar_expanded_action_views_exclusive">true</bool>
<bool name="abc_config_showMenuShortcutsWhenKeyboardPresent">false</bool>
+
+ <!-- Whether to allow vertically stacked button bars. This is disabled for
+ configurations with a small (e.g. less than 320dp) screen height. -->
+ <bool name="abc_allow_stacked_button_bar">false</bool>
</resources>
diff --git a/v7/appcompat/res/values/colors_material.xml b/v7/appcompat/res/values/colors_material.xml
index cf30f0dd..70fd21d 100644
--- a/v7/appcompat/res/values/colors_material.xml
+++ b/v7/appcompat/res/values/colors_material.xml
@@ -30,8 +30,8 @@
<color name="primary_dark_material_dark">@android:color/black</color>
<color name="primary_dark_material_light">@color/material_grey_600</color>
- <!-- 26% white (foreground) -->
- <color name="ripple_material_dark">#42ffffff</color>
+ <!-- 20% white (foreground) -->
+ <color name="ripple_material_dark">#33ffffff</color>
<!-- 12% black (foreground) -->
<color name="ripple_material_light">#1f000000</color>
diff --git a/v7/appcompat/res/values/dimens.xml b/v7/appcompat/res/values/dimens.xml
index 06f1a06..37130e3 100644
--- a/v7/appcompat/res/values/dimens.xml
+++ b/v7/appcompat/res/values/dimens.xml
@@ -44,19 +44,18 @@
<!-- Width of the icon in a dropdown list -->
<dimen name="abc_dropdownitem_icon_width">32dip</dimen>
-
<!-- The platform's desired fixed width for a dialog along the major axis
(the screen is in landscape). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_width_major">320dp</item>
+ <item type="dimen" name="abc_dialog_fixed_width_major">320dp</item>
<!-- The platform's desired fixed width for a dialog along the minor axis
(the screen is in portrait). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_width_minor">320dp</item>
+ <item type="dimen" name="abc_dialog_fixed_width_minor">320dp</item>
<!-- The platform's desired fixed height for a dialog along the major axis
(the screen is in portrait). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_height_major">80%</item>
+ <item type="dimen" name="abc_dialog_fixed_height_major">80%</item>
<!-- The platform's desired fixed height for a dialog along the minor axis
(the screen is in landscape). This may be either a fraction or a dimension.-->
- <item type="dimen" name="dialog_fixed_height_minor">100%</item>
+ <item type="dimen" name="abc_dialog_fixed_height_minor">100%</item>
<dimen name="abc_button_inset_vertical_material">6dp</dimen>
<dimen name="abc_button_inset_horizontal_material">@dimen/abc_control_inset_material</dimen>
@@ -87,6 +86,9 @@
<!-- Padding above and below selection dialog lists. -->
<dimen name="abc_dialog_list_padding_vertical_material">8dp</dimen>
+ <!-- Dialog padding minus control padding, used to fix alignment. -->
+ <dimen name="abc_select_dialog_padding_start_material">20dp</dimen>
+
<!-- The platform's desired minimum size for a dialog's width when it
is along the major axis (that is the screen is landscape). This may
be either a fraction or a dimension. -->
diff --git a/v7/appcompat/res/values/dimens_material.xml b/v7/appcompat/res/values/dimens_material.xml
index f67127c..357dc3e 100644
--- a/v7/appcompat/res/values/dimens_material.xml
+++ b/v7/appcompat/res/values/dimens_material.xml
@@ -68,4 +68,7 @@
<item name="abc_disabled_alpha_material_light" format="float" type="dimen">0.26</item>
<item name="abc_disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
+ <dimen name="abc_seekbar_track_background_height_material">2dp</dimen>
+ <dimen name="abc_seekbar_track_progress_height_material">2dp</dimen>
+
</resources>
diff --git a/v7/appcompat/res/values/strings.xml b/v7/appcompat/res/values/strings.xml
index a04b396..6e2a622 100644
--- a/v7/appcompat/res/values/strings.xml
+++ b/v7/appcompat/res/values/strings.xml
@@ -68,4 +68,9 @@
for most appropriate textual indicator of "more than X".
[CHAR LIMIT=4] -->
<string name="status_bar_notification_info_overflow">999+</string>
+
+ <!-- Default text for a button that can be toggled on and off. -->
+ <string name="abc_capital_on">ON</string>
+ <!-- Default text for a button that can be toggled on and off. -->
+ <string name="abc_capital_off">OFF</string>
</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index e10c01f..6c5c776 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -60,8 +60,7 @@
<style name="Widget.AppCompat.ActionButton.CloseMode" parent="Base.Widget.AppCompat.ActionButton.CloseMode" />
- <style name="Widget.AppCompat.ActionButton.Overflow"
- parent="RtlOverlay.Widget.AppCompat.ActionButton.Overflow" />
+ <style name="Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton.Overflow" />
<style name="Widget.AppCompat.ActionBar.TabBar"
parent="Base.Widget.AppCompat.ActionBar.TabBar">
@@ -218,12 +217,16 @@
<style name="Widget.AppCompat.ButtonBar.AlertDialog" parent="Base.Widget.AppCompat.ButtonBar.AlertDialog" />
+ <style name="Widget.AppCompat.ImageButton" parent="Base.Widget.AppCompat.ImageButton" />
+
<style name="Widget.AppCompat.TextView.SpinnerItem" parent="Base.Widget.AppCompat.TextView.SpinnerItem" />
<style name="AlertDialog.AppCompat" parent="Base.AlertDialog.AppCompat" />
<style name="AlertDialog.AppCompat.Light" parent="Base.AlertDialog.AppCompat.Light" />
+ <style name="Widget.AppCompat.SeekBar" parent="Base.Widget.AppCompat.SeekBar" />
+
<!-- Toolbar -->
<style name="Widget.AppCompat.Toolbar" parent="Base.Widget.AppCompat.Toolbar" />
diff --git a/v7/appcompat/res/values/styles_base.xml b/v7/appcompat/res/values/styles_base.xml
index d65b16f..b119217 100644
--- a/v7/appcompat/res/values/styles_base.xml
+++ b/v7/appcompat/res/values/styles_base.xml
@@ -60,10 +60,8 @@
<item name="backgroundSplit">?attr/colorPrimary</item>
</style>
- <style name="Base.Widget.AppCompat.ActionButton" parent="">
+ <style name="Base.Widget.AppCompat.ActionButton" parent="RtlUnderlay.Widget.AppCompat.ActionButton">
<item name="android:background">?attr/actionBarItemBackground</item>
- <item name="android:paddingLeft">12dip</item>
- <item name="android:paddingRight">12dip</item>
<item name="android:minWidth">@dimen/abc_action_button_min_width_material</item>
<item name="android:minHeight">@dimen/abc_action_button_min_height_material</item>
<item name="android:scaleType">center</item>
@@ -76,7 +74,7 @@
<item name="android:background">?attr/controlBackground</item>
</style>
- <style name="Base.Widget.AppCompat.ActionButton.Overflow">
+ <style name="Base.Widget.AppCompat.ActionButton.Overflow" parent="RtlUnderlay.Widget.AppCompat.ActionButton.Overflow">
<item name="android:src">@drawable/abc_ic_menu_moreoverflow_mtrl_alpha</item>
<item name="android:background">?attr/actionBarItemBackground</item>
<item name="android:contentDescription">@string/abc_action_menu_overflow_description</item>
@@ -386,6 +384,8 @@
<item name="android:background">?attr/controlBackground</item>
<item name="showText">false</item>
<item name="switchPadding">@dimen/abc_switch_padding</item>
+ <item name="android:textOn">@string/abc_capital_on</item>
+ <item name="android:textOff">@string/abc_capital_off</item>
</style>
<style name="Base.TextAppearance.AppCompat.Widget.Switch" parent="TextAppearance.AppCompat.Button" />
@@ -395,6 +395,16 @@
<item name="android:indeterminateDrawable">@drawable/abc_ratingbar_full_material</item>
</style>
+ <style name="Base.Widget.AppCompat.SeekBar" parent="android:Widget">
+ <item name="android:indeterminateOnly">false</item>
+ <item name="android:progressDrawable">@drawable/abc_seekbar_track_material</item>
+ <item name="android:indeterminateDrawable">@drawable/abc_seekbar_track_material</item>
+ <item name="android:thumb">@drawable/abc_seekbar_thumb_material</item>
+ <item name="android:focusable">true</item>
+ <item name="android:paddingLeft">16dip</item>
+ <item name="android:paddingRight">16dip</item>
+ </style>
+
<!-- Bordered ink button -->
<style name="Base.Widget.AppCompat.Button" parent="android:Widget">
<item name="android:background">@drawable/abc_btn_default_mtrl_shape</item>
@@ -434,6 +444,10 @@
<item name="android:minHeight">@dimen/abc_alert_dialog_button_bar_height</item>
</style>
+ <style name="Base.Widget.AppCompat.ImageButton" parent="android:Widget.ImageButton">
+ <item name="android:background">@drawable/abc_btn_default_mtrl_shape</item>
+ </style>
+
<style name="Base.Widget.AppCompat.TextView.SpinnerItem" parent="android:Widget.TextView.SpinnerItem">
<item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.TextView.SpinnerItem</item>
<item name="android:paddingLeft">8dp</item>
diff --git a/v7/appcompat/res/values/styles_rtl.xml b/v7/appcompat/res/values/styles_rtl.xml
index 876b396..a70aa30 100644
--- a/v7/appcompat/res/values/styles_rtl.xml
+++ b/v7/appcompat/res/values/styles_rtl.xml
@@ -47,7 +47,12 @@
<item name="android:paddingRight">8dp</item>
</style>
- <style name="RtlOverlay.Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton.Overflow">
+ <style name="RtlUnderlay.Widget.AppCompat.ActionButton" parent="android:Widget">
+ <item name="android:paddingLeft">12dp</item>
+ <item name="android:paddingRight">12dp</item>
+ </style>
+
+ <style name="RtlUnderlay.Widget.AppCompat.ActionButton.Overflow" parent="Base.Widget.AppCompat.ActionButton">
<item name="android:paddingLeft">@dimen/abc_action_bar_overflow_padding_start_material</item>
<item name="android:paddingRight">@dimen/abc_action_bar_overflow_padding_end_material</item>
</style>
@@ -71,4 +76,4 @@
<style name="RtlOverlay.DialogWindowTitle.AppCompat" parent="Base.DialogWindowTitle.AppCompat">
</style>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index d0dfca5..f8e0ac6 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -111,8 +111,10 @@
<!-- Base platform-dependent theme providing an action bar in a dark-themed activity. -->
<style name="Base.V7.Theme.AppCompat" parent="Platform.AppCompat">
+ <item name="windowNoTitle">false</item>
<item name="windowActionBar">true</item>
<item name="windowActionBarOverlay">false</item>
+ <item name="windowActionModeOverlay">false</item>
<item name="actionBarPopupTheme">@null</item>
<!-- Used by MediaRouter -->
@@ -189,7 +191,7 @@
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.AppCompat.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.AppCompat.Widget.PopupMenu.Small</item>
<item name="listPopupWindowStyle">@style/Widget.AppCompat.ListPopupWindow</item>
- <item name="dropDownListViewStyle">@style/Widget.AppCompat.ListView.DropDown</item>
+ <item name="dropDownListViewStyle">?android:attr/dropDownListViewStyle</item>
<!-- SearchView attributes -->
<item name="searchViewStyle">@style/Widget.AppCompat.SearchView</item>
@@ -229,12 +231,15 @@
<item name="switchStyle">@style/Widget.AppCompat.CompoundButton.Switch</item>
<item name="ratingBarStyle">@style/Widget.AppCompat.RatingBar</item>
+ <item name="seekBarStyle">@style/Widget.AppCompat.SeekBar</item>
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.AppCompat.Button</item>
<item name="buttonStyleSmall">@style/Widget.AppCompat.Button.Small</item>
<item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Widget.Button</item>
+ <item name="imageButtonStyle">@style/Widget.AppCompat.ImageButton</item>
+
<item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item>
<item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
<item name="buttonBarPositiveButtonStyle">?attr/buttonBarButtonStyle</item>
@@ -261,8 +266,10 @@
<!-- Base platform-dependent theme providing an action bar in a light-themed activity. -->
<style name="Base.V7.Theme.AppCompat.Light" parent="Platform.AppCompat.Light">
+ <item name="windowNoTitle">false</item>
<item name="windowActionBar">true</item>
<item name="windowActionBarOverlay">false</item>
+ <item name="windowActionModeOverlay">false</item>
<item name="actionBarPopupTheme">@null</item>
<!-- Used by MediaRouter -->
@@ -339,7 +346,7 @@
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.AppCompat.Light.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.AppCompat.Light.Widget.PopupMenu.Small</item>
<item name="listPopupWindowStyle">@style/Widget.AppCompat.ListPopupWindow</item>
- <item name="dropDownListViewStyle">@style/Widget.AppCompat.ListView.DropDown</item>
+ <item name="dropDownListViewStyle">?android:attr/dropDownListViewStyle</item>
<!-- SearchView attributes -->
<item name="searchViewStyle">@style/Widget.AppCompat.Light.SearchView</item>
@@ -379,12 +386,15 @@
<item name="switchStyle">@style/Widget.AppCompat.CompoundButton.Switch</item>
<item name="ratingBarStyle">@style/Widget.AppCompat.RatingBar</item>
+ <item name="seekBarStyle">@style/Widget.AppCompat.SeekBar</item>
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.AppCompat.Button</item>
<item name="buttonStyleSmall">@style/Widget.AppCompat.Button.Small</item>
<item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Widget.Button</item>
+ <item name="imageButtonStyle">@style/Widget.AppCompat.ImageButton</item>
+
<item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item>
<item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
<item name="buttonBarPositiveButtonStyle">?attr/buttonBarButtonStyle</item>
@@ -504,17 +514,17 @@
</style>
<style name="Base.Theme.AppCompat.Dialog.FixedSize">
- <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ <item name="windowFixedWidthMajor">@dimen/abc_dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/abc_dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/abc_dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/abc_dialog_fixed_height_minor</item>
</style>
<style name="Base.Theme.AppCompat.Light.Dialog.FixedSize">
- <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ <item name="windowFixedWidthMajor">@dimen/abc_dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/abc_dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/abc_dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/abc_dialog_fixed_height_minor</item>
</style>
<!-- We're not large, so redirect to Theme.AppCompat -->
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
index 6dceaf6..c15c531 100644
--- a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
+++ b/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
@@ -282,9 +282,11 @@
}
private void toggle() {
- if (mDrawerLayout.isDrawerVisible(GravityCompat.START)) {
+ int drawerLockMode = mDrawerLayout.getDrawerLockMode(GravityCompat.START);
+ if (mDrawerLayout.isDrawerVisible(GravityCompat.START)
+ && (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
mDrawerLayout.closeDrawer(GravityCompat.START);
- } else {
+ } else if (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
mDrawerLayout.openDrawer(GravityCompat.START);
}
}
diff --git a/v7/appcompat/src/android/support/v7/app/AlertController.java b/v7/appcompat/src/android/support/v7/app/AlertController.java
index 76c1670..5f8eb4b 100644
--- a/v7/appcompat/src/android/support/v7/app/AlertController.java
+++ b/v7/appcompat/src/android/support/v7/app/AlertController.java
@@ -21,20 +21,25 @@
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Handler;
import android.os.Message;
+import android.support.annotation.Nullable;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.NestedScrollView;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintTypedArray;
import android.text.TextUtils;
import android.util.TypedValue;
-import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
+import android.view.ViewStub;
import android.view.Window;
import android.view.WindowManager;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
@@ -46,7 +51,6 @@
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
-import android.widget.ScrollView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
@@ -84,7 +88,7 @@
private CharSequence mButtonNeutralText;
private Message mButtonNeutralMessage;
- private ScrollView mScrollView;
+ private NestedScrollView mScrollView;
private int mIconId = 0;
private Drawable mIcon;
@@ -159,19 +163,13 @@
}
}
- private static boolean shouldCenterSingleButton(Context context) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.alertDialogCenterButtons, outValue, true);
- return outValue.data != 0;
- }
-
public AlertController(Context context, AppCompatDialog di, Window window) {
mContext = context;
mDialog = di;
mWindow = window;
mHandler = new ButtonHandler(di);
- TypedArray a = context.obtainStyledAttributes(null, R.styleable.AlertDialog,
+ final TypedArray a = context.obtainStyledAttributes(null, R.styleable.AlertDialog,
R.attr.alertDialogStyle, 0);
mAlertDialogLayout = a.getResourceId(R.styleable.AlertDialog_android_layout, 0);
@@ -211,7 +209,6 @@
public void installContent() {
/* We use a custom title so never request a window title */
mDialog.supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
-
final int contentView = selectContentView();
mDialog.setContentView(contentView);
setupView();
@@ -368,6 +365,7 @@
/**
* @param attrId the attributeId of the theme-specific drawable
* to resolve the resourceId for.
+ *
* @return resId the resourceId of the theme-specific drawable
*/
public int getIconAttributeResId(int attrId) {
@@ -403,26 +401,194 @@
return mScrollView != null && mScrollView.executeKeyEvent(event);
}
- private void setupView() {
- final ViewGroup contentPanel = (ViewGroup) mWindow.findViewById(R.id.contentPanel);
- setupContent(contentPanel);
- final boolean hasButtons = setupButtons();
+ /**
+ * Resolves whether a custom or default panel should be used. Removes the
+ * default panel if a custom panel should be used. If the resolved panel is
+ * a view stub, inflates before returning.
+ *
+ * @param customPanel the custom panel
+ * @param defaultPanel the default panel
+ * @return the panel to use
+ */
+ @Nullable
+ private ViewGroup resolvePanel(@Nullable View customPanel, @Nullable View defaultPanel) {
+ if (customPanel == null) {
+ // Inflate the default panel, if needed.
+ if (defaultPanel instanceof ViewStub) {
+ defaultPanel = ((ViewStub) defaultPanel).inflate();
+ }
- final ViewGroup topPanel = (ViewGroup) mWindow.findViewById(R.id.topPanel);
- final TintTypedArray a = TintTypedArray.obtainStyledAttributes(mContext,
- null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
- final boolean hasTitle = setupTitle(topPanel);
+ return (ViewGroup) defaultPanel;
+ }
- final View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
- if (!hasButtons) {
- buttonPanel.setVisibility(View.GONE);
- final View spacer = mWindow.findViewById(R.id.textSpacerNoButtons);
- if (spacer != null) {
- spacer.setVisibility(View.VISIBLE);
+ // Remove the default panel entirely.
+ if (defaultPanel != null) {
+ final ViewParent parent = defaultPanel.getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(defaultPanel);
}
}
- final FrameLayout customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
+ // Inflate the custom panel, if needed.
+ if (customPanel instanceof ViewStub) {
+ customPanel = ((ViewStub) customPanel).inflate();
+ }
+
+ return (ViewGroup) customPanel;
+ }
+
+ private void setupView() {
+ final View parentPanel = mWindow.findViewById(R.id.parentPanel);
+ final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
+ final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
+ final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
+
+ // Install custom content before setting up the title or buttons so
+ // that we can handle panel overrides.
+ final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
+ setupCustomContent(customPanel);
+
+ final View customTopPanel = customPanel.findViewById(R.id.topPanel);
+ final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
+ final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
+
+ // Resolve the correct panels and remove the defaults, if needed.
+ final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
+ final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
+ final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
+
+ setupContent(contentPanel);
+ setupButtons(buttonPanel);
+ setupTitle(topPanel);
+
+ final boolean hasCustomPanel = customPanel != null
+ && customPanel.getVisibility() != View.GONE;
+ final boolean hasTopPanel = topPanel != null
+ && topPanel.getVisibility() != View.GONE;
+ final boolean hasButtonPanel = buttonPanel != null
+ && buttonPanel.getVisibility() != View.GONE;
+
+ // Only display the text spacer if we don't have buttons.
+ if (!hasButtonPanel) {
+ if (contentPanel != null) {
+ final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
+ if (spacer != null) {
+ spacer.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ if (hasTopPanel) {
+ // Only clip scrolling content to padding if we have a title.
+ if (mScrollView != null) {
+ mScrollView.setClipToPadding(true);
+ }
+ }
+
+ // Update scroll indicators as needed.
+ if (!hasCustomPanel) {
+ final View content = mListView != null ? mListView : mScrollView;
+ if (content != null) {
+ final int indicators = (hasTopPanel ? ViewCompat.SCROLL_INDICATOR_TOP : 0)
+ | (hasButtonPanel ? ViewCompat.SCROLL_INDICATOR_BOTTOM : 0);
+ setScrollIndicators(contentPanel, content, indicators,
+ ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_BOTTOM);
+ }
+ }
+
+ final ListView listView = mListView;
+ if (listView != null && mAdapter != null) {
+ listView.setAdapter(mAdapter);
+ final int checkedItem = mCheckedItem;
+ if (checkedItem > -1) {
+ listView.setItemChecked(checkedItem, true);
+ listView.setSelection(checkedItem);
+ }
+ }
+ }
+
+ private void setScrollIndicators(ViewGroup contentPanel, View content,
+ final int indicators, final int mask) {
+ // Set up scroll indicators (if present).
+ View indicatorUp = mWindow.findViewById(R.id.scrollIndicatorUp);
+ View indicatorDown = mWindow.findViewById(R.id.scrollIndicatorDown);
+
+ if (Build.VERSION.SDK_INT >= 23) {
+ // We're on Marshmallow so can rely on the View APIs
+ ViewCompat.setScrollIndicators(content, indicators, mask);
+ // We can also remove the compat indicator views
+ if (indicatorUp != null) {
+ contentPanel.removeView(indicatorUp);
+ }
+ if (indicatorDown != null) {
+ contentPanel.removeView(indicatorDown);
+ }
+ } else {
+ // First, remove the indicator views if we're not set to use them
+ if (indicatorUp != null && (indicators & ViewCompat.SCROLL_INDICATOR_TOP) == 0) {
+ contentPanel.removeView(indicatorUp);
+ indicatorUp = null;
+ }
+ if (indicatorDown != null && (indicators & ViewCompat.SCROLL_INDICATOR_BOTTOM) == 0) {
+ contentPanel.removeView(indicatorDown);
+ indicatorDown = null;
+ }
+
+ if (indicatorUp != null || indicatorDown != null) {
+ final View top = indicatorUp;
+ final View bottom = indicatorDown;
+
+ if (mMessage != null) {
+ // We're just showing the ScrollView, set up listener.
+ mScrollView.setOnScrollChangeListener(
+ new NestedScrollView.OnScrollChangeListener() {
+ @Override
+ public void onScrollChange(NestedScrollView v, int scrollX,
+ int scrollY,
+ int oldScrollX, int oldScrollY) {
+ manageScrollIndicators(v, top, bottom);
+ }
+ });
+ // Set up the indicators following layout.
+ mScrollView.post(new Runnable() {
+ @Override
+ public void run() {
+ manageScrollIndicators(mScrollView, top, bottom);
+ }
+ });
+ } else if (mListView != null) {
+ // We're just showing the AbsListView, set up listener.
+ mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {}
+
+ @Override
+ public void onScroll(AbsListView v, int firstVisibleItem,
+ int visibleItemCount, int totalItemCount) {
+ manageScrollIndicators(v, top, bottom);
+ }
+ });
+ // Set up the indicators following layout.
+ mListView.post(new Runnable() {
+ @Override
+ public void run() {
+ manageScrollIndicators(mListView, top, bottom);
+ }
+ });
+ } else {
+ // We don't have any content to scroll, remove the indicators.
+ if (top != null) {
+ contentPanel.removeView(top);
+ }
+ if (bottom != null) {
+ contentPanel.removeView(bottom);
+ }
+ }
+ }
+ }
+ }
+
+ private void setupCustomContent(ViewGroup customPanel) {
final View customView;
if (mView != null) {
customView = mView;
@@ -454,23 +620,9 @@
} else {
customPanel.setVisibility(View.GONE);
}
-
- final ListView listView = mListView;
- if (listView != null && mAdapter != null) {
- listView.setAdapter(mAdapter);
- final int checkedItem = mCheckedItem;
- if (checkedItem > -1) {
- listView.setItemChecked(checkedItem, true);
- listView.setSelection(checkedItem);
- }
- }
-
- a.recycle();
}
- private boolean setupTitle(ViewGroup topPanel) {
- boolean hasTitle = true;
-
+ private void setupTitle(ViewGroup topPanel) {
if (mCustomTitleView != null) {
// Add the custom title view directly to the topPanel layout
LayoutParams lp = new LayoutParams(
@@ -512,18 +664,17 @@
titleTemplate.setVisibility(View.GONE);
mIconView.setVisibility(View.GONE);
topPanel.setVisibility(View.GONE);
- hasTitle = false;
}
}
- return hasTitle;
}
private void setupContent(ViewGroup contentPanel) {
- mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
+ mScrollView = (NestedScrollView) mWindow.findViewById(R.id.scrollView);
mScrollView.setFocusable(false);
+ mScrollView.setNestedScrollingEnabled(false);
// Special case for users that only want to display a String
- mMessageView = (TextView) mWindow.findViewById(android.R.id.message);
+ mMessageView = (TextView) contentPanel.findViewById(android.R.id.message);
if (mMessageView == null) {
return;
}
@@ -546,12 +697,23 @@
}
}
- private boolean setupButtons() {
+ private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
+ if (upIndicator != null) {
+ upIndicator.setVisibility(
+ ViewCompat.canScrollVertically(v, -1) ? View.VISIBLE : View.INVISIBLE);
+ }
+ if (downIndicator != null) {
+ downIndicator.setVisibility(
+ ViewCompat.canScrollVertically(v, 1) ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+
+ private void setupButtons(ViewGroup buttonPanel) {
int BIT_BUTTON_POSITIVE = 1;
int BIT_BUTTON_NEGATIVE = 2;
int BIT_BUTTON_NEUTRAL = 4;
int whichButtons = 0;
- mButtonPositive = (Button) mWindow.findViewById(android.R.id.button1);
+ mButtonPositive = (Button) buttonPanel.findViewById(android.R.id.button1);
mButtonPositive.setOnClickListener(mButtonHandler);
if (TextUtils.isEmpty(mButtonPositiveText)) {
@@ -562,7 +724,7 @@
whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
}
- mButtonNegative = (Button) mWindow.findViewById(android.R.id.button2);
+ mButtonNegative = (Button) buttonPanel.findViewById(android.R.id.button2);
mButtonNegative.setOnClickListener(mButtonHandler);
if (TextUtils.isEmpty(mButtonNegativeText)) {
@@ -574,7 +736,7 @@
whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
}
- mButtonNeutral = (Button) mWindow.findViewById(android.R.id.button3);
+ mButtonNeutral = (Button) buttonPanel.findViewById(android.R.id.button3);
mButtonNeutral.setOnClickListener(mButtonHandler);
if (TextUtils.isEmpty(mButtonNeutralText)) {
@@ -586,28 +748,10 @@
whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
}
- if (shouldCenterSingleButton(mContext)) {
- /*
- * If we only have 1 button it should be centered on the layout and
- * expand to fill 50% of the available space.
- */
- if (whichButtons == BIT_BUTTON_POSITIVE) {
- centerButton(mButtonPositive);
- } else if (whichButtons == BIT_BUTTON_NEGATIVE) {
- centerButton(mButtonNegative);
- } else if (whichButtons == BIT_BUTTON_NEUTRAL) {
- centerButton(mButtonNeutral);
- }
+ final boolean hasButtons = whichButtons != 0;
+ if (!hasButtons) {
+ buttonPanel.setVisibility(View.GONE);
}
-
- return whichButtons != 0;
- }
-
- private void centerButton(Button button) {
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) button.getLayoutParams();
- params.gravity = Gravity.CENTER_HORIZONTAL;
- params.weight = 0.5f;
- button.setLayoutParams(params);
}
public static class AlertParams {
@@ -661,7 +805,6 @@
/**
* Called before the ListView is bound to an adapter.
- *
* @param listView The ListView that will be shown in the dialog.
*/
void onPrepareListView(ListView listView);
@@ -732,7 +875,7 @@
private void createListView(final AlertController dialog) {
final ListView listView = (ListView) mInflater.inflate(dialog.mListLayout, null);
- ListAdapter adapter;
+ final ListAdapter adapter;
if (mIsMultiChoice) {
if (mCursor == null) {
@@ -763,8 +906,8 @@
@Override
public void bindView(View view, Context context, Cursor cursor) {
- CheckedTextView text = (CheckedTextView) view
- .findViewById(android.R.id.text1);
+ CheckedTextView text = (CheckedTextView) view.findViewById(
+ android.R.id.text1);
text.setText(cursor.getString(mLabelIndex));
listView.setItemChecked(cursor.getPosition(),
cursor.getInt(mIsCheckedIndex) == 1);
@@ -779,14 +922,20 @@
};
}
} else {
- int layout = mIsSingleChoice
- ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;
- if (mCursor == null) {
- adapter = (mAdapter != null) ? mAdapter
- : new CheckedItemAdapter(mContext, layout, android.R.id.text1, mItems);
+ final int layout;
+ if (mIsSingleChoice) {
+ layout = dialog.mSingleChoiceItemLayout;
} else {
- adapter = new SimpleCursorAdapter(mContext, layout,
- mCursor, new String[]{mLabelColumn}, new int[]{android.R.id.text1});
+ layout = dialog.mListItemLayout;
+ }
+
+ if (mCursor != null) {
+ adapter = new SimpleCursorAdapter(mContext, layout, mCursor,
+ new String[] { mLabelColumn }, new int[] { android.R.id.text1 });
+ } else if (mAdapter != null) {
+ adapter = mAdapter;
+ } else {
+ adapter = new CheckedItemAdapter(mContext, layout, android.R.id.text1, mItems);
}
}
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
index b22e209..ef38511 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
@@ -175,7 +175,16 @@
public abstract MenuInflater getMenuInflater();
/**
- * Should be called from {@link Activity#onCreate Activity.onCreate()}
+ * Should be called from {@link Activity#onCreate Activity.onCreate()}.
+ *
+ * <p>This should be called before {@code super.onCreate()} as so:</p>
+ * <pre class="prettyprint">
+ * protected void onCreate(Bundle savedInstanceState) {
+ * getDelegate().onCreate(savedInstanceState);
+ * super.onCreate(savedInstanceState);
+ * // ...
+ * }
+ * </pre>
*/
public abstract void onCreate(Bundle savedInstanceState);
@@ -280,8 +289,8 @@
* <pre class="prettyprint">
* protected void onCreate(Bundle savedInstanceState) {
* getDelegate().installViewFactory();
- * super.onCreate(savedInstanceState);
* getDelegate().onCreate(savedInstanceState);
+ * super.onCreate(savedInstanceState);
*
* // ...
* }
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
index b8182e6..394cf60 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
@@ -18,15 +18,13 @@
import android.app.Activity;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
-import android.os.Bundle;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.WindowCallbackWrapper;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.widget.TintTypedArray;
import android.support.v7.view.ActionMode;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.WindowCallbackWrapper;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.widget.TintTypedArray;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
@@ -54,6 +52,8 @@
boolean mIsFloating;
// true if this activity has no title
boolean mWindowNoTitle;
+ // true if the theme has been read
+ boolean mThemeRead;
private CharSequence mTitle;
@@ -276,8 +276,9 @@
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
- return super.onMenuOpened(featureId, menu)
- || AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu);
+ super.onMenuOpened(featureId, menu);
+ AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu);
+ return true;
}
@Override
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
index f134c48..35e7ca3 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
@@ -17,7 +17,7 @@
package android.support.v7.app;
import android.content.Context;
-import android.support.v7.internal.view.SupportActionModeWrapper;
+import android.support.v7.view.SupportActionModeWrapper;
import android.view.ActionMode;
import android.view.Window;
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
index 54ec0ad..e147b7d 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
@@ -31,6 +31,8 @@
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v4.app.NavUtils;
+import android.support.v4.os.ParcelableCompat;
+import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.LayoutInflaterCompat;
import android.support.v4.view.LayoutInflaterFactory;
import android.support.v4.view.OnApplyWindowInsetsListener;
@@ -42,24 +44,21 @@
import android.support.v4.view.WindowInsetsCompat;
import android.support.v4.widget.PopupWindowCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.app.AppCompatViewInflater;
-import android.support.v7.internal.app.ToolbarActionBar;
-import android.support.v7.internal.app.WindowDecorActionBar;
-import android.support.v7.internal.view.ContextThemeWrapper;
-import android.support.v7.internal.view.StandaloneActionMode;
-import android.support.v7.internal.view.menu.ListMenuPresenter;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.widget.ActionBarContextView;
-import android.support.v7.internal.widget.ContentFrameLayout;
-import android.support.v7.internal.widget.DecorContentParent;
-import android.support.v7.internal.widget.FitWindowsViewGroup;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.ViewStubCompat;
-import android.support.v7.internal.widget.ViewUtils;
import android.support.v7.view.ActionMode;
+import android.support.v7.view.ContextThemeWrapper;
+import android.support.v7.view.StandaloneActionMode;
+import android.support.v7.view.menu.ListMenuPresenter;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPresenter;
+import android.support.v7.view.menu.MenuView;
+import android.support.v7.widget.ActionBarContextView;
+import android.support.v7.widget.AppCompatDrawableManager;
+import android.support.v7.widget.ContentFrameLayout;
+import android.support.v7.widget.DecorContentParent;
+import android.support.v7.widget.FitWindowsViewGroup;
import android.support.v7.widget.Toolbar;
+import android.support.v7.widget.ViewStubCompat;
+import android.support.v7.widget.ViewUtils;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.AttributeSet;
@@ -116,6 +115,8 @@
private PanelFeatureState[] mPanels;
private PanelFeatureState mPreparedPanel;
+ private boolean mLongPressBackDown;
+
private boolean mInvalidatePanelMenuPosted;
private int mInvalidatePanelMenuFeatures;
private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
@@ -461,6 +462,16 @@
((FrameLayout) decorContent).setForeground(null);
}
+ abcContent.setAttachListener(new ContentFrameLayout.OnAttachListener() {
+ @Override
+ public void onAttachedFromWindow() {}
+
+ @Override
+ public void onDetachedFromWindow() {
+ dismissPopups();
+ }
+ });
+
return subDecor;
}
@@ -865,9 +876,17 @@
onKeyUpPanel(Window.FEATURE_OPTIONS_PANEL, event);
return true;
case KeyEvent.KEYCODE_BACK:
+ final boolean wasLongPressBackDown = mLongPressBackDown;
+ mLongPressBackDown = false;
+
PanelFeatureState st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
if (st != null && st.isOpen) {
- closePanel(st, true);
+ if (!wasLongPressBackDown) {
+ // Certain devices allow opening the options menu via a long press of the
+ // back button. We should only close the open options menu if it wasn't
+ // opened via a long press gesture.
+ closePanel(st, true);
+ }
return true;
}
if (onBackPressed()) {
@@ -882,7 +901,14 @@
switch (keyCode) {
case KeyEvent.KEYCODE_MENU:
onKeyDownPanel(Window.FEATURE_OPTIONS_PANEL, event);
- // Break, and let this fall through to the original callback
+ // We need to return true here and not let it bubble up to the Window.
+ // For empty menus, PhoneWindow's KEYCODE_BACK handling will steals all events,
+ // not allowing the Activity to call onBackPressed().
+ return true;
+ case KeyEvent.KEYCODE_BACK:
+ // Certain devices allow opening the options menu via a long press of the back
+ // button. We keep a record of whether the last event is from a long press.
+ mLongPressBackDown = (event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
break;
}
@@ -1630,6 +1656,31 @@
return mSubDecor;
}
+ private void dismissPopups() {
+ if (mDecorContentParent != null) {
+ mDecorContentParent.dismissPopups();
+ }
+
+ if (mActionModePopup != null) {
+ mWindowDecor.removeCallbacks(mShowActionModePopup);
+ if (mActionModePopup.isShowing()) {
+ try {
+ mActionModePopup.dismiss();
+ } catch (IllegalArgumentException e) {
+ // Pre-v18, there are times when the Window will remove the popup before us.
+ // In these cases we need to swallow the resulting exception.
+ }
+ }
+ mActionModePopup = null;
+ }
+ endOnGoingFadeAnimation();
+
+ PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+ if (st != null && st.menu != null) {
+ st.menu.close();
+ }
+ }
+
/**
* Clears out internal reference when the action mode is destroyed.
*/
@@ -1924,32 +1975,35 @@
}
}
- private static SavedState readFromParcel(Parcel source) {
+ private static SavedState readFromParcel(Parcel source, ClassLoader loader) {
SavedState savedState = new SavedState();
savedState.featureId = source.readInt();
savedState.isOpen = source.readInt() == 1;
if (savedState.isOpen) {
- savedState.menuState = source.readBundle();
+ savedState.menuState = source.readBundle(loader);
}
return savedState;
}
public static final Parcelable.Creator<SavedState> CREATOR
- = new Parcelable.Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return readFromParcel(in);
- }
+ = ParcelableCompat.newCreator(
+ new ParcelableCompatCreatorCallbacks<SavedState>() {
+ @Override
+ public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+ return readFromParcel(in, loader);
+ }
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ });
}
}
- private class ListMenuDecorView extends FrameLayout {
+ private class ListMenuDecorView extends ContentFrameLayout {
public ListMenuDecorView(Context context) {
super(context);
}
@@ -1976,12 +2030,11 @@
@Override
public void setBackgroundResource(int resid) {
- setBackgroundDrawable(TintManager.getDrawable(getContext(), resid));
+ setBackgroundDrawable(AppCompatDrawableManager.get().getDrawable(getContext(), resid));
}
private boolean isOutOfBounds(int x, int y) {
return x < -5 || y < -5 || x > (getWidth() + 5) || y > (getHeight() + 5);
}
}
-
}
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java b/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java
new file mode 100644
index 0000000..a74623e
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.app;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.TypedArray;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.appcompat.R;
+import android.support.v7.view.ContextThemeWrapper;
+import android.support.v7.widget.AppCompatAutoCompleteTextView;
+import android.support.v7.widget.AppCompatButton;
+import android.support.v7.widget.AppCompatCheckBox;
+import android.support.v7.widget.AppCompatCheckedTextView;
+import android.support.v7.widget.AppCompatEditText;
+import android.support.v7.widget.AppCompatImageButton;
+import android.support.v7.widget.AppCompatImageView;
+import android.support.v7.widget.AppCompatMultiAutoCompleteTextView;
+import android.support.v7.widget.AppCompatRadioButton;
+import android.support.v7.widget.AppCompatRatingBar;
+import android.support.v7.widget.AppCompatSeekBar;
+import android.support.v7.widget.AppCompatSpinner;
+import android.support.v7.widget.AppCompatTextView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.InflateException;
+import android.view.View;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * This class is responsible for manually inflating our tinted widgets which are used on devices
+ * running {@link android.os.Build.VERSION_CODES#KITKAT KITKAT} or below. As such, this class
+ * should only be used when running on those devices.
+ * <p>This class two main responsibilities: the first is to 'inject' our tinted views in place of
+ * the framework versions in layout inflation; the second is backport the {@code android:theme}
+ * functionality for any inflated widgets. This include theme inheritance from it's parent.
+ */
+class AppCompatViewInflater {
+
+ private static final Class<?>[] sConstructorSignature = new Class[]{
+ Context.class, AttributeSet.class};
+ private static final int[] sOnClickAttrs = new int[]{android.R.attr.onClick};
+
+ private static final String LOG_TAG = "AppCompatViewInflater";
+
+ private static final Map<String, Constructor<? extends View>> sConstructorMap
+ = new ArrayMap<>();
+
+ private final Object[] mConstructorArgs = new Object[2];
+
+ public final View createView(View parent, final String name, @NonNull Context context,
+ @NonNull AttributeSet attrs, boolean inheritContext,
+ boolean readAndroidTheme, boolean readAppTheme) {
+ final Context originalContext = context;
+
+ // We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
+ // by using the parent's context
+ if (inheritContext && parent != null) {
+ context = parent.getContext();
+ }
+ if (readAndroidTheme || readAppTheme) {
+ // We then apply the theme on the context, if specified
+ context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
+ }
+
+ View view = null;
+
+ // We need to 'inject' our tint aware Views in place of the standard framework versions
+ switch (name) {
+ case "TextView":
+ view = new AppCompatTextView(context, attrs);
+ break;
+ case "ImageView":
+ view = new AppCompatImageView(context, attrs);
+ break;
+ case "Button":
+ view = new AppCompatButton(context, attrs);
+ break;
+ case "EditText":
+ view = new AppCompatEditText(context, attrs);
+ break;
+ case "Spinner":
+ view = new AppCompatSpinner(context, attrs);
+ break;
+ case "ImageButton":
+ view = new AppCompatImageButton(context, attrs);
+ break;
+ case "CheckBox":
+ view = new AppCompatCheckBox(context, attrs);
+ break;
+ case "RadioButton":
+ view = new AppCompatRadioButton(context, attrs);
+ break;
+ case "CheckedTextView":
+ view = new AppCompatCheckedTextView(context, attrs);
+ break;
+ case "AutoCompleteTextView":
+ view = new AppCompatAutoCompleteTextView(context, attrs);
+ break;
+ case "MultiAutoCompleteTextView":
+ view = new AppCompatMultiAutoCompleteTextView(context, attrs);
+ break;
+ case "RatingBar":
+ view = new AppCompatRatingBar(context, attrs);
+ break;
+ case "SeekBar":
+ view = new AppCompatSeekBar(context, attrs);
+ break;
+ }
+
+ if (view == null && originalContext != context) {
+ // If the original context does not equal our themed context, then we need to manually
+ // inflate it using the name so that android:theme takes effect.
+ view = createViewFromTag(context, name, attrs);
+ }
+
+ if (view != null) {
+ // If we have created a view, check it's android:onClick
+ checkOnClickListener(view, attrs);
+ }
+
+ return view;
+ }
+
+ private View createViewFromTag(Context context, String name, AttributeSet attrs) {
+ if (name.equals("view")) {
+ name = attrs.getAttributeValue(null, "class");
+ }
+
+ try {
+ mConstructorArgs[0] = context;
+ mConstructorArgs[1] = attrs;
+
+ if (-1 == name.indexOf('.')) {
+ // try the android.widget prefix first...
+ return createView(context, name, "android.widget.");
+ } else {
+ return createView(context, name, null);
+ }
+ } catch (Exception e) {
+ // We do not want to catch these, lets return null and let the actual LayoutInflater
+ // try
+ return null;
+ } finally {
+ // Don't retain references on context.
+ mConstructorArgs[0] = null;
+ mConstructorArgs[1] = null;
+ }
+ }
+
+ /**
+ * android:onClick doesn't handle views with a ContextWrapper context. This method
+ * backports new framework functionality to traverse the Context wrappers to find a
+ * suitable target.
+ */
+ private void checkOnClickListener(View view, AttributeSet attrs) {
+ final Context context = view.getContext();
+
+ if (!ViewCompat.hasOnClickListeners(view) || !(context instanceof ContextWrapper)) {
+ // Skip our compat functionality if: the view doesn't have an onClickListener,
+ // or the Context isn't a ContextWrapper
+ return;
+ }
+
+ final TypedArray a = context.obtainStyledAttributes(attrs, sOnClickAttrs);
+ final String handlerName = a.getString(0);
+ if (handlerName != null) {
+ view.setOnClickListener(new DeclaredOnClickListener(view, handlerName));
+ }
+ a.recycle();
+ }
+
+ private View createView(Context context, String name, String prefix)
+ throws ClassNotFoundException, InflateException {
+ Constructor<? extends View> constructor = sConstructorMap.get(name);
+
+ try {
+ if (constructor == null) {
+ // Class not found in the cache, see if it's real, and try to add it
+ Class<? extends View> clazz = context.getClassLoader().loadClass(
+ prefix != null ? (prefix + name) : name).asSubclass(View.class);
+
+ constructor = clazz.getConstructor(sConstructorSignature);
+ sConstructorMap.put(name, constructor);
+ }
+ constructor.setAccessible(true);
+ return constructor.newInstance(mConstructorArgs);
+ } catch (Exception e) {
+ // We do not want to catch these, lets return null and let the actual LayoutInflater
+ // try
+ return null;
+ }
+ }
+
+ /**
+ * Allows us to emulate the {@code android:theme} attribute for devices before L.
+ */
+ private static Context themifyContext(Context context, AttributeSet attrs,
+ boolean useAndroidTheme, boolean useAppTheme) {
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.View, 0, 0);
+ int themeId = 0;
+ if (useAndroidTheme) {
+ // First try reading android:theme if enabled
+ themeId = a.getResourceId(R.styleable.View_android_theme, 0);
+ }
+ if (useAppTheme && themeId == 0) {
+ // ...if that didn't work, try reading app:theme (for legacy reasons) if enabled
+ themeId = a.getResourceId(R.styleable.View_theme, 0);
+
+ if (themeId != 0) {
+ Log.i(LOG_TAG, "app:theme is now deprecated. "
+ + "Please move to using android:theme instead.");
+ }
+ }
+ a.recycle();
+
+ if (themeId != 0 && (!(context instanceof ContextThemeWrapper)
+ || ((ContextThemeWrapper) context).getThemeResId() != themeId)) {
+ // If the context isn't a ContextThemeWrapper, or it is but does not have
+ // the same theme as we need, wrap it in a new wrapper
+ context = new ContextThemeWrapper(context, themeId);
+ }
+ return context;
+ }
+
+ /**
+ * An implementation of OnClickListener that attempts to lazily load a
+ * named click handling method from a parent or ancestor context.
+ */
+ private static class DeclaredOnClickListener implements View.OnClickListener {
+ private final View mHostView;
+ private final String mMethodName;
+
+ private Method mResolvedMethod;
+ private Context mResolvedContext;
+
+ public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
+ mHostView = hostView;
+ mMethodName = methodName;
+ }
+
+ @Override
+ public void onClick(@NonNull View v) {
+ if (mResolvedMethod == null) {
+ resolveMethod(mHostView.getContext(), mMethodName);
+ }
+
+ try {
+ mResolvedMethod.invoke(mResolvedContext, v);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException(
+ "Could not execute non-public method for android:onClick", e);
+ } catch (InvocationTargetException e) {
+ throw new IllegalStateException(
+ "Could not execute method for android:onClick", e);
+ }
+ }
+
+ @NonNull
+ private void resolveMethod(@Nullable Context context, @NonNull String name) {
+ while (context != null) {
+ try {
+ if (!context.isRestricted()) {
+ final Method method = context.getClass().getMethod(mMethodName, View.class);
+ if (method != null) {
+ mResolvedMethod = method;
+ mResolvedContext = context;
+ return;
+ }
+ }
+ } catch (NoSuchMethodException e) {
+ // Failed to find method, keep searching up the hierarchy.
+ }
+
+ if (context instanceof ContextWrapper) {
+ context = ((ContextWrapper) context).getBaseContext();
+ } else {
+ // Can't search up the hierarchy, null out and fail.
+ context = null;
+ }
+ }
+
+ final int id = mHostView.getId();
+ final String idText = id == View.NO_ID ? "" : " with id '"
+ + mHostView.getContext().getResources().getResourceEntryName(id) + "'";
+ throw new IllegalStateException("Could not find method " + mMethodName
+ + "(View) in a parent or ancestor Context for android:onClick "
+ + "attribute defined on view " + mHostView.getClass() + idText);
+ }
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java b/v7/appcompat/src/android/support/v7/app/NavItemSelectedListener.java
similarity index 93%
rename from v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java
rename to v7/appcompat/src/android/support/v7/app/NavItemSelectedListener.java
index 41e684a..39b5bfe 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java
+++ b/v7/appcompat/src/android/support/v7/app/NavItemSelectedListener.java
@@ -15,17 +15,14 @@
*/
-package android.support.v7.internal.app;
+package android.support.v7.app;
-import android.support.v7.app.ActionBar;
import android.view.View;
import android.widget.AdapterView;
/**
* Wrapper to adapt the ActionBar.OnNavigationListener in an AdapterView.OnItemSelectedListener
* for use in Spinner widgets. Used by action bar implementations.
- *
- * @hide
*/
class NavItemSelectedListener implements AdapterView.OnItemSelectedListener {
private final ActionBar.OnNavigationListener mListener;
diff --git a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
index 689d47f..514ebef 100644
--- a/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompat.java
@@ -22,8 +22,6 @@
import android.os.Build;
import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v7.internal.app.NotificationCompatImpl21;
-import android.support.v7.internal.app.NotificationCompatImplBase;
/**
* An extension of {@link android.support.v4.app.NotificationCompat} which supports
diff --git a/v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImpl21.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
similarity index 92%
rename from v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImpl21.java
rename to v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
index a68ad81d..cfa8839 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImpl21.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImpl21.java
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package android.support.v7.internal.app;
+package android.support.v7.app;
import android.app.Notification;
import android.media.session.MediaSession;
import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
-/**
- * @hide
- */
-public class NotificationCompatImpl21 {
+class NotificationCompatImpl21 {
public static void addMediaStyle(NotificationBuilderWithBuilderAccessor b,
int[] actionsToShowInCompact,
diff --git a/v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImplBase.java b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImplBase.java
rename to v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
index c52290dc..2bd772c 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/NotificationCompatImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/NotificationCompatImplBase.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package android.support.v7.internal.app;
+package android.support.v7.app;
import android.app.Notification;
import android.app.PendingIntent;
@@ -23,9 +23,9 @@
import android.graphics.Bitmap;
import android.os.Build;
import android.os.SystemClock;
-import android.support.v7.appcompat.R;
import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
import android.support.v4.app.NotificationCompatBase;
+import android.support.v7.appcompat.R;
import android.util.TypedValue;
import android.view.View;
import android.widget.RemoteViews;
@@ -36,9 +36,8 @@
/**
* Helper class to generate MediaStyle notifications for pre-Lollipop platforms. Overrides
* contentView and bigContentView of the notification.
- * @hide
*/
-public class NotificationCompatImplBase {
+class NotificationCompatImplBase {
static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
static final int MAX_MEDIA_BUTTONS = 5;
@@ -173,6 +172,7 @@
// 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) {
+ contentView.setViewVisibility(R.id.icon, View.VISIBLE);
contentView.setImageViewBitmap(R.id.icon, largeIcon);
} else {
contentView.setViewVisibility(R.id.icon, View.GONE);
diff --git a/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java b/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
rename to v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
index cb8de47..aa1a0ae 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.app;
+package android.support.v7.app;
import android.content.Context;
import android.content.res.Configuration;
@@ -22,16 +22,14 @@
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatDelegate;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.WindowCallbackWrapper;
-import android.support.v7.internal.view.menu.ListMenuPresenter;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.widget.DecorToolbar;
-import android.support.v7.internal.widget.ToolbarWidgetWrapper;
+import android.support.v7.view.WindowCallbackWrapper;
+import android.support.v7.view.menu.ListMenuPresenter;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPresenter;
+import android.support.v7.widget.DecorToolbar;
import android.support.v7.widget.Toolbar;
+import android.support.v7.widget.ToolbarWidgetWrapper;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.KeyCharacterMap;
@@ -45,10 +43,7 @@
import java.util.ArrayList;
-/**
- * @hide
- */
-public class ToolbarActionBar extends ActionBar {
+class ToolbarActionBar extends ActionBar {
private DecorToolbar mDecorToolbar;
private boolean mToolbarMenuPrepared;
private Window.Callback mWindowCallback;
diff --git a/v7/appcompat/src/android/support/v7/app/TwilightManager.java b/v7/appcompat/src/android/support/v7/app/TwilightManager.java
index b17d578..e1731de 100644
--- a/v7/appcompat/src/android/support/v7/app/TwilightManager.java
+++ b/v7/appcompat/src/android/support/v7/app/TwilightManager.java
@@ -79,31 +79,27 @@
}
private Location getLastKnownLocation() {
- Location coarseLocation = null;
- Location fineLocation = null;
+ Location coarseLoc = null;
+ Location fineLoc = null;
int permission = PermissionChecker.checkSelfPermission(mContext,
- Manifest.permission.ACCESS_FINE_LOCATION);
+ Manifest.permission.ACCESS_COARSE_LOCATION);
if (permission == PermissionChecker.PERMISSION_GRANTED) {
- coarseLocation = getLastKnownLocationForProvider(LocationManager.NETWORK_PROVIDER);
+ coarseLoc = getLastKnownLocationForProvider(LocationManager.NETWORK_PROVIDER);
}
permission = PermissionChecker.checkSelfPermission(mContext,
- Manifest.permission.ACCESS_COARSE_LOCATION);
+ Manifest.permission.ACCESS_FINE_LOCATION);
if (permission == PermissionChecker.PERMISSION_GRANTED) {
- fineLocation = getLastKnownLocationForProvider(LocationManager.GPS_PROVIDER);
+ fineLoc = getLastKnownLocationForProvider(LocationManager.GPS_PROVIDER);
}
- if (coarseLocation != null && fineLocation != null) {
+ if (fineLoc != null && coarseLoc != null) {
// If we have both a fine and coarse location, use the latest
- if (fineLocation.getTime() > coarseLocation.getTime()) {
- return fineLocation;
- } else {
- return coarseLocation;
- }
+ return fineLoc.getTime() > coarseLoc.getTime() ? fineLoc : coarseLoc;
} else {
// Else, return the non-null one (if there is one)
- return fineLocation != null ? fineLocation : coarseLocation;
+ return fineLoc != null ? fineLoc : coarseLoc;
}
}
diff --git a/v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java b/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java
rename to v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
index e76f658..2ec054b 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.app;
+package android.support.v7.app;
import android.app.Activity;
import android.app.Dialog;
@@ -31,21 +31,20 @@
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
import android.support.v4.view.ViewPropertyAnimatorUpdateListener;
-import android.support.v7.app.ActionBar;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ActionBarPolicy;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPopupHelper;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.ActionBarContainer;
-import android.support.v7.internal.widget.ActionBarContextView;
-import android.support.v7.internal.widget.ActionBarOverlayLayout;
-import android.support.v7.internal.widget.DecorToolbar;
-import android.support.v7.internal.widget.ScrollingTabContainerView;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v7.view.ActionBarPolicy;
import android.support.v7.view.ActionMode;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.ViewPropertyAnimatorCompatSet;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.view.menu.SubMenuBuilder;
+import android.support.v7.widget.ActionBarContainer;
+import android.support.v7.widget.ActionBarContextView;
+import android.support.v7.widget.ActionBarOverlayLayout;
+import android.support.v7.widget.AppCompatDrawableManager;
+import android.support.v7.widget.DecorToolbar;
+import android.support.v7.widget.ScrollingTabContainerView;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
@@ -58,7 +57,6 @@
import android.view.Window;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.SpinnerAdapter;
@@ -132,8 +130,6 @@
private boolean mShowHideAnimationEnabled;
boolean mHideOnContentScroll;
- private TintManager mTintManager;
-
final ViewPropertyAnimatorListener mHideListener = new ViewPropertyAnimatorListenerAdapter() {
@Override
public void onAnimationEnd(View view) {
@@ -846,7 +842,11 @@
ViewPropertyAnimatorCompat fadeIn, fadeOut;
if (toActionMode) {
- fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.GONE,
+ // We use INVISIBLE for the Toolbar to make sure that the container has a non-zero
+ // height throughout. The context view is GONE initially, so will not have been laid
+ // out when the animation starts. This can lead to the container collapsing to 0px
+ // height for a short period.
+ fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.INVISIBLE,
FADE_OUT_DURATION_MS);
fadeIn = mContextView.setupAnimatorToVisibility(View.VISIBLE,
FADE_IN_DURATION_MS);
@@ -1180,7 +1180,7 @@
@Override
public Tab setIcon(int resId) {
- return setIcon(getTintManager().getDrawable(resId));
+ return setIcon(AppCompatDrawableManager.get().getDrawable(mContext, resId));
}
@Override
@@ -1336,12 +1336,4 @@
setDisplayHomeAsUpEnabled(enable);
}
}
-
- TintManager getTintManager() {
- if (mTintManager == null) {
- mTintManager = TintManager.get(mContext);
- }
- return mTintManager;
- }
-
}
diff --git a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
index 82e8f18..2c658b1 100644
--- a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
+++ b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
@@ -447,6 +447,13 @@
}
/**
+ * Returns the paint instance used for all drawing.
+ */
+ public final Paint getPaint() {
+ return mPaint;
+ }
+
+ /**
* Linear interpolate between a and b with parameter t.
*/
private static float lerp(float a, float b, float t) {
diff --git a/v7/appcompat/src/android/support/v7/internal/VersionUtils.java b/v7/appcompat/src/android/support/v7/internal/VersionUtils.java
deleted file mode 100644
index babd65c..0000000
--- a/v7/appcompat/src/android/support/v7/internal/VersionUtils.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package android.support.v7.internal;
-
-import android.os.Build;
-
-/**
- * @hide
- */
-public class VersionUtils {
-
- private VersionUtils() {}
-
- public static boolean isAtLeastL() {
- return Build.VERSION.SDK_INT >= 21;
- }
-
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java b/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java
deleted file mode 100644
index 621fc51..0000000
--- a/v7/appcompat/src/android/support/v7/internal/app/AppCompatViewInflater.java
+++ /dev/null
@@ -1,193 +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 android.support.v7.internal.app;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.support.annotation.NonNull;
-import android.support.v4.util.ArrayMap;
-import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ContextThemeWrapper;
-import android.support.v7.widget.AppCompatAutoCompleteTextView;
-import android.support.v7.widget.AppCompatButton;
-import android.support.v7.widget.AppCompatCheckBox;
-import android.support.v7.widget.AppCompatCheckedTextView;
-import android.support.v7.widget.AppCompatEditText;
-import android.support.v7.widget.AppCompatMultiAutoCompleteTextView;
-import android.support.v7.widget.AppCompatRadioButton;
-import android.support.v7.widget.AppCompatRatingBar;
-import android.support.v7.widget.AppCompatSpinner;
-import android.support.v7.internal.widget.ViewUtils;
-import android.support.v7.widget.AppCompatTextView;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.InflateException;
-import android.view.View;
-
-import java.lang.reflect.Constructor;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * This class is responsible for manually inflating our tinted widgets which are used on devices
- * running {@link android.os.Build.VERSION_CODES#KITKAT KITKAT} or below. As such, this class
- * should only be used when running on those devices.
- * <p>This class two main responsibilities: the first is to 'inject' our tinted views in place of
- * the framework versions in layout inflation; the second is backport the {@code android:theme}
- * functionality for any inflated widgets. This include theme inheritance from it's parent.
- *
- * @hide
- */
-public class AppCompatViewInflater {
-
- static final Class<?>[] sConstructorSignature = new Class[]{
- Context.class, AttributeSet.class};
-
- private static final String LOG_TAG = "AppCompatViewInflater";
-
- private static final Map<String, Constructor<? extends View>> sConstructorMap
- = new ArrayMap<>();
-
- private final Object[] mConstructorArgs = new Object[2];
-
- public final View createView(View parent, final String name, @NonNull Context context,
- @NonNull AttributeSet attrs, boolean inheritContext,
- boolean readAndroidTheme, boolean readAppTheme) {
- final Context originalContext = context;
-
- // We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
- // by using the parent's context
- if (inheritContext && parent != null) {
- context = parent.getContext();
- }
- if (readAndroidTheme || readAppTheme) {
- // We then apply the theme on the context, if specified
- context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
- }
-
- // We need to 'inject' our tint aware Views in place of the standard framework versions
- switch (name) {
- case "EditText":
- return new AppCompatEditText(context, attrs);
- case "Spinner":
- return new AppCompatSpinner(context, attrs);
- case "CheckBox":
- return new AppCompatCheckBox(context, attrs);
- case "RadioButton":
- return new AppCompatRadioButton(context, attrs);
- case "CheckedTextView":
- return new AppCompatCheckedTextView(context, attrs);
- case "AutoCompleteTextView":
- return new AppCompatAutoCompleteTextView(context, attrs);
- case "MultiAutoCompleteTextView":
- return new AppCompatMultiAutoCompleteTextView(context, attrs);
- case "RatingBar":
- return new AppCompatRatingBar(context, attrs);
- case "Button":
- return new AppCompatButton(context, attrs);
- case "TextView":
- return new AppCompatTextView(context, attrs);
- }
-
- if (originalContext != context) {
- // If the original context does not equal our themed context, then we need to manually
- // inflate it using the name so that android:theme takes effect.
- return createViewFromTag(context, name, attrs);
- }
-
- return null;
- }
-
- private View createViewFromTag(Context context, String name, AttributeSet attrs) {
- if (name.equals("view")) {
- name = attrs.getAttributeValue(null, "class");
- }
-
- try {
- mConstructorArgs[0] = context;
- mConstructorArgs[1] = attrs;
-
- if (-1 == name.indexOf('.')) {
- // try the android.widget prefix first...
- return createView(context, name, "android.widget.");
- } else {
- return createView(context, name, null);
- }
- } catch (Exception e) {
- // We do not want to catch these, lets return null and let the actual LayoutInflater
- // try
- return null;
- } finally {
- // Don't retain references on context.
- mConstructorArgs[0] = null;
- mConstructorArgs[1] = null;
- }
- }
-
- private View createView(Context context, String name, String prefix)
- throws ClassNotFoundException, InflateException {
- Constructor<? extends View> constructor = sConstructorMap.get(name);
-
- try {
- if (constructor == null) {
- // Class not found in the cache, see if it's real, and try to add it
- Class<? extends View> clazz = context.getClassLoader().loadClass(
- prefix != null ? (prefix + name) : name).asSubclass(View.class);
-
- constructor = clazz.getConstructor(sConstructorSignature);
- sConstructorMap.put(name, constructor);
- }
- constructor.setAccessible(true);
- return constructor.newInstance(mConstructorArgs);
- } catch (Exception e) {
- // We do not want to catch these, lets return null and let the actual LayoutInflater
- // try
- return null;
- }
- }
-
- /**
- * Allows us to emulate the {@code android:theme} attribute for devices before L.
- */
- private static Context themifyContext(Context context, AttributeSet attrs,
- boolean useAndroidTheme, boolean useAppTheme) {
- final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.View, 0, 0);
- int themeId = 0;
- if (useAndroidTheme) {
- // First try reading android:theme if enabled
- themeId = a.getResourceId(R.styleable.View_android_theme, 0);
- }
- if (useAppTheme && themeId == 0) {
- // ...if that didn't work, try reading app:theme (for legacy reasons) if enabled
- themeId = a.getResourceId(R.styleable.View_theme, 0);
-
- if (themeId != 0) {
- Log.i(LOG_TAG, "app:theme is now deprecated. "
- + "Please move to using android:theme instead.");
- }
- }
- a.recycle();
-
- if (themeId != 0 && (!(context instanceof ContextThemeWrapper)
- || ((ContextThemeWrapper) context).getThemeResId() != themeId)) {
- // If the context isn't a ContextThemeWrapper, or it is but does not have
- // the same theme as we need, wrap it in a new wrapper
- context = new ContextThemeWrapper(context, themeId);
- }
- return context;
- }
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawableV21.java b/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawableV21.java
deleted file mode 100644
index 19cd5a1..0000000
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawableV21.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package android.support.v7.internal.widget;
-
-import android.graphics.Outline;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-
-class ActionBarBackgroundDrawableV21 extends ActionBarBackgroundDrawable {
-
- public ActionBarBackgroundDrawableV21(ActionBarContainer container) {
- super(container);
- }
-
- @Override
- public void getOutline(@NonNull Outline outline) {
- if (mContainer.mIsSplit) {
- if (mContainer.mSplitBackground != null) {
- mContainer.mSplitBackground.getOutline(outline);
- }
- } else {
- // ignore the stacked background for shadow casting
- if (mContainer.mBackground != null) {
- mContainer.mBackground.getOutline(outline);
- }
- }
- }
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java b/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java
deleted file mode 100644
index 17dd557..0000000
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintImageView.java
+++ /dev/null
@@ -1,70 +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 android.support.v7.internal.widget;
-
-import android.content.Context;
-import android.support.annotation.DrawableRes;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-/**
- * An tint aware {@link android.widget.ImageView}
- *
- * @hide
- */
-public class TintImageView extends ImageView {
-
- private static final int[] TINT_ATTRS = {
- android.R.attr.background,
- android.R.attr.src
- };
-
- private final TintManager mTintManager;
-
- public TintImageView(Context context) {
- this(context, null);
- }
-
- public TintImageView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public TintImageView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, TINT_ATTRS,
- defStyleAttr, 0);
- if (a.length() > 0) {
- if (a.hasValue(0)) {
- setBackgroundDrawable(a.getDrawable(0));
- }
- if (a.hasValue(1)) {
- setImageDrawable(a.getDrawable(1));
- }
- }
- a.recycle();
-
- // Keep the TintManager in case we need it later
- mTintManager = a.getTintManager();
- }
-
- @Override
- public void setImageResource(@DrawableRes int resId) {
- // Intercept this call and instead retrieve the Drawable via the tint manager
- setImageDrawable(mTintManager.getDrawable(resId));
- }
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/text/AllCapsTransformationMethod.java b/v7/appcompat/src/android/support/v7/text/AllCapsTransformationMethod.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/text/AllCapsTransformationMethod.java
rename to v7/appcompat/src/android/support/v7/text/AllCapsTransformationMethod.java
index 76d1aed..7150262 100644
--- a/v7/appcompat/src/android/support/v7/internal/text/AllCapsTransformationMethod.java
+++ b/v7/appcompat/src/android/support/v7/text/AllCapsTransformationMethod.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.text;
+package android.support.v7.text;
import android.content.Context;
import android.graphics.Rect;
diff --git a/v7/appcompat/src/android/support/v7/internal/transition/ActionBarTransition.java b/v7/appcompat/src/android/support/v7/transition/ActionBarTransition.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/transition/ActionBarTransition.java
rename to v7/appcompat/src/android/support/v7/transition/ActionBarTransition.java
index bc4ad04..6cffd53 100644
--- a/v7/appcompat/src/android/support/v7/internal/transition/ActionBarTransition.java
+++ b/v7/appcompat/src/android/support/v7/transition/ActionBarTransition.java
@@ -15,7 +15,7 @@
*/
-package android.support.v7.internal.transition;
+package android.support.v7.transition;
import android.view.ViewGroup;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/ActionBarPolicy.java b/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/ActionBarPolicy.java
rename to v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
index dc5c4f0..0e50cc1 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/ActionBarPolicy.java
+++ b/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view;
+package android.support.v7.view;
import android.content.Context;
import android.content.res.Resources;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java b/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java
rename to v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
index d8932ee..6b77fd6 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view;
+package android.support.v7.view;
import android.content.Context;
import android.content.ContextWrapper;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/StandaloneActionMode.java b/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
similarity index 92%
rename from v7/appcompat/src/android/support/v7/internal/view/StandaloneActionMode.java
rename to v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
index 887b43d..7f4c87e 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/StandaloneActionMode.java
+++ b/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
@@ -13,15 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.v7.internal.view;
+package android.support.v7.view;
import android.content.Context;
import android.support.v4.view.MenuItemCompat;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPopupHelper;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.ActionBarContextView;
-import android.support.v7.view.ActionMode;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.view.menu.SubMenuBuilder;
+import android.support.v7.widget.ActionBarContextView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/SupportActionModeWrapper.java b/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/SupportActionModeWrapper.java
rename to v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
index 2c09e64..7eb6354 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/SupportActionModeWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view;
+package android.support.v7.view;
import android.annotation.TargetApi;
import android.content.Context;
@@ -22,7 +22,7 @@
import android.support.v4.internal.view.SupportMenu;
import android.support.v4.internal.view.SupportMenuItem;
import android.support.v4.util.SimpleArrayMap;
-import android.support.v7.internal.view.menu.MenuWrapperFactory;
+import android.support.v7.view.menu.MenuWrapperFactory;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java b/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
rename to v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
index 7bc3978..c8004ee 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
+++ b/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view;
+package android.support.v7.view;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -28,8 +28,8 @@
import android.support.v4.view.ActionProvider;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuItemWrapperICS;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuItemWrapperICS;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java b/v7/appcompat/src/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java
rename to v7/appcompat/src/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
index ec1d567..8727c9d 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java
+++ b/v7/appcompat/src/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view;
+package android.support.v7.view;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java b/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java
rename to v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
index 900d304..45278bc 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view;
+package android.support.v7.view;
import android.view.ActionMode;
import android.view.KeyEvent;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItem.java b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItem.java
rename to v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
index b466a0b..5e6ea31 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItem.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ActionProvider;
import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v4.view.ActionProvider;
import android.support.v4.view.MenuItemCompat;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItemView.java
rename to v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
index b7f5ff7..0b80cf2 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ActionMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.content.res.Configuration;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuPresenter.java b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuPresenter.java
rename to v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
index 34cc821..868ff41 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.support.v4.view.ViewCompat;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuWrapper.java b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuWrapper.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuWrapper.java
rename to v7/appcompat/src/android/support/v7/view/menu/BaseMenuWrapper.java
index b8f7793..1a31ec6 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseMenuWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/BaseMenuWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.support.v4.internal.view.SupportMenuItem;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseWrapper.java b/v7/appcompat/src/android/support/v7/view/menu/BaseWrapper.java
similarity index 94%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/BaseWrapper.java
rename to v7/appcompat/src/android/support/v7/view/menu/BaseWrapper.java
index 116bc23..35422ca 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/BaseWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/BaseWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
class BaseWrapper<T> {
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ExpandedMenuView.java b/v7/appcompat/src/android/support/v7/view/menu/ExpandedMenuView.java
similarity index 90%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ExpandedMenuView.java
rename to v7/appcompat/src/android/support/v7/view/menu/ExpandedMenuView.java
index fa12f67..202c46a 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ExpandedMenuView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ExpandedMenuView.java
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuBuilder.ItemInvoker;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.widget.TintTypedArray;
+import android.support.v7.view.menu.MenuBuilder.ItemInvoker;
+import android.support.v7.widget.TintTypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuItemView.java b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuItemView.java
rename to v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
index ebb9529..388e78f 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuItemView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.content.res.TypedArray;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuPresenter.java b/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuPresenter.java
rename to v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
index ac98840..a0b7359 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/ListMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
-import android.database.DataSetObserver;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v7.appcompat.R;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuBuilder.java b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuBuilder.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
index 16624c7..b976655 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuBuilder.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.ComponentName;
import android.content.Context;
@@ -27,11 +27,11 @@
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.content.ContextCompat;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.appcompat.R;
-import android.support.v4.view.ActionProvider;
import android.support.v4.internal.view.SupportMenu;
import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v4.view.ActionProvider;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.appcompat.R;
import android.util.SparseArray;
import android.view.ContextMenu;
import android.view.KeyCharacterMap;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuDialogHelper.java b/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuDialogHelper.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
index dc4e9f52..6e4036f 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuDialogHelper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.app.Dialog;
import android.content.DialogInterface;
@@ -28,10 +28,8 @@
/**
* Helper for menus that appear as Dialogs (context and submenus).
- *
- * @hide
*/
-public class MenuDialogHelper implements DialogInterface.OnKeyListener,
+class MenuDialogHelper implements DialogInterface.OnKeyListener,
DialogInterface.OnClickListener,
DialogInterface.OnDismissListener,
MenuPresenter.Callback {
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
index ffddb31..7709a36 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
@@ -14,18 +14,17 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Build;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ActionProvider;
import android.support.v4.internal.view.SupportMenuItem;
+import android.support.v4.view.ActionProvider;
import android.support.v4.view.MenuItemCompat;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v7.widget.AppCompatDrawableManager;
import android.util.Log;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
@@ -419,7 +418,8 @@
}
if (mIconResId != NO_ICON) {
- Drawable icon = TintManager.getDrawable(mMenu.getContext(), mIconResId);
+ Drawable icon = AppCompatDrawableManager.get()
+ .getDrawable(mMenu.getContext(), mIconResId);
mIconResId = NO_ICON;
mIconDrawable = icon;
return icon;
@@ -538,7 +538,7 @@
@Override
public String toString() {
- return mTitle.toString();
+ return mTitle != null ? mTitle.toString() : null;
}
void setMenuInfo(ContextMenuInfo menuInfo) {
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
index 3e6a99a..a717628 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.annotation.TargetApi;
import android.content.Context;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperJB.java b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperJB.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
index 4dbb0e0..9a02b4f 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperJB.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.annotation.TargetApi;
import android.content.Context;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java b/v7/appcompat/src/android/support/v7/view/menu/MenuPopupHelper.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuPopupHelper.java
index bdcc79a..c0e0fb5 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuPopupHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.content.res.Resources;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPresenter.java b/v7/appcompat/src/android/support/v7/view/menu/MenuPresenter.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuPresenter.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuPresenter.java
index 4e92426..cf414fc 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuPresenter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.os.Parcelable;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuView.java b/v7/appcompat/src/android/support/v7/view/menu/MenuView.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuView.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuView.java
index 7a3aabc..a4d9310 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuView.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.graphics.drawable.Drawable;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperFactory.java b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperFactory.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperFactory.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuWrapperFactory.java
index 74358747..0130822 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperFactory.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperFactory.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.os.Build;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperICS.java
rename to v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
index 79833f5..e733427 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.support.v4.internal.view.SupportMenu;
-import android.support.v4.internal.view.SupportMenuItem;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuBuilder.java b/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuBuilder.java
rename to v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
index 90bf77f..a213b77 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuBuilder.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.graphics.drawable.Drawable;
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuWrapperICS.java b/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuWrapperICS.java
rename to v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
index a4306e9..9c1d5e5 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/SubMenuWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.view.menu;
+package android.support.v7.view.menu;
import android.content.Context;
import android.graphics.drawable.Drawable;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java b/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java
rename to v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
index 0824828..2121b74 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.Configuration;
@@ -25,8 +25,6 @@
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.support.v7.appcompat.R;
-import android.support.v7.widget.ActionMenuPresenter;
-import android.support.v7.widget.ActionMenuView;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawable.java b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
similarity index 61%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawable.java
rename to v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
index 6248f79..b2fa191 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarBackgroundDrawable.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
@@ -1,4 +1,20 @@
-package android.support.v7.internal.widget;
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
new file mode 100644
index 0000000..0b05fe7
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.graphics.Outline;
+import android.support.annotation.NonNull;
+
+class ActionBarBackgroundDrawableV21 extends ActionBarBackgroundDrawable {
+
+ public ActionBarBackgroundDrawableV21(ActionBarContainer container) {
+ super(container);
+ }
+
+ @Override
+ public void getOutline(@NonNull Outline outline) {
+ if (mContainer.mIsSplit) {
+ if (mContainer.mSplitBackground != null) {
+ mContainer.mSplitBackground.getOutline(outline);
+ }
+ } else {
+ // ignore the stacked background for shadow casting
+ if (mContainer.mBackground != null) {
+ mContainer.mBackground.getOutline(outline);
+ }
+ }
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContainer.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActionBarContainer.java
rename to v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
index 239fe4c..c8c69ea 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContainer.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.VersionUtils;
import android.support.v7.view.ActionMode;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -55,7 +54,7 @@
super(context, attrs);
// Set a transparent background so that we project appropriately.
- final Drawable bg = VersionUtils.isAtLeastL()
+ final Drawable bg = Build.VERSION.SDK_INT >= 21
? new ActionBarBackgroundDrawableV21(this)
: new ActionBarBackgroundDrawable(this);
setBackgroundDrawable(bg);
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java
rename to v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
index 7c5d221..4f45c2a 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
-import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.view.ActionMode;
-import android.support.v7.widget.ActionMenuPresenter;
-import android.support.v7.widget.ActionMenuView;
+import android.support.v7.view.menu.MenuBuilder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java b/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java
rename to v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
index d647d7f..9623383 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.Configuration;
@@ -33,9 +33,7 @@
import android.support.v4.widget.ScrollerCompat;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.VersionUtils;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.widget.Toolbar;
+import android.support.v7.view.menu.MenuPresenter;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.Menu;
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
index 7a84b08..e0e1a83 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
@@ -26,16 +26,15 @@
import android.support.v4.view.ActionProvider;
import android.support.v4.view.GravityCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.transition.ActionBarTransition;
-import android.support.v7.internal.view.ActionBarPolicy;
-import android.support.v7.internal.view.menu.ActionMenuItemView;
-import android.support.v7.internal.view.menu.BaseMenuPresenter;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuPopupHelper;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.TintImageView;
+import android.support.v7.transition.ActionBarTransition;
+import android.support.v7.view.ActionBarPolicy;
+import android.support.v7.view.menu.ActionMenuItemView;
+import android.support.v7.view.menu.BaseMenuPresenter;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.view.menu.MenuView;
+import android.support.v7.view.menu.SubMenuBuilder;
import android.util.SparseBooleanArray;
import android.view.MenuItem;
import android.view.SoundEffectConstants;
@@ -47,10 +46,8 @@
/**
* MenuPresenter for building action menus as seen in the action bar and action modes.
- *
- * @hide
*/
-public class ActionMenuPresenter extends BaseMenuPresenter
+class ActionMenuPresenter extends BaseMenuPresenter
implements ActionProvider.SubUiVisibilityListener {
private static final String TAG = "ActionMenuPresenter";
@@ -606,7 +603,8 @@
};
}
- private class OverflowMenuButton extends TintImageView implements ActionMenuView.ActionMenuChildView {
+ private class OverflowMenuButton extends AppCompatImageView
+ implements ActionMenuView.ActionMenuChildView {
private final float[] mTempPts = new float[2];
public OverflowMenuButton(Context context) {
@@ -704,7 +702,9 @@
@Override
public void onDismiss() {
super.onDismiss();
- mMenu.close();
+ if (mMenu != null) {
+ mMenu.close();
+ }
mOverflowPopup = null;
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
index 0e47283..9919fec 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
@@ -21,12 +21,11 @@
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
-import android.support.v7.internal.view.menu.ActionMenuItemView;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.widget.ViewUtils;
+import android.support.v7.view.menu.ActionMenuItemView;
+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.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java b/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java
rename to v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
index 88dbf12..af405eb 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -87,10 +87,8 @@
* <p>
* <strong>Note:</strong> This class is thread safe.
* </p>
- *
- * @hide
*/
-public class ActivityChooserModel extends DataSetObservable {
+class ActivityChooserModel extends DataSetObservable {
/**
* Client that utilizes an {@link ActivityChooserModel}.
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserView.java b/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserView.java
rename to v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
index 9931afb..3ea3a2e 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.Intent;
@@ -27,8 +27,6 @@
import android.support.v4.view.ActionProvider;
import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.widget.LinearLayoutCompat;
-import android.support.v7.widget.ListPopupWindow;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
index a057677..4df02a0 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
@@ -24,9 +24,6 @@
import android.support.annotation.Nullable;
import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.AutoCompleteTextView;
@@ -52,7 +49,7 @@
android.R.attr.popupBackground
};
- private TintManager mTintManager;
+ private AppCompatDrawableManager mDrawableManager;
private AppCompatBackgroundHelper mBackgroundTintHelper;
private AppCompatTextHelper mTextHelper;
@@ -67,25 +64,27 @@
public AppCompatAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
+ mDrawableManager = AppCompatDrawableManager.get();
+
TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
TINT_ATTRS, defStyleAttr, 0);
- mTintManager = a.getTintManager();
if (a.hasValue(0)) {
setDropDownBackgroundDrawable(a.getDrawable(0));
}
a.recycle();
- mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
- mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper = AppCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+ mTextHelper.applyCompoundDrawablesTints();
}
@Override
public void setDropDownBackgroundResource(@DrawableRes int resId) {
- if (mTintManager != null) {
- setDropDownBackgroundDrawable(mTintManager.getDrawable(resId));
+ if (mDrawableManager != null) {
+ setDropDownBackgroundDrawable(mDrawableManager.getDrawable(getContext(), resId));
} else {
super.setDropDownBackgroundResource(resId);
}
@@ -165,6 +164,9 @@
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySupportBackgroundTint();
}
+ if (mTextHelper != null) {
+ mTextHelper.applyCompoundDrawablesTints();
+ }
}
@Override
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
index 7494b24..90d823c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
@@ -23,22 +23,20 @@
import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
import android.support.v7.graphics.drawable.DrawableUtils;
-import android.support.v7.internal.widget.TintInfo;
-import android.support.v7.internal.widget.TintManager;
import android.util.AttributeSet;
import android.view.View;
class AppCompatBackgroundHelper {
private final View mView;
- private final TintManager mTintManager;
+ private final AppCompatDrawableManager mDrawableManager;
private TintInfo mInternalBackgroundTint;
private TintInfo mBackgroundTint;
- AppCompatBackgroundHelper(View view, TintManager tintManager) {
+ AppCompatBackgroundHelper(View view, AppCompatDrawableManager drawableManager) {
mView = view;
- mTintManager = tintManager;
+ mDrawableManager = drawableManager;
}
void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
@@ -46,7 +44,7 @@
R.styleable.ViewBackgroundHelper, defStyleAttr, 0);
try {
if (a.hasValue(R.styleable.ViewBackgroundHelper_android_background)) {
- ColorStateList tint = mTintManager.getTintList(
+ ColorStateList tint = mDrawableManager.getTintList(mView.getContext(),
a.getResourceId(R.styleable.ViewBackgroundHelper_android_background, -1));
if (tint != null) {
setInternalBackgroundTint(tint);
@@ -69,7 +67,9 @@
void onSetBackgroundResource(int resId) {
// Update the default background tint
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null);
+ setInternalBackgroundTint(mDrawableManager != null
+ ? mDrawableManager.getTintList(mView.getContext(), resId)
+ : null);
}
void onSetBackgroundDrawable(Drawable background) {
@@ -106,11 +106,14 @@
}
void applySupportBackgroundTint() {
- if (mView.getBackground() != null) {
+ final Drawable background = mView.getBackground();
+ if (background != null) {
if (mBackgroundTint != null) {
- TintManager.tintViewBackground(mView, mBackgroundTint);
+ AppCompatDrawableManager
+ .tintDrawable(background, mBackgroundTint, mView.getDrawableState());
} else if (mInternalBackgroundTint != null) {
- TintManager.tintViewBackground(mView, mInternalBackgroundTint);
+ AppCompatDrawableManager.tintDrawable(background, mInternalBackgroundTint,
+ mView.getDrawableState());
}
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
index 91d69c8..15dacb0 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
@@ -24,8 +24,6 @@
import android.support.annotation.Nullable;
import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.text.AllCapsTransformationMethod;
-import android.support.v7.internal.widget.TintManager;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -48,7 +46,7 @@
*/
public class AppCompatButton extends Button implements TintableBackgroundView {
- private final TintManager mTintManager;
+ private final AppCompatDrawableManager mDrawableManager;
private final AppCompatBackgroundHelper mBackgroundTintHelper;
private final AppCompatTextHelper mTextHelper;
@@ -63,12 +61,13 @@
public AppCompatButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mTintManager = TintManager.get(getContext());
- mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mDrawableManager = AppCompatDrawableManager.get();
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
- mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper = AppCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+ mTextHelper.applyCompoundDrawablesTints();
}
@Override
@@ -145,6 +144,9 @@
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySupportBackgroundTint();
}
+ if (mTextHelper != null) {
+ mTextHelper.applyCompoundDrawablesTints();
+ }
}
@Override
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
index 1ad2c77..4a6ecbe 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
@@ -25,7 +25,6 @@
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.TintableCompoundButton;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintManager;
import android.util.AttributeSet;
import android.widget.CheckBox;
@@ -44,7 +43,7 @@
*/
public class AppCompatCheckBox extends CheckBox implements TintableCompoundButton {
- private TintManager mTintManager;
+ private AppCompatDrawableManager mDrawableManager;
private AppCompatCompoundButtonHelper mCompoundButtonHelper;
public AppCompatCheckBox(Context context) {
@@ -57,8 +56,8 @@
public AppCompatCheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mTintManager = TintManager.get(context);
- mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mTintManager);
+ mDrawableManager = AppCompatDrawableManager.get();
+ mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mDrawableManager);
mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
}
@@ -72,8 +71,8 @@
@Override
public void setButtonDrawable(@DrawableRes int resId) {
- setButtonDrawable(mTintManager != null
- ? mTintManager.getDrawable(resId)
+ setButtonDrawable(mDrawableManager != null
+ ? mDrawableManager.getDrawable(getContext(), resId)
: ContextCompat.getDrawable(getContext(), resId));
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
index 4776b83..29c877c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
@@ -18,8 +18,6 @@
import android.content.Context;
import android.support.annotation.DrawableRes;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.CheckedTextView;
@@ -35,7 +33,8 @@
android.R.attr.checkMark
};
- private TintManager mTintManager;
+ private AppCompatDrawableManager mDrawableManager;
+ private AppCompatTextHelper mTextHelper;
public AppCompatCheckedTextView(Context context) {
this(context, null);
@@ -48,23 +47,40 @@
public AppCompatCheckedTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
- setCheckMarkDrawable(a.getDrawable(0));
- a.recycle();
+ mTextHelper = AppCompatTextHelper.create(this);
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+ mTextHelper.applyCompoundDrawablesTints();
- mTintManager = a.getTintManager();
- }
+ mDrawableManager = AppCompatDrawableManager.get();
+
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
+ TINT_ATTRS, defStyleAttr, 0);
+ setCheckMarkDrawable(a.getDrawable(0));
+ a.recycle();
}
@Override
public void setCheckMarkDrawable(@DrawableRes int resId) {
- if (mTintManager != null) {
- setCheckMarkDrawable(mTintManager.getDrawable(resId));
+ if (mDrawableManager != null) {
+ setCheckMarkDrawable(mDrawableManager.getDrawable(getContext(), resId));
} else {
super.setCheckMarkDrawable(resId);
}
}
+ @Override
+ public void setTextAppearance(Context context, int resId) {
+ super.setTextAppearance(context, resId);
+ if (mTextHelper != null) {
+ mTextHelper.onSetTextAppearance(context, resId);
+ }
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ if (mTextHelper != null) {
+ mTextHelper.applyCompoundDrawablesTints();
+ }
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
index 20c3667..ad3e6d3 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
@@ -26,14 +26,13 @@
import android.support.v4.widget.CompoundButtonCompat;
import android.support.v7.appcompat.R;
import android.support.v7.graphics.drawable.DrawableUtils;
-import android.support.v7.internal.widget.TintManager;
import android.util.AttributeSet;
import android.widget.CompoundButton;
class AppCompatCompoundButtonHelper {
private final CompoundButton mView;
- private final TintManager mTintManager;
+ private final AppCompatDrawableManager mDrawableManager;
private ColorStateList mButtonTintList = null;
private PorterDuff.Mode mButtonTintMode = null;
@@ -49,9 +48,9 @@
void setButtonDrawable(Drawable buttonDrawable);
}
- AppCompatCompoundButtonHelper(CompoundButton view, TintManager tintManager) {
+ AppCompatCompoundButtonHelper(CompoundButton view, AppCompatDrawableManager drawableManager) {
mView = view;
- mTintManager = tintManager;
+ mDrawableManager = drawableManager;
}
void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
@@ -62,7 +61,8 @@
final int resourceId = a.getResourceId(
R.styleable.CompoundButton_android_button, 0);
if (resourceId != 0) {
- mView.setButtonDrawable(mTintManager.getDrawable(resourceId));
+ mView.setButtonDrawable(
+ mDrawableManager.getDrawable(mView.getContext(), resourceId));
}
}
if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
similarity index 65%
rename from v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
rename to v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
index d926e17..4fcaf13 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -22,8 +22,14 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.StateListDrawable;
import android.os.Build;
+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.graphics.ColorUtils;
import android.support.v4.graphics.drawable.DrawableCompat;
@@ -31,27 +37,45 @@
import android.support.v7.appcompat.R;
import android.util.Log;
import android.util.SparseArray;
-import android.view.View;
-import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.WeakHashMap;
-import static android.support.v7.internal.widget.ThemeUtils.getDisabledThemeAttrColor;
-import static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColor;
-import static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColorStateList;
+import static android.support.v7.widget.ThemeUtils.getDisabledThemeAttrColor;
+import static android.support.v7.widget.ThemeUtils.getThemeAttrColor;
+import static android.support.v7.widget.ThemeUtils.getThemeAttrColorStateList;
/**
* @hide
*/
-public final class TintManager {
+public final class AppCompatDrawableManager {
- public static final boolean SHOULD_BE_USED = Build.VERSION.SDK_INT < 21;
+ public interface InflateDelegate {
+ /**
+ * Allows custom inflation of a drawable resource.
+ *
+ * @param context Context to inflate/create with
+ * @param resId Resource ID of the drawable
+ * @return the created drawable, or {@code null} to leave inflation to
+ * AppCompatDrawableManager.
+ */
+ @Nullable
+ Drawable onInflateDrawable(@NonNull Context context, @DrawableRes int resId);
+ }
private static final String TAG = "TintManager";
private static final boolean DEBUG = false;
private static final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN;
- private static final WeakHashMap<Context, TintManager> INSTANCE_CACHE = new WeakHashMap<>();
+ private static AppCompatDrawableManager INSTANCE;
+
+ public static AppCompatDrawableManager get() {
+ if (INSTANCE == null) {
+ INSTANCE = new AppCompatDrawableManager();
+ }
+ return INSTANCE;
+ }
+
private static final ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6);
/**
@@ -131,46 +155,27 @@
R.drawable.abc_btn_radio_material
};
- private final WeakReference<Context> mContextRef;
- private SparseArray<ColorStateList> mTintLists;
- private ColorStateList mDefaultColorStateList;
+ private WeakHashMap<Context, SparseArray<ColorStateList>> mTintLists;
+ private ArrayList<InflateDelegate> mDelegates;
- /**
- * A helper method to get a {@link TintManager} and then call {@link #getDrawable(int)}.
- * This method should not be used routinely.
- */
- public static Drawable getDrawable(Context context, int resId) {
- if (isInTintList(resId)) {
- return TintManager.get(context).getDrawable(resId);
- } else {
- return ContextCompat.getDrawable(context, resId);
+ public Drawable getDrawable(@NonNull Context context, @DrawableRes int resId) {
+ return getDrawable(context, resId, false);
+ }
+
+ public Drawable getDrawable(@NonNull Context context, @DrawableRes int resId,
+ boolean failIfNotKnown) {
+ // Let the InflateDelegates have a go first
+ if (mDelegates != null) {
+ for (int i = 0, count = mDelegates.size(); i < count; i++) {
+ final InflateDelegate delegate = mDelegates.get(i);
+ final Drawable result = delegate.onInflateDrawable(context, resId);
+ if (result != null) {
+ return result;
+ }
+ }
}
- }
- /**
- * Get a {@link android.support.v7.internal.widget.TintManager} instance.
- */
- public static TintManager get(Context context) {
- TintManager tm = INSTANCE_CACHE.get(context);
- if (tm == null) {
- tm = new TintManager(context);
- INSTANCE_CACHE.put(context, tm);
- }
- return tm;
- }
-
- private TintManager(Context context) {
- mContextRef = new WeakReference<>(context);
- }
-
- public Drawable getDrawable(int resId) {
- return getDrawable(resId, false);
- }
-
- public Drawable getDrawable(int resId, boolean failIfNotKnown) {
- final Context context = mContextRef.get();
- if (context == null) return null;
-
+ // The delegates failed so we'll carry on
Drawable drawable = ContextCompat.getDrawable(context, resId);
if (drawable != null) {
@@ -179,7 +184,7 @@
drawable = drawable.mutate();
}
- final ColorStateList tintList = getTintList(resId);
+ final ColorStateList tintList = getTintList(context, resId);
if (tintList != null) {
// First wrap the Drawable and set the tint list
drawable = DrawableCompat.wrap(drawable);
@@ -191,13 +196,21 @@
DrawableCompat.setTintMode(drawable, tintMode);
}
} else if (resId == R.drawable.abc_cab_background_top_material) {
- return new LayerDrawable(new Drawable[] {
- getDrawable(R.drawable.abc_cab_background_internal_bg),
- getDrawable(R.drawable.abc_cab_background_top_mtrl_alpha)
+ return new LayerDrawable(new Drawable[]{
+ getDrawable(context, R.drawable.abc_cab_background_internal_bg),
+ getDrawable(context, R.drawable.abc_cab_background_top_mtrl_alpha)
});
+ } else if (resId == R.drawable.abc_seekbar_track_material) {
+ LayerDrawable ld = (LayerDrawable) drawable;
+ setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.background),
+ getThemeAttrColor(context, R.attr.colorControlNormal), DEFAULT_MODE);
+ setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.secondaryProgress),
+ getThemeAttrColor(context, R.attr.colorControlNormal), DEFAULT_MODE);
+ setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.progress),
+ getThemeAttrColor(context, R.attr.colorControlActivated), DEFAULT_MODE);
} else {
- final boolean usedColorFilter = tintDrawableUsingColorFilter(resId, drawable);
- if (!usedColorFilter && failIfNotKnown) {
+ final boolean tinted = tintDrawableUsingColorFilter(context, resId, drawable);
+ if (!tinted && failIfNotKnown) {
// If we didn't tint using a ColorFilter, and we're set to fail if we don't
// know the id, return null
drawable = null;
@@ -207,10 +220,8 @@
return drawable;
}
- public final boolean tintDrawableUsingColorFilter(final int resId, Drawable drawable) {
- final Context context = mContextRef.get();
- if (context == null) return false;
-
+ public final boolean tintDrawableUsingColorFilter(@NonNull Context context,
+ @DrawableRes final int resId, @NonNull Drawable drawable) {
PorterDuff.Mode tintMode = DEFAULT_MODE;
boolean colorAttrSet = false;
int colorAttr = 0;
@@ -249,6 +260,21 @@
return false;
}
+ public void addDelegate(@NonNull InflateDelegate delegate) {
+ if (mDelegates == null) {
+ mDelegates = new ArrayList<>();
+ }
+ if (!mDelegates.contains(delegate)) {
+ mDelegates.add(delegate);
+ }
+ }
+
+ public void removeDelegate(@NonNull InflateDelegate delegate) {
+ if (mDelegates != null) {
+ mDelegates.remove(delegate);
+ }
+ }
+
private static boolean arrayContains(int[] array, int value) {
for (int id : array) {
if (id == value) {
@@ -258,16 +284,6 @@
return false;
}
- private static boolean isInTintList(int drawableId) {
- return arrayContains(TINT_COLOR_CONTROL_NORMAL, drawableId) ||
- arrayContains(COLORFILTER_TINT_COLOR_CONTROL_NORMAL, drawableId) ||
- arrayContains(COLORFILTER_COLOR_CONTROL_ACTIVATED, drawableId) ||
- arrayContains(TINT_COLOR_CONTROL_STATE_LIST, drawableId) ||
- arrayContains(COLORFILTER_COLOR_BACKGROUND_MULTIPLY, drawableId) ||
- arrayContains(TINT_CHECKABLE_BUTTON_LIST, drawableId) ||
- drawableId == R.drawable.abc_cab_background_top_material;
- }
-
final PorterDuff.Mode getTintMode(final int resId) {
PorterDuff.Mode mode = null;
@@ -278,12 +294,9 @@
return mode;
}
- public final ColorStateList getTintList(int resId) {
- final Context context = mContextRef.get();
- if (context == null) return null;
-
+ public final ColorStateList getTintList(@NonNull Context context, @DrawableRes int resId) {
// Try the cache first (if it exists)
- ColorStateList tint = mTintLists != null ? mTintLists.get(resId) : null;
+ ColorStateList tint = getTintListFromCache(context, resId);
if (tint == null) {
// ...if the cache did not contain a color state list, try and create one
@@ -304,71 +317,85 @@
} else if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) {
tint = getThemeAttrColorStateList(context, R.attr.colorControlNormal);
} else if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) {
- tint = getDefaultColorStateList(context);
+ tint = createDefaultColorStateList(context);
} else if (arrayContains(TINT_CHECKABLE_BUTTON_LIST, resId)) {
tint = createCheckableButtonColorStateList(context);
+ } else if (resId == R.drawable.abc_seekbar_thumb_material) {
+ tint = createSeekbarThumbColorStateList(context);
}
if (tint != null) {
- if (mTintLists == null) {
- // If our tint list cache hasn't been set up yet, create it
- mTintLists = new SparseArray<>();
- }
- // Add any newly created ColorStateList to the cache
- mTintLists.append(resId, tint);
+ addTintListToCache(context, resId, tint);
}
}
return tint;
}
- private ColorStateList getDefaultColorStateList(Context context) {
- if (mDefaultColorStateList == null) {
- /**
- * Generate the default color state list which uses the colorControl attributes.
- * Order is important here. The default enabled state needs to go at the bottom.
- */
-
- final int colorControlNormal = getThemeAttrColor(context, R.attr.colorControlNormal);
- final int colorControlActivated = getThemeAttrColor(context,
- R.attr.colorControlActivated);
-
- final int[][] states = new int[7][];
- final int[] colors = new int[7];
- int i = 0;
-
- // Disabled state
- states[i] = ThemeUtils.DISABLED_STATE_SET;
- colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal);
- i++;
-
- states[i] = ThemeUtils.FOCUSED_STATE_SET;
- colors[i] = colorControlActivated;
- i++;
-
- states[i] = ThemeUtils.ACTIVATED_STATE_SET;
- colors[i] = colorControlActivated;
- i++;
-
- states[i] = ThemeUtils.PRESSED_STATE_SET;
- colors[i] = colorControlActivated;
- i++;
-
- states[i] = ThemeUtils.CHECKED_STATE_SET;
- colors[i] = colorControlActivated;
- i++;
-
- states[i] = ThemeUtils.SELECTED_STATE_SET;
- colors[i] = colorControlActivated;
- i++;
-
- // Default enabled state
- states[i] = ThemeUtils.EMPTY_STATE_SET;
- colors[i] = colorControlNormal;
- i++;
-
- mDefaultColorStateList = new ColorStateList(states, colors);
+ private ColorStateList getTintListFromCache(@NonNull Context context, @DrawableRes int resId) {
+ if (mTintLists != null) {
+ final SparseArray<ColorStateList> tints = mTintLists.get(context);
+ return tints != null ? tints.get(resId) : null;
}
- return mDefaultColorStateList;
+ return null;
+ }
+
+ private void addTintListToCache(@NonNull Context context, @DrawableRes int resId,
+ @NonNull ColorStateList tintList) {
+ if (mTintLists == null) {
+ mTintLists = new WeakHashMap<>();
+ }
+ SparseArray<ColorStateList> themeTints = mTintLists.get(context);
+ if (themeTints == null) {
+ themeTints = new SparseArray<>();
+ mTintLists.put(context, themeTints);
+ }
+ themeTints.append(resId, tintList);
+ }
+
+ private ColorStateList createDefaultColorStateList(Context context) {
+ /**
+ * Generate the default color state list which uses the colorControl attributes.
+ * Order is important here. The default enabled state needs to go at the bottom.
+ */
+
+ final int colorControlNormal = getThemeAttrColor(context, R.attr.colorControlNormal);
+ final int colorControlActivated = getThemeAttrColor(context, R.attr.colorControlActivated);
+
+ final int[][] states = new int[7][];
+ final int[] colors = new int[7];
+ int i = 0;
+
+ // Disabled state
+ states[i] = ThemeUtils.DISABLED_STATE_SET;
+ colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal);
+ i++;
+
+ states[i] = ThemeUtils.FOCUSED_STATE_SET;
+ colors[i] = colorControlActivated;
+ i++;
+
+ states[i] = ThemeUtils.ACTIVATED_STATE_SET;
+ colors[i] = colorControlActivated;
+ i++;
+
+ states[i] = ThemeUtils.PRESSED_STATE_SET;
+ colors[i] = colorControlActivated;
+ i++;
+
+ states[i] = ThemeUtils.CHECKED_STATE_SET;
+ colors[i] = colorControlActivated;
+ i++;
+
+ states[i] = ThemeUtils.SELECTED_STATE_SET;
+ colors[i] = colorControlActivated;
+ i++;
+
+ // Default enabled state
+ states[i] = ThemeUtils.EMPTY_STATE_SET;
+ colors[i] = colorControlNormal;
+ i++;
+
+ return new ColorStateList(states, colors);
}
private ColorStateList createCheckableButtonColorStateList(Context context) {
@@ -541,6 +568,23 @@
return new ColorStateList(states, colors);
}
+ private ColorStateList createSeekbarThumbColorStateList(Context context) {
+ final int[][] states = new int[2][];
+ final int[] colors = new int[2];
+ int i = 0;
+
+ // Disabled state
+ states[i] = ThemeUtils.DISABLED_STATE_SET;
+ colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlActivated);
+ i++;
+
+ states[i] = ThemeUtils.EMPTY_STATE_SET;
+ colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated);
+ i++;
+
+ return new ColorStateList(states, colors);
+ }
+
private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> {
public ColorFilterLruCache(int maxSize) {
@@ -563,22 +607,50 @@
}
}
- public static void tintViewBackground(View view, TintInfo tint) {
- final Drawable background = view.getBackground();
- if (tint.mHasTintList || tint.mHasTintMode) {
- background.setColorFilter(createTintFilter(
- tint.mHasTintList ? tint.mTintList : null,
- tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE,
- view.getDrawableState()));
- } else {
- background.clearColorFilter();
+ public static void tintDrawable(Drawable drawable, TintInfo tint, int[] state) {
+ if (shouldMutateBackground(drawable) && drawable.mutate() != drawable) {
+ Log.d(TAG, "Mutated drawable is not the same instance as the input.");
+ return;
}
- if (Build.VERSION.SDK_INT <= 10) {
- // On Gingerbread, GradientDrawable does not invalidate itself when it's ColorFilter
- // has changed, so we need to force an invalidation
- view.invalidate();
+ if (tint.mHasTintList || tint.mHasTintMode) {
+ drawable.setColorFilter(createTintFilter(
+ tint.mHasTintList ? tint.mTintList : null,
+ tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE,
+ state));
+ } else {
+ drawable.clearColorFilter();
}
+
+ if (Build.VERSION.SDK_INT <= 23) {
+ // Pre-v23 there is no guarantee that a state change will invoke an invalidation,
+ // so we force it ourselves
+ drawable.invalidateSelf();
+ }
+ }
+
+ private static boolean shouldMutateBackground(Drawable drawable) {
+ if (drawable instanceof LayerDrawable) {
+ return Build.VERSION.SDK_INT >= 16;
+ } else if (drawable instanceof InsetDrawable) {
+ return Build.VERSION.SDK_INT >= 14;
+ } else if (drawable instanceof StateListDrawable) {
+ // StateListDrawable has a bug in mutate() on API 7
+ return Build.VERSION.SDK_INT >= 8;
+ } else if (drawable instanceof DrawableContainer) {
+ // If we have a DrawableContainer, let's traverse it's child array
+ final Drawable.ConstantState state = drawable.getConstantState();
+ if (state instanceof DrawableContainer.DrawableContainerState) {
+ final DrawableContainer.DrawableContainerState containerState =
+ (DrawableContainer.DrawableContainerState) state;
+ for (Drawable child : containerState.getChildren()) {
+ if (!shouldMutateBackground(child)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
}
private static PorterDuffColorFilter createTintFilter(ColorStateList tint,
@@ -590,7 +662,7 @@
return getPorterDuffColorFilter(color, tintMode);
}
- private static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) {
+ public static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) {
// First, lets see if the cache already contains the color filter
PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);
@@ -602,4 +674,8 @@
return filter;
}
+
+ private static void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) {
+ d.setColorFilter(getPorterDuffColorFilter(color, mode == null ? DEFAULT_MODE : mode));
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java b/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
index 885fd6d..d690545c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
@@ -24,8 +24,6 @@
import android.support.annotation.Nullable;
import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintManager;
import android.util.AttributeSet;
import android.widget.EditText;
@@ -46,7 +44,7 @@
*/
public class AppCompatEditText extends EditText implements TintableBackgroundView {
- private TintManager mTintManager;
+ private AppCompatDrawableManager mDrawableManager;
private AppCompatBackgroundHelper mBackgroundTintHelper;
private AppCompatTextHelper mTextHelper;
@@ -61,12 +59,13 @@
public AppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
- mTintManager = TintManager.get(getContext());
- mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mDrawableManager = AppCompatDrawableManager.get();
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
- mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper = AppCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+ mTextHelper.applyCompoundDrawablesTints();
}
@Override
@@ -143,6 +142,9 @@
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySupportBackgroundTint();
}
+ if (mTextHelper != null) {
+ mTextHelper.applyCompoundDrawablesTints();
+ }
}
@Override
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
new file mode 100644
index 0000000..18c07c9
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.TintableBackgroundView;
+import android.support.v7.appcompat.R;
+import android.util.AttributeSet;
+import android.widget.ImageButton;
+
+/**
+ * A {@link ImageButton} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.view.ViewCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ * {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link android.widget.ImageButton} in your
+ * layouts. You should only need to manually use this class when writing custom views.</p>
+ */
+public class AppCompatImageButton extends ImageButton implements TintableBackgroundView {
+
+ private AppCompatBackgroundHelper mBackgroundTintHelper;
+ private AppCompatImageHelper mImageHelper;
+
+ public AppCompatImageButton(Context context) {
+ this(context, null);
+ }
+
+ public AppCompatImageButton(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.imageButtonStyle);
+ }
+
+ public AppCompatImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
+
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, drawableManager);
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+ mImageHelper = new AppCompatImageHelper(this, drawableManager);
+ mImageHelper.loadFromAttributes(attrs, defStyleAttr);
+ }
+
+ @Override
+ public void setImageResource(@DrawableRes int resId) {
+ // Intercept this call and instead retrieve the Drawable via the image helper
+ mImageHelper.setImageResource(resId);
+ }
+
+ @Override
+ public void setBackgroundResource(@DrawableRes int resId) {
+ super.setBackgroundResource(resId);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundResource(resId);
+ }
+ }
+
+ @Override
+ public void setBackgroundDrawable(Drawable background) {
+ super.setBackgroundDrawable(background);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundDrawable(background);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
+ *
+ * @hide
+ */
+ @Override
+ public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
+ *
+ * @hide
+ */
+ @Override
+ @Nullable
+ public ColorStateList getSupportBackgroundTintList() {
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
+ *
+ * @hide
+ */
+ @Override
+ public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+ *
+ * @hide
+ */
+ @Override
+ @Nullable
+ public PorterDuff.Mode getSupportBackgroundTintMode() {
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.applySupportBackgroundTint();
+ }
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java
new file mode 100644
index 0000000..f6e5bae
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.support.v4.content.ContextCompat;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+class AppCompatImageHelper {
+
+ private static final int[] VIEW_ATTRS = {android.R.attr.src};
+
+ private final ImageView mView;
+ private final AppCompatDrawableManager mDrawableManager;
+
+ AppCompatImageHelper(ImageView view, AppCompatDrawableManager drawableManager) {
+ mView = view;
+ mDrawableManager = drawableManager;
+ }
+
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
+ VIEW_ATTRS, defStyleAttr, 0);
+ try {
+ if (a.hasValue(0)) {
+ mView.setImageDrawable(a.getDrawable(0));
+ }
+ } finally {
+ a.recycle();
+ }
+ }
+
+ void setImageResource(int resId) {
+ if (resId != 0) {
+ mView.setImageDrawable(mDrawableManager != null
+ ? mDrawableManager.getDrawable(mView.getContext(), resId)
+ : ContextCompat.getDrawable(mView.getContext(), resId));
+ } else {
+ mView.setImageDrawable(null);
+ }
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
new file mode 100644
index 0000000..0d85121
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.TintableBackgroundView;
+import android.support.v7.appcompat.R;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+/**
+ * A {@link ImageView} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.view.ViewCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ * {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link android.widget.ImageView} in your
+ * layouts. You should only need to manually use this class when writing custom views.</p>
+ */
+public class AppCompatImageView extends ImageView implements TintableBackgroundView {
+
+ private AppCompatBackgroundHelper mBackgroundTintHelper;
+ private AppCompatImageHelper mImageHelper;
+
+ public AppCompatImageView(Context context) {
+ this(context, null);
+ }
+
+ public AppCompatImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AppCompatImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
+
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, drawableManager);
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+ mImageHelper = new AppCompatImageHelper(this, drawableManager);
+ mImageHelper.loadFromAttributes(attrs, defStyleAttr);
+ }
+
+ @Override
+ public void setImageResource(@DrawableRes int resId) {
+ // Intercept this call and instead retrieve the Drawable via the image helper
+ mImageHelper.setImageResource(resId);
+ }
+
+ @Override
+ public void setBackgroundResource(@DrawableRes int resId) {
+ super.setBackgroundResource(resId);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundResource(resId);
+ }
+ }
+
+ @Override
+ public void setBackgroundDrawable(Drawable background) {
+ super.setBackgroundDrawable(background);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundDrawable(background);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
+ *
+ * @hide
+ */
+ @Override
+ public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
+ *
+ * @hide
+ */
+ @Override
+ @Nullable
+ public ColorStateList getSupportBackgroundTintList() {
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
+ *
+ * @hide
+ */
+ @Override
+ public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+ *
+ * @hide
+ */
+ @Override
+ @Nullable
+ public PorterDuff.Mode getSupportBackgroundTintMode() {
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.applySupportBackgroundTint();
+ }
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
index 6f97adb..34cece6 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
@@ -24,9 +24,6 @@
import android.support.annotation.Nullable;
import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.MultiAutoCompleteTextView;
@@ -52,7 +49,7 @@
android.R.attr.popupBackground
};
- private TintManager mTintManager;
+ private AppCompatDrawableManager mDrawableManager;
private AppCompatBackgroundHelper mBackgroundTintHelper;
private AppCompatTextHelper mTextHelper;
@@ -67,25 +64,27 @@
public AppCompatMultiAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
+ mDrawableManager = AppCompatDrawableManager.get();
+
TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
TINT_ATTRS, defStyleAttr, 0);
- mTintManager = a.getTintManager();
if (a.hasValue(0)) {
setDropDownBackgroundDrawable(a.getDrawable(0));
}
a.recycle();
- mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
- mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper = AppCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+ mTextHelper.applyCompoundDrawablesTints();
}
@Override
public void setDropDownBackgroundResource(@DrawableRes int resId) {
- if (mTintManager != null) {
- setDropDownBackgroundDrawable(mTintManager.getDrawable(resId));
+ if (mDrawableManager != null) {
+ setDropDownBackgroundDrawable(mDrawableManager.getDrawable(getContext(), resId));
} else {
super.setDropDownBackgroundResource(resId);
}
@@ -165,6 +164,9 @@
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySupportBackgroundTint();
}
+ if (mTextHelper != null) {
+ mTextHelper.applyCompoundDrawablesTints();
+ }
}
@Override
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java b/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java
rename to v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
index d71d606..0cce845 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.annotation.TargetApi;
import android.content.Context;
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatProgressBarHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatProgressBarHelper.java
new file mode 100644
index 0000000..209a6c2
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatProgressBarHelper.java
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Shader;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ClipDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RoundRectShape;
+import android.graphics.drawable.shapes.Shape;
+import android.support.v4.graphics.drawable.DrawableWrapper;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.widget.ProgressBar;
+
+class AppCompatProgressBarHelper {
+
+ private static final int[] TINT_ATTRS = {
+ android.R.attr.indeterminateDrawable,
+ android.R.attr.progressDrawable
+ };
+
+ private final ProgressBar mView;
+ final AppCompatDrawableManager mDrawableManager;
+
+ private Bitmap mSampleTile;
+
+ AppCompatProgressBarHelper(ProgressBar view, AppCompatDrawableManager drawableManager) {
+ mView = view;
+ mDrawableManager = drawableManager;
+ }
+
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
+ TINT_ATTRS, defStyleAttr, 0);
+
+ Drawable drawable = a.getDrawableIfKnown(0);
+ if (drawable != null) {
+ mView.setIndeterminateDrawable(tileifyIndeterminate(drawable));
+ }
+
+ drawable = a.getDrawableIfKnown(1);
+ if (drawable != null) {
+ mView.setProgressDrawable(tileify(drawable, false));
+ }
+
+ a.recycle();
+ }
+
+ /**
+ * Converts a drawable to a tiled version of itself. It will recursively
+ * traverse layer and state list drawables.
+ */
+ private Drawable tileify(Drawable drawable, boolean clip) {
+ if (drawable instanceof DrawableWrapper) {
+ Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable();
+ if (inner != null) {
+ inner = tileify(inner, clip);
+ ((DrawableWrapper) drawable).setWrappedDrawable(inner);
+ }
+ } else if (drawable instanceof LayerDrawable) {
+ LayerDrawable background = (LayerDrawable) drawable;
+ final int N = background.getNumberOfLayers();
+ Drawable[] outDrawables = new Drawable[N];
+
+ for (int i = 0; i < N; i++) {
+ int id = background.getId(i);
+ outDrawables[i] = tileify(background.getDrawable(i),
+ (id == android.R.id.progress || id == android.R.id.secondaryProgress));
+ }
+ LayerDrawable newBg = new LayerDrawable(outDrawables);
+
+ for (int i = 0; i < N; i++) {
+ newBg.setId(i, background.getId(i));
+ }
+
+ return newBg;
+
+ } else if (drawable instanceof BitmapDrawable) {
+ final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
+ if (mSampleTile == null) {
+ mSampleTile = tileBitmap;
+ }
+
+ final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
+ final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
+ Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
+ shapeDrawable.getPaint().setShader(bitmapShader);
+ return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
+ ClipDrawable.HORIZONTAL) : shapeDrawable;
+ }
+
+ return drawable;
+ }
+
+ /**
+ * Convert a AnimationDrawable for use as a barberpole animation.
+ * Each frame of the animation is wrapped in a ClipDrawable and
+ * given a tiling BitmapShader.
+ */
+ private Drawable tileifyIndeterminate(Drawable drawable) {
+ if (drawable instanceof AnimationDrawable) {
+ AnimationDrawable background = (AnimationDrawable) drawable;
+ final int N = background.getNumberOfFrames();
+ AnimationDrawable newBg = new AnimationDrawable();
+ newBg.setOneShot(background.isOneShot());
+
+ for (int i = 0; i < N; i++) {
+ Drawable frame = tileify(background.getFrame(i), true);
+ frame.setLevel(10000);
+ newBg.addFrame(frame, background.getDuration(i));
+ }
+ newBg.setLevel(10000);
+ drawable = newBg;
+ }
+ return drawable;
+ }
+
+ private Shape getDrawableShape() {
+ final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
+ return new RoundRectShape(roundedCorners, null, null);
+ }
+
+ Bitmap getSampleTime() {
+ return mSampleTile;
+ }
+
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
index 0d928fc..3814a7e 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
@@ -25,7 +25,6 @@
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.TintableCompoundButton;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintManager;
import android.util.AttributeSet;
import android.widget.RadioButton;
@@ -44,7 +43,7 @@
*/
public class AppCompatRadioButton extends RadioButton implements TintableCompoundButton {
- private TintManager mTintManager;
+ private AppCompatDrawableManager mDrawableManager;
private AppCompatCompoundButtonHelper mCompoundButtonHelper;
public AppCompatRadioButton(Context context) {
@@ -57,8 +56,8 @@
public AppCompatRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mTintManager = TintManager.get(context);
- mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mTintManager);
+ mDrawableManager = AppCompatDrawableManager.get();
+ mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mDrawableManager);
mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
}
@@ -72,8 +71,8 @@
@Override
public void setButtonDrawable(@DrawableRes int resId) {
- setButtonDrawable(mTintManager != null
- ? mTintManager.getDrawable(resId)
+ setButtonDrawable(mDrawableManager != null
+ ? mDrawableManager.getDrawable(getContext(), resId)
: ContextCompat.getDrawable(getContext(), resId));
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java b/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
index 51811a8..8909265 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
@@ -18,23 +18,9 @@
import android.content.Context;
import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Shader;
-import android.graphics.drawable.AnimationDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ClipDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RoundRectShape;
-import android.graphics.drawable.shapes.Shape;
-import android.support.v4.graphics.drawable.DrawableWrapper;
import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
-import android.view.Gravity;
import android.widget.RatingBar;
/**
@@ -45,12 +31,8 @@
*/
public class AppCompatRatingBar extends RatingBar {
- private static final int[] TINT_ATTRS = {
- android.R.attr.indeterminateDrawable,
- android.R.attr.progressDrawable
- };
-
- private Bitmap mSampleTile;
+ private AppCompatProgressBarHelper mAppCompatProgressBarHelper;
+ private AppCompatDrawableManager mDrawableManager;
public AppCompatRatingBar(Context context) {
this(context, null);
@@ -63,104 +45,19 @@
public AppCompatRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
+ mDrawableManager = AppCompatDrawableManager.get();
- Drawable drawable = a.getDrawableIfKnown(0);
- if (drawable != null) {
- setIndeterminateDrawable(tileifyIndeterminate(drawable));
- }
-
- drawable = a.getDrawableIfKnown(1);
- if (drawable != null) {
- setProgressDrawable(tileify(drawable, false));
- }
-
- a.recycle();
- }
- }
-
- /**
- * Converts a drawable to a tiled version of itself. It will recursively
- * traverse layer and state list drawables.
- */
- private Drawable tileify(Drawable drawable, boolean clip) {
- if (drawable instanceof DrawableWrapper) {
- Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable();
- if (inner != null) {
- inner = tileify(inner, clip);
- ((DrawableWrapper) drawable).setWrappedDrawable(inner);
- }
- } else if (drawable instanceof LayerDrawable) {
- LayerDrawable background = (LayerDrawable) drawable;
- final int N = background.getNumberOfLayers();
- Drawable[] outDrawables = new Drawable[N];
-
- for (int i = 0; i < N; i++) {
- int id = background.getId(i);
- outDrawables[i] = tileify(background.getDrawable(i),
- (id == android.R.id.progress || id == android.R.id.secondaryProgress));
- }
- LayerDrawable newBg = new LayerDrawable(outDrawables);
-
- for (int i = 0; i < N; i++) {
- newBg.setId(i, background.getId(i));
- }
-
- return newBg;
-
- } else if (drawable instanceof BitmapDrawable) {
- final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
- if (mSampleTile == null) {
- mSampleTile = tileBitmap;
- }
-
- final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
- final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
- Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
- shapeDrawable.getPaint().setShader(bitmapShader);
- return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
- ClipDrawable.HORIZONTAL) : shapeDrawable;
- }
-
- return drawable;
- }
-
- /**
- * Convert a AnimationDrawable for use as a barberpole animation.
- * Each frame of the animation is wrapped in a ClipDrawable and
- * given a tiling BitmapShader.
- */
- private Drawable tileifyIndeterminate(Drawable drawable) {
- if (drawable instanceof AnimationDrawable) {
- AnimationDrawable background = (AnimationDrawable) drawable;
- final int N = background.getNumberOfFrames();
- AnimationDrawable newBg = new AnimationDrawable();
- newBg.setOneShot(background.isOneShot());
-
- for (int i = 0; i < N; i++) {
- Drawable frame = tileify(background.getFrame(i), true);
- frame.setLevel(10000);
- newBg.addFrame(frame, background.getDuration(i));
- }
- newBg.setLevel(10000);
- drawable = newBg;
- }
- return drawable;
- }
-
- private Shape getDrawableShape() {
- final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
- return new RoundRectShape(roundedCorners, null, null);
+ mAppCompatProgressBarHelper = new AppCompatProgressBarHelper(this, mDrawableManager);
+ mAppCompatProgressBarHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mSampleTile != null) {
- final int width = mSampleTile.getWidth() * getNumStars();
+ Bitmap sampleTile = mAppCompatProgressBarHelper.getSampleTime();
+ if (sampleTile != null) {
+ final int width = sampleTile.getWidth() * getNumStars();
setMeasuredDimension(ViewCompat.resolveSizeAndState(width, widthMeasureSpec, 0),
getMeasuredHeight());
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java
new file mode 100644
index 0000000..4f3ee05
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.support.v7.appcompat.R;
+import android.util.AttributeSet;
+import android.widget.SeekBar;
+
+/**
+ * A {@link SeekBar} which supports compatible features on older version of the platform.
+ *
+ * <p>This will automatically be used when you use {@link SeekBar} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
+ */
+public class AppCompatSeekBar extends SeekBar {
+
+ private AppCompatSeekBarHelper mAppCompatSeekBarHelper;
+ private AppCompatDrawableManager mDrawableManager;
+
+ public AppCompatSeekBar(Context context) {
+ this(context, null);
+ }
+
+ public AppCompatSeekBar(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.seekBarStyle);
+ }
+
+ public AppCompatSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ mDrawableManager = AppCompatDrawableManager.get();
+
+ mAppCompatSeekBarHelper = new AppCompatSeekBarHelper(this, mDrawableManager);
+ mAppCompatSeekBarHelper.loadFromAttributes(attrs, defStyleAttr);
+ }
+
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java
new file mode 100644
index 0000000..2af2acc
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.SeekBar;
+
+class AppCompatSeekBarHelper extends AppCompatProgressBarHelper {
+
+ private static final int[] TINT_ATTRS = {
+ android.R.attr.thumb
+ };
+
+ private final SeekBar mView;
+
+ AppCompatSeekBarHelper(SeekBar view, AppCompatDrawableManager drawableManager) {
+ super(view, drawableManager);
+ mView = view;
+ }
+
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+ super.loadFromAttributes(attrs, defStyleAttr);
+
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
+ TINT_ATTRS, defStyleAttr, 0);
+ Drawable drawable = a.getDrawableIfKnown(0);
+ if (drawable != null) {
+ mView.setThumb(drawable);
+ }
+ a.recycle();
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
index 90985cdb..964ea76 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
@@ -30,10 +30,7 @@
import android.support.v4.view.TintableBackgroundView;
import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ContextThemeWrapper;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ViewUtils;
+import android.support.v7.view.ContextThemeWrapper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -41,6 +38,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.PopupWindow;
@@ -77,7 +75,7 @@
private static final int MODE_DROPDOWN = 1;
private static final int MODE_THEME = -1;
- private TintManager mTintManager;
+ private AppCompatDrawableManager mDrawableManager;
private AppCompatBackgroundHelper mBackgroundTintHelper;
@@ -199,8 +197,8 @@
TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.Spinner, defStyleAttr, 0);
- mTintManager = a.getTintManager();
- mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mDrawableManager = AppCompatDrawableManager.get();
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
if (popupTheme != null) {
mPopupContext = new ContextThemeWrapper(context, popupTheme);
@@ -267,6 +265,15 @@
};
}
}
+
+ final CharSequence[] entries = a.getTextArray(R.styleable.Spinner_android_entries);
+ if (entries != null) {
+ final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<>(context,
+ R.layout.support_simple_spinner_dropdown_item, entries);
+ adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
+ setAdapter(adapter);
+ }
+
a.recycle();
mPopupSet = true;
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
index 7a75e76..d8e7784 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
@@ -19,30 +19,59 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.text.AllCapsTransformationMethod;
-import android.support.v7.internal.widget.ThemeUtils;
+import android.support.v7.text.AllCapsTransformationMethod;
import android.util.AttributeSet;
import android.widget.TextView;
class AppCompatTextHelper {
- private static final int[] VIEW_ATTRS = {android.R.attr.textAppearance};
+ static AppCompatTextHelper create(TextView textView) {
+ if (Build.VERSION.SDK_INT >= 17) {
+ return new AppCompatTextHelperV17(textView);
+ }
+ return new AppCompatTextHelper(textView);
+ }
+
+ private static final int[] VIEW_ATTRS = {android.R.attr.textAppearance,
+ android.R.attr.drawableLeft, android.R.attr.drawableTop,
+ android.R.attr.drawableRight, android.R.attr.drawableBottom };
private static final int[] TEXT_APPEARANCE_ATTRS = {R.attr.textAllCaps};
- private final TextView mView;
+ final TextView mView;
+
+ private TintInfo mDrawableLeftTint;
+ private TintInfo mDrawableTopTint;
+ private TintInfo mDrawableRightTint;
+ private TintInfo mDrawableBottomTint;
AppCompatTextHelper(TextView view) {
mView = view;
}
void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
- Context context = mView.getContext();
+ final Context context = mView.getContext();
+ final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
// First read the TextAppearance style id
TypedArray a = context.obtainStyledAttributes(attrs, VIEW_ATTRS, defStyleAttr, 0);
final int ap = a.getResourceId(0, -1);
+
+ // Now read the compound drawable and grab any tints
+ if (a.hasValue(1)) {
+ mDrawableLeftTint = createTintInfo(context, drawableManager, a.getResourceId(1, 0));
+ }
+ if (a.hasValue(2)) {
+ mDrawableTopTint = createTintInfo(context, drawableManager, a.getResourceId(2, 0));
+ }
+ if (a.hasValue(3)) {
+ mDrawableRightTint = createTintInfo(context, drawableManager, a.getResourceId(3, 0));
+ }
+ if (a.hasValue(4)) {
+ mDrawableBottomTint = createTintInfo(context, drawableManager, a.getResourceId(4, 0));
+ }
a.recycle();
// Now check TextAppearance's textAllCaps value
@@ -56,33 +85,10 @@
// Now read the style's value
a = context.obtainStyledAttributes(attrs, TEXT_APPEARANCE_ATTRS, defStyleAttr, 0);
- if (a.hasValue(0)) {
- setAllCaps(a.getBoolean(0, false));
+ if (a.getBoolean(0, false)) {
+ setAllCaps(true);
}
a.recycle();
-
- final ColorStateList textColors = mView.getTextColors();
- if (textColors != null && !textColors.isStateful()) {
- // If we have a ColorStateList which isn't stateful, create one which includes
- // a disabled state
-
- final int disabledTextColor;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- // Pre-Lollipop, we will use textColorSecondary with android:disabledAlpha
- // applied
- disabledTextColor = ThemeUtils.getDisabledThemeAttrColor(context,
- android.R.attr.textColorSecondary);
- } else {
- // With certain styles on Lollipop, there is a StateListAnimator which sets
- // an alpha on the whole view, so we don't need to apply disabledAlpha to
- // textColorSecondary
- disabledTextColor = ThemeUtils.getThemeAttrColor(context,
- android.R.attr.textColorSecondary);
- }
-
- mView.setTextColor(ThemeUtils.createDisabledStateList(
- textColors.getDefaultColor(), disabledTextColor));
- }
}
void onSetTextAppearance(Context context, int resId) {
@@ -98,4 +104,32 @@
? new AllCapsTransformationMethod(mView.getContext())
: null);
}
+
+ void applyCompoundDrawablesTints() {
+ if (mDrawableLeftTint != null || mDrawableTopTint != null ||
+ mDrawableRightTint != null || mDrawableBottomTint != null) {
+ final Drawable[] compoundDrawables = mView.getCompoundDrawables();
+ applyCompoundDrawableTint(compoundDrawables[0], mDrawableLeftTint);
+ applyCompoundDrawableTint(compoundDrawables[1], mDrawableTopTint);
+ applyCompoundDrawableTint(compoundDrawables[2], mDrawableRightTint);
+ applyCompoundDrawableTint(compoundDrawables[3], mDrawableBottomTint);
+ }
+ }
+
+ final void applyCompoundDrawableTint(Drawable drawable, TintInfo info) {
+ if (drawable != null && info != null) {
+ AppCompatDrawableManager.tintDrawable(drawable, info, mView.getDrawableState());
+ }
+ }
+
+ protected static TintInfo createTintInfo(Context context,
+ AppCompatDrawableManager drawableManager, int drawableId) {
+ final ColorStateList tintList = drawableManager.getTintList(context, drawableId);
+ if (tintList != null) {
+ final TintInfo tintInfo = new TintInfo();
+ tintInfo.mHasTintList = true;
+ tintInfo.mTintList = tintList;
+ }
+ return null;
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java
new file mode 100644
index 0000000..18047e7
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+class AppCompatTextHelperV17 extends AppCompatTextHelper {
+
+ private static final int[] VIEW_ATTRS_v17 = {
+ android.R.attr.drawableStart, android.R.attr.drawableEnd };
+
+ private TintInfo mDrawableStartTint;
+ private TintInfo mDrawableEndTint;
+
+ AppCompatTextHelperV17(TextView view) {
+ super(view);
+ }
+
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+ super.loadFromAttributes(attrs, defStyleAttr);
+
+ final Context context = mView.getContext();
+ final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
+
+ TypedArray a = context.obtainStyledAttributes(attrs, VIEW_ATTRS_v17, defStyleAttr, 0);
+ if (a.hasValue(0)) {
+ mDrawableStartTint = createTintInfo(context, drawableManager, a.getResourceId(0, 0));
+ }
+ if (a.hasValue(1)) {
+ mDrawableEndTint = createTintInfo(context, drawableManager, a.getResourceId(1, 0));
+ }
+ a.recycle();
+ }
+
+ @Override
+ void applyCompoundDrawablesTints() {
+ super.applyCompoundDrawablesTints();
+
+ if (mDrawableStartTint != null || mDrawableEndTint != null) {
+ final Drawable[] compoundDrawables = mView.getCompoundDrawablesRelative();
+ applyCompoundDrawableTint(compoundDrawables[0], mDrawableStartTint);
+ applyCompoundDrawableTint(compoundDrawables[2], mDrawableEndTint);
+ }
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
index ccedfe0..b21f6bc 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
@@ -17,6 +17,12 @@
package android.support.v7.widget;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
import android.util.AttributeSet;
import android.widget.TextView;
@@ -27,13 +33,19 @@
* <ul>
* <li>Supports {@link R.attr#textAllCaps} style attribute which works back to
* {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.view.ViewCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ * {@link R.attr#backgroundTintMode}.</li>
* </ul>
*
* <p>This will automatically be used when you use {@link TextView} in your layouts.
* You should only need to manually use this class when writing custom views.</p>
*/
-public class AppCompatTextView extends TextView {
+public class AppCompatTextView extends TextView implements TintableBackgroundView {
+ private AppCompatDrawableManager mDrawableManager;
+ private AppCompatBackgroundHelper mBackgroundTintHelper;
private AppCompatTextHelper mTextHelper;
public AppCompatTextView(Context context) {
@@ -47,8 +59,81 @@
public AppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mTextHelper = new AppCompatTextHelper(this);
+ mDrawableManager = AppCompatDrawableManager.get();
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mDrawableManager);
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+ mTextHelper = AppCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+ mTextHelper.applyCompoundDrawablesTints();
+ }
+
+ @Override
+ public void setBackgroundResource(@DrawableRes int resId) {
+ super.setBackgroundResource(resId);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundResource(resId);
+ }
+ }
+
+ @Override
+ public void setBackgroundDrawable(Drawable background) {
+ super.setBackgroundDrawable(background);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundDrawable(background);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
+ *
+ * @hide
+ */
+ @Override
+ public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#getBackgroundTintList(android.view.View)}
+ *
+ * @hide
+ */
+ @Override
+ @Nullable
+ public ColorStateList getSupportBackgroundTintList() {
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
+ *
+ * @hide
+ */
+ @Override
+ public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+ }
+ }
+
+ /**
+ * This should be accessed via
+ * {@link android.support.v4.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+ *
+ * @hide
+ */
+ @Override
+ @Nullable
+ public PorterDuff.Mode getSupportBackgroundTintMode() {
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
}
@Override
@@ -58,4 +143,15 @@
mTextHelper.onSetTextAppearance(context, resId);
}
}
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.applySupportBackgroundTint();
+ }
+ if (mTextHelper != null) {
+ mTextHelper.applyCompoundDrawablesTints();
+ }
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java b/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java
new file mode 100644
index 0000000..20fa89d
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v7.appcompat.R;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ *
+ * @hide
+ */
+public class ButtonBarLayout extends LinearLayout {
+
+ /** Whether the current configuration allows stacking. */
+ private boolean mAllowStacking;
+ private int mLastWidthSize = -1;
+
+ public ButtonBarLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ButtonBarLayout);
+ mAllowStacking = ta.getBoolean(R.styleable.ButtonBarLayout_allowStacking, false);
+ ta.recycle();
+ }
+
+ public void setAllowStacking(boolean allowStacking) {
+ if (mAllowStacking != allowStacking) {
+ mAllowStacking = allowStacking;
+ if (!mAllowStacking && getOrientation() == LinearLayout.VERTICAL) {
+ setStacked(false);
+ }
+ requestLayout();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ if (mAllowStacking) {
+ if (widthSize > mLastWidthSize && isStacked()) {
+ // We're being measured wider this time, try un-stacking.
+ setStacked(false);
+ }
+ mLastWidthSize = widthSize;
+ }
+ boolean needsRemeasure = false;
+ // If we're not stacked, make sure the measure spec is AT_MOST rather
+ // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we
+ // know to stack the buttons.
+ final int initialWidthMeasureSpec;
+ if (!isStacked() && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
+ initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
+ // We'll need to remeasure again to fill excess space.
+ needsRemeasure = true;
+ } else {
+ initialWidthMeasureSpec = widthMeasureSpec;
+ }
+ super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
+ if (mAllowStacking && !isStacked()) {
+ final int measuredWidth = getMeasuredWidthAndState();
+ final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+ if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+ setStacked(true);
+ // Measure again in the new orientation.
+ needsRemeasure = true;
+ }
+ }
+ if (needsRemeasure) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ private void setStacked(boolean stacked) {
+ setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+ setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+ final View spacer = findViewById(R.id.spacer);
+ if (spacer != null) {
+ spacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+ }
+ // Reverse the child order. This is specific to the Material button
+ // bar's layout XML and will probably not generalize.
+ final int childCount = getChildCount();
+ for (int i = childCount - 2; i >= 0; i--) {
+ bringChildToFront(getChildAt(i));
+ }
+ }
+
+ private boolean isStacked() {
+ return getOrientation() == LinearLayout.VERTICAL;
+ }
+}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ContentFrameLayout.java b/v7/appcompat/src/android/support/v7/widget/ContentFrameLayout.java
similarity index 89%
rename from v7/appcompat/src/android/support/v7/internal/widget/ContentFrameLayout.java
rename to v7/appcompat/src/android/support/v7/widget/ContentFrameLayout.java
index 7de9c8b..9a0de68 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ContentFrameLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/ContentFrameLayout.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.graphics.Rect;
@@ -33,6 +33,11 @@
*/
public class ContentFrameLayout extends FrameLayout {
+ public interface OnAttachListener {
+ void onDetachedFromWindow();
+ void onAttachedFromWindow();
+ }
+
private TypedValue mMinWidthMajor;
private TypedValue mMinWidthMinor;
private TypedValue mFixedWidthMajor;
@@ -42,6 +47,8 @@
private final Rect mDecorPadding;
+ private OnAttachListener mAttachListener;
+
public ContentFrameLayout(Context context) {
this(context, null);
}
@@ -62,6 +69,10 @@
fitSystemWindows(insets);
}
+ public void setAttachListener(OnAttachListener attachListener) {
+ mAttachListener = attachListener;
+ }
+
/**
* Notify this view of the window decor view's padding. We use these values when working out
* our size for the window size attributes.
@@ -181,4 +192,20 @@
if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
return mFixedHeightMinor;
}
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mAttachListener != null) {
+ mAttachListener.onAttachedFromWindow();
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mAttachListener != null) {
+ mAttachListener.onDetachedFromWindow();
+ }
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DecorContentParent.java b/v7/appcompat/src/android/support/v7/widget/DecorContentParent.java
similarity index 94%
rename from v7/appcompat/src/android/support/v7/internal/widget/DecorContentParent.java
rename to v7/appcompat/src/android/support/v7/widget/DecorContentParent.java
index e4400ac..a311416 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DecorContentParent.java
+++ b/v7/appcompat/src/android/support/v7/widget/DecorContentParent.java
@@ -15,11 +15,11 @@
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
-import android.support.v7.internal.view.menu.MenuPresenter;
+import android.support.v7.view.menu.MenuPresenter;
import android.util.SparseArray;
import android.view.Menu;
import android.view.Window;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java b/v7/appcompat/src/android/support/v7/widget/DecorToolbar.java
similarity index 95%
rename from v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java
rename to v7/appcompat/src/android/support/v7/widget/DecorToolbar.java
index 52d53b3..a334139 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java
+++ b/v7/appcompat/src/android/support/v7/widget/DecorToolbar.java
@@ -15,14 +15,14 @@
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
import android.support.v4.view.ViewPropertyAnimatorCompat;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPresenter;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPresenter;
import android.util.SparseArray;
import android.view.Menu;
import android.view.View;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DialogTitle.java b/v7/appcompat/src/android/support/v7/widget/DialogTitle.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/DialogTitle.java
rename to v7/appcompat/src/android/support/v7/widget/DialogTitle.java
index 446d70d..052efff 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DialogTitle.java
+++ b/v7/appcompat/src/android/support/v7/widget/DialogTitle.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.TypedArray;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DrawableUtils.java b/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/widget/DrawableUtils.java
rename to v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
index 1ff5e4d..b57b40f 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DrawableUtils.java
+++ b/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -25,10 +25,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-/**
- * @hide
- */
-public class DrawableUtils {
+class DrawableUtils {
private static final String TAG = "DrawableUtils";
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsFrameLayout.java b/v7/appcompat/src/android/support/v7/widget/FitWindowsFrameLayout.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/widget/FitWindowsFrameLayout.java
rename to v7/appcompat/src/android/support/v7/widget/FitWindowsFrameLayout.java
index 49f95fa..53750f8 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsFrameLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/FitWindowsFrameLayout.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.graphics.Rect;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsLinearLayout.java b/v7/appcompat/src/android/support/v7/widget/FitWindowsLinearLayout.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/widget/FitWindowsLinearLayout.java
rename to v7/appcompat/src/android/support/v7/widget/FitWindowsLinearLayout.java
index 6adf74d..e2f7a73 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsLinearLayout.java
+++ b/v7/appcompat/src/android/support/v7/widget/FitWindowsLinearLayout.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.graphics.Rect;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java b/v7/appcompat/src/android/support/v7/widget/FitWindowsViewGroup.java
similarity index 95%
rename from v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java
rename to v7/appcompat/src/android/support/v7/widget/FitWindowsViewGroup.java
index c84fda0..098a23e 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/FitWindowsViewGroup.java
+++ b/v7/appcompat/src/android/support/v7/widget/FitWindowsViewGroup.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.graphics.Rect;
diff --git a/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java b/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
index b89115c..a6dce15 100644
--- a/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
@@ -25,8 +25,6 @@
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ViewUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
diff --git a/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java b/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
index 0d2bcb8..5779599 100644
--- a/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
+++ b/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
@@ -26,12 +26,11 @@
import android.os.SystemClock;
import android.support.v4.text.TextUtilsCompat;
import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.widget.ListViewAutoScrollHelper;
import android.support.v4.widget.PopupWindowCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.AppCompatPopupWindow;
-import android.support.v7.internal.widget.ListViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -43,6 +42,7 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.LinearLayout;
@@ -74,6 +74,7 @@
private static final int EXPAND_LIST_TIMEOUT = 250;
private static Method sClipToWindowEnabledMethod;
+ private static Method sGetMaxAvailableHeightMethod;
static {
try {
@@ -82,6 +83,13 @@
} catch (NoSuchMethodException e) {
Log.i(TAG, "Could not find method setClipToScreenEnabled() on PopupWindow. Oh well.");
}
+ try {
+ sGetMaxAvailableHeightMethod = PopupWindow.class.getDeclaredMethod(
+ "getMaxAvailableHeight", View.class, int.class, boolean.class);
+ } catch (NoSuchMethodException e) {
+ Log.i(TAG, "Could not find method getMaxAvailableHeight(View, int, boolean)"
+ + " on PopupWindow. Oh well.");
+ }
}
private Context mContext;
@@ -93,6 +101,7 @@
private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
private int mDropDownHorizontalOffset;
private int mDropDownVerticalOffset;
+ private int mDropDownWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
private boolean mDropDownVerticalOffsetSet;
private int mDropDownGravity = Gravity.NO_GRAVITY;
@@ -119,7 +128,7 @@
private final ListSelectorHider mHideSelector = new ListSelectorHider();
private Runnable mShowDropDownRunnable;
- private Handler mHandler = new Handler();
+ private final Handler mHandler;
private Rect mTempRect = new Rect();
@@ -226,6 +235,7 @@
*/
public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
mContext = context;
+ mHandler = new Handler(context.getMainLooper());
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ListPopupWindow,
defStyleAttr, defStyleRes);
@@ -531,6 +541,19 @@
}
/**
+ * Set the layout type for this popup window.
+ * <p>
+ * See {@link WindowManager.LayoutParams#type} for possible values.
+ *
+ * @param layoutType Layout type for this window.
+ *
+ * @see WindowManager.LayoutParams#type
+ */
+ public void setWindowLayoutType(int layoutType) {
+ mDropDownWindowLayoutType = layoutType;
+ }
+
+ /**
* Sets a listener to receive events when a list item is clicked.
*
* @param clickListener Listener to register
@@ -583,12 +606,11 @@
public void show() {
int height = buildDropDown();
- int widthSpec = 0;
- int heightSpec = 0;
-
boolean noInputMethod = isInputMethodNotNeeded();
+ PopupWindowCompat.setWindowLayoutType(mPopup, mDropDownWindowLayoutType);
if (mPopup.isShowing()) {
+ final int widthSpec;
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
// The call to PopupWindow's update method below can accept -1 for any
// value you do not want to update.
@@ -599,19 +621,19 @@
widthSpec = mDropDownWidth;
}
+ final int heightSpec;
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
// The call to PopupWindow's update method below can accept -1 for any
// value you do not want to update.
heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
if (noInputMethod) {
- mPopup.setWindowLayoutMode(
- mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
- ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
+ mPopup.setWidth(mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+ ViewGroup.LayoutParams.MATCH_PARENT : 0);
+ mPopup.setHeight(0);
} else {
- mPopup.setWindowLayoutMode(
- mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
- ViewGroup.LayoutParams.MATCH_PARENT : 0,
- ViewGroup.LayoutParams.MATCH_PARENT);
+ mPopup.setWidth(mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+ ViewGroup.LayoutParams.MATCH_PARENT : 0);
+ mPopup.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
}
} else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
heightSpec = height;
@@ -622,29 +644,33 @@
mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
mPopup.update(getAnchorView(), mDropDownHorizontalOffset,
- mDropDownVerticalOffset, widthSpec, heightSpec);
+ mDropDownVerticalOffset, (widthSpec < 0)? -1 : widthSpec,
+ (heightSpec < 0)? -1 : heightSpec);
} else {
+ final int widthSpec;
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
- mPopup.setWidth(getAnchorView().getWidth());
+ widthSpec = getAnchorView().getWidth();
} else {
- mPopup.setWidth(mDropDownWidth);
+ widthSpec = mDropDownWidth;
}
}
+ final int heightSpec;
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
- mPopup.setHeight(height);
+ heightSpec = height;
} else {
- mPopup.setHeight(mDropDownHeight);
+ heightSpec = mDropDownHeight;
}
}
- mPopup.setWindowLayoutMode(widthSpec, heightSpec);
+ mPopup.setWidth(widthSpec);
+ mPopup.setHeight(heightSpec);
setPopupClipToScreenEnabled(true);
// use outside touchable to dismiss drop down when touching outside of it, so
@@ -1126,10 +1152,19 @@
break;
}
- // measure the hint's height to find how much more vertical space
- // we need to add to the drop down's height
- int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.UNSPECIFIED;
+ // Measure the hint's height to find how much more vertical
+ // space we need to add to the drop down's height.
+ final int widthSize;
+ final int widthMode;
+ if (mDropDownWidth >= 0) {
+ widthMode = MeasureSpec.AT_MOST;
+ widthSize = mDropDownWidth;
+ } else {
+ widthMode = MeasureSpec.UNSPECIFIED;
+ widthSize = 0;
+ }
+ final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
+ final int heightSpec = MeasureSpec.UNSPECIFIED;
hintView.measure(widthSpec, heightSpec);
hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
@@ -1169,11 +1204,10 @@
}
// Max height available on the screen for a popup.
- boolean ignoreBottomDecorations =
+ final boolean ignoreBottomDecorations =
mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
- final int maxHeight = mPopup.getMaxAvailableHeight(
- getAnchorView(), mDropDownVerticalOffset /*, ignoreBottomDecorations*/);
-
+ final int maxHeight = getMaxAvailableHeight(getAnchorView(), mDropDownVerticalOffset,
+ ignoreBottomDecorations);
if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
return maxHeight + padding;
}
@@ -1629,6 +1663,11 @@
// This will call through to updateSelectorState()
drawableStateChanged();
+ final View motionView = getChildAt(mMotionPosition - getFirstVisiblePosition());
+ if (motionView != null) {
+ motionView.setPressed(false);
+ }
+
if (mClickAnimation != null) {
mClickAnimation.cancel();
mClickAnimation = null;
@@ -1638,11 +1677,37 @@
private void setPressedItem(View child, int position, float x, float y) {
mDrawsInPressedState = true;
- // Ordering is essential. First update the pressed state and layout
- // the children. This will ensure the selector actually gets drawn.
- setPressed(true);
+ // Ordering is essential. First, update the container's pressed state.
+ if (Build.VERSION.SDK_INT >= 21) {
+ drawableHotspotChanged(x, y);
+ }
+ if (!isPressed()) {
+ setPressed(true);
+ }
+
+ // Next, run layout to stabilize child positions.
layoutChildren();
+ // Manage the pressed view based on motion position. This allows us to
+ // play nicely with actual touch and scroll events.
+ if (mMotionPosition != INVALID_POSITION) {
+ final View motionView = getChildAt(mMotionPosition - getFirstVisiblePosition());
+ if (motionView != null && motionView != child && motionView.isPressed()) {
+ motionView.setPressed(false);
+ }
+ }
+ mMotionPosition = position;
+
+ // Offset for child coordinates.
+ final float childX = x - child.getLeft();
+ final float childY = y - child.getTop();
+ if (Build.VERSION.SDK_INT >= 21) {
+ child.drawableHotspotChanged(childX, childY);
+ }
+ if (!child.isPressed()) {
+ child.setPressed(true);
+ }
+
// Ensure that keyboard focus starts from the last touched position.
setSelection(position);
positionSelectorLikeTouchCompat(position, child, x, y);
@@ -1697,7 +1762,6 @@
public boolean hasFocus() {
return mHijackFocus || super.hasFocus();
}
-
}
private class PopupDataSetObserver extends DataSetObserver {
@@ -1723,8 +1787,9 @@
private class ResizePopupRunnable implements Runnable {
public void run() {
- if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() &&
- mDropDownList.getChildCount() <= mListItemExpandMaximum) {
+ if (mDropDownList != null && ViewCompat.isAttachedToWindow(mDropDownList)
+ && mDropDownList.getCount() > mDropDownList.getChildCount()
+ && mDropDownList.getChildCount() <= mListItemExpandMaximum) {
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
show();
}
@@ -1777,4 +1842,16 @@
}
}
+ private int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
+ if (sGetMaxAvailableHeightMethod != null) {
+ try {
+ return (int) sGetMaxAvailableHeightMethod.invoke(mPopup, anchor, yOffset,
+ ignoreBottomDecorations);
+ } catch (Exception e) {
+ Log.i(TAG, "Could not call getMaxAvailableHeightMethod(View, int, boolean)"
+ + " on PopupWindow. Using the public version.");
+ }
+ }
+ return mPopup.getMaxAvailableHeight(anchor, yOffset);
+ }
}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ListViewCompat.java b/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
similarity index 94%
rename from v7/appcompat/src/android/support/v7/internal/widget/ListViewCompat.java
rename to v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
index e2e6c4c..573a1f3 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ListViewCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.graphics.Canvas;
@@ -23,6 +23,7 @@
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.graphics.drawable.DrawableWrapper;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
@@ -50,6 +51,8 @@
int mSelectionRightPadding = 0;
int mSelectionBottomPadding = 0;
+ protected int mMotionPosition;
+
private Field mIsChildViewEnabled;
private GateKeeperDrawable mSelector;
@@ -107,6 +110,16 @@
super.dispatchDraw(canvas);
}
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mMotionPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
+ break;
+ }
+ return super.onTouchEvent(ev);
+ }
+
protected void updateSelectorStateCompat() {
Drawable selector = getSelector();
if (selector != null && shouldShowSelectorCompat()) {
@@ -291,8 +304,14 @@
// Compute child height spec
int heightMeasureSpec;
- final ViewGroup.LayoutParams childLp = child.getLayoutParams();
- if (childLp != null && childLp.height > 0) {
+ ViewGroup.LayoutParams childLp = child.getLayoutParams();
+
+ if (childLp == null) {
+ childLp = generateDefaultLayoutParams();
+ child.setLayoutParams(childLp);
+ }
+
+ if (childLp.height > 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(childLp.height,
MeasureSpec.EXACTLY);
} else {
@@ -300,6 +319,10 @@
}
child.measure(widthMeasureSpec, heightMeasureSpec);
+ // Since this view was measured directly aginst the parent measure
+ // spec, we must measure it again before reuse.
+ child.forceLayout();
+
if (i > 0) {
// Count the divider for all but one child
returnedHeight += dividerHeight;
@@ -383,6 +406,4 @@
return false;
}
}
-
-
}
diff --git a/v7/appcompat/src/android/support/v7/widget/PopupMenu.java b/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
index 5c4dde8..7f097c7 100644
--- a/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
+++ b/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
@@ -20,11 +20,11 @@
import android.content.Context;
import android.support.annotation.MenuRes;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPopupHelper;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
+import android.support.v7.view.SupportMenuInflater;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.view.menu.MenuPresenter;
+import android.support.v7.view.menu.SubMenuBuilder;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ResourcesWrapper.java b/v7/appcompat/src/android/support/v7/widget/ResourcesWrapper.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/widget/ResourcesWrapper.java
rename to v7/appcompat/src/android/support/v7/widget/ResourcesWrapper.java
index 48ebab8..828a792 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ResourcesWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/ResourcesWrapper.java
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import org.xmlpull.v1.XmlPullParserException;
import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -27,11 +26,9 @@
import android.content.res.XmlResourceParser;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Drawable.ConstantState;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
-import android.util.LongSparseArray;
import android.util.TypedValue;
import java.io.IOException;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/RtlSpacingHelper.java b/v7/appcompat/src/android/support/v7/widget/RtlSpacingHelper.java
similarity index 96%
rename from v7/appcompat/src/android/support/v7/internal/widget/RtlSpacingHelper.java
rename to v7/appcompat/src/android/support/v7/widget/RtlSpacingHelper.java
index e6c80d1..6a4e360 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/RtlSpacingHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/RtlSpacingHelper.java
@@ -15,16 +15,14 @@
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
/**
* RtlSpacingHelper manages the relationship between left/right and start/end for views
* that need to maintain both absolute and relative settings for a form of spacing similar
* to view padding.
- *
- * @hide
*/
-public class RtlSpacingHelper {
+class RtlSpacingHelper {
public static final int UNDEFINED = Integer.MIN_VALUE;
private int mLeft = 0;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java b/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java
rename to v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
index 0d27d32..06118bf 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.Configuration;
@@ -25,10 +25,7 @@
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.support.v7.app.ActionBar;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ActionBarPolicy;
-import android.support.v7.widget.AppCompatSpinner;
-import android.support.v7.widget.AppCompatTextView;
-import android.support.v7.widget.LinearLayoutCompat;
+import android.support.v7.view.ActionBarPolicy;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.view.Gravity;
diff --git a/v7/appcompat/src/android/support/v7/widget/SearchView.java b/v7/appcompat/src/android/support/v7/widget/SearchView.java
index 553e3ab..e4644d0 100644
--- a/v7/appcompat/src/android/support/v7/widget/SearchView.java
+++ b/v7/appcompat/src/android/support/v7/widget/SearchView.java
@@ -39,9 +39,6 @@
import android.support.v4.view.KeyEventCompat;
import android.support.v4.widget.CursorAdapter;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ViewUtils;
import android.support.v7.view.CollapsibleActionView;
import android.text.Editable;
import android.text.InputType;
@@ -162,7 +159,7 @@
private SearchableInfo mSearchable;
private Bundle mAppSearchData;
- private final TintManager mTintManager;
+ private final AppCompatDrawableManager mDrawableManager;
static final AutoCompleteTextViewReflector HIDDEN_METHOD_INVOKER = new AutoCompleteTextViewReflector();
@@ -278,10 +275,10 @@
public SearchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mDrawableManager = AppCompatDrawableManager.get();
+
final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context,
attrs, R.styleable.SearchView, defStyleAttr, 0);
- // Keep the TintManager in case we need it later
- mTintManager = a.getTintManager();
final LayoutInflater inflater = LayoutInflater.from(context);
final int layoutResId = a.getResourceId(
@@ -829,7 +826,15 @@
mSearchButton.setVisibility(visCollapsed);
updateSubmitButton(hasText);
mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE);
- mCollapsedIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
+
+ final int iconVisibility;
+ if (mCollapsedIcon.getDrawable() == null || mIconifiedByDefault) {
+ iconVisibility = GONE;
+ } else {
+ iconVisibility = VISIBLE;
+ }
+ mCollapsedIcon.setVisibility(iconVisibility);
+
updateCloseButton();
updateVoiceButton(!hasText);
updateSubmitArea();
diff --git a/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java b/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java
index a840f95..25f6cc5 100644
--- a/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java
+++ b/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java
@@ -24,63 +24,101 @@
import android.os.Build;
import android.support.v4.view.ActionProvider;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.ActivityChooserModel;
-import android.support.v7.internal.widget.ActivityChooserView;
-import android.support.v7.internal.widget.TintManager;
+import android.support.v7.widget.ActivityChooserModel.OnChooseActivityListener;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
-import android.support.v7.internal.widget.ActivityChooserModel.OnChooseActivityListener;
/**
- * This is a provider for a share action. It is responsible for creating views
- * that enable data sharing and also to show a sub menu with sharing activities
- * if the hosting item is placed on the overflow menu.
+ * Provides a share action, which is suitable for an activity's app bar. Creates
+ * views that enable data sharing. If the provider appears in the
+ * overflow menu, it creates a submenu with the appropriate sharing
+ * actions.
*
- * <p class="note"><strong>Note:</strong> This class is included in the <a
- * href="{@docRoot}tools/extras/support-library.html">support library</a> for compatibility
- * with API level 7 and higher. If you're developing your app for API level 14 and higher
- * <em>only</em>, you should instead use the framework {@link android.widget.ShareActionProvider}
- * class.</p>
+ * <h3 id="add-share-action">Adding a share action</h3>
*
- * <p>
- * Here is how to use the action provider with custom backing file in a {@link MenuItem}:
- * </p>
- * <pre><code>
- * // In {@link android.app.Activity#onCreateOptionsMenu Activity.onCreateOptionsMenu()}
- * public boolean onCreateOptionsMenu(Menu menu) {
- * // Get the menu item.
- * MenuItem menuItem = menu.findItem(R.id.my_menu_item);
- * // Get the provider and hold onto it to set/change the share intent.
- * mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);
- * // Set history different from the default before getting the action
- * // view since a call to {@link android.support.v4.view.MenuItemCompat#getActionView(android.view.MenuItem) MenuItemCompat.getActionView()} calls
- * // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
- * // line if using the default share history file is desired.
- * mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
- * . . .
- * }
+ * <p>To add a "share" action to your activity, put a
+ * <code>ShareActionProvider</code> in the app bar's menu resource. For
+ * example:</p>
*
- * // Somewhere in the application.
- * public void doShare(Intent shareIntent) {
- * // When you want to share set the share intent.
- * mShareActionProvider.setShareIntent(shareIntent);
- * }
- * </code></pre>
- * <p>
- * <strong>Note:</strong> While the sample snippet demonstrates how to use this provider
- * in the context of a menu item, the use of the provider is not limited to menu items.
- * </p>
+ * <pre>
+ * <item android:id="@+id/action_share"
+ * android:title="@string/share"
+ * app:showAsAction="ifRoom"
+ * app:actionProviderClass="android.support.v7.widget.ShareActionProvider"/>
+ * </pre>
*
- * <div class="special reference">
- * <h3>Developer Guides</h3>
+ * <p>You do not need to specify an icon, since the
+ * <code>ShareActionProvider</code> widget takes care of its own appearance and
+ * behavior. However, you do need to specify a title with
+ * <code>android:title</code>, in case the action ends up in the overflow
+ * menu.</p>
*
- * <p>For information about how to use {@link ShareActionProvider}, see the
- * <a href="{@docRoot}guide/topics/ui/actionbar.html#ActionProvider">Action Bar</a> API guide.</p>
- * </div>
+ * <p>Next, set up the intent that contains the content your activity is
+ * able to share. You should create this intent in your handler for
+ * {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()},
+ * and update it every time the shareable content changes. To set up the
+ * intent:</p>
+ *
+ * <ol>
+ * <li>Get a reference to the ShareActionProvider by calling {@link
+ * android.view.MenuItem#getActionProvider getActionProvider()} and
+ * passing the share action's {@link android.view.MenuItem}. For
+ * example:
+ *
+ * <pre>
+ * MenuItem shareItem = menu.findItem(R.id.action_share);
+ * ShareActionProvider myShareActionProvider =
+ * (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);</pre></li>
+ *
+ * <li>Create an intent with the {@link android.content.Intent#ACTION_SEND}
+ * action, and attach the content shared by the activity. For example, the
+ * following intent shares an image:
+ *
+ * <pre>
+ * Intent myShareIntent = new Intent(Intent.ACTION_SEND);
+ * myShareIntent.setType("image/*");
+ * myShareIntent.putExtra(Intent.EXTRA_STREAM, myImageUri);</pre></li>
+ *
+ * <li>Call {@link #setShareIntent setShareIntent()} to attach this intent to
+ * the action provider:
+ *
+ * <pre>
+ * myShareActionProvider.setShareIntent(myShareIntent);
+ * </pre></li>
+ *
+ * <li>When the content changes, modify the intent or create a new one,
+ * and call {@link #setShareIntent setShareIntent()} again. For example:
+ *
+ * <pre>
+ * // Image has changed! Update the intent:
+ * myShareIntent.putExtra(Intent.EXTRA_STREAM, myNewImageUri);
+ * myShareActionProvider.setShareIntent(myShareIntent);</pre></li>
+ * </ol>
+ *
+ * <h3 id="rankings">Share target rankings</h3>
+ *
+ * <p>The share action provider retains a ranking for each share target,
+ * based on how often the user chooses each one. The more often a user
+ * chooses a target, the higher its rank; the
+ * most-commonly used target appears in the app bar as the default target.</p>
+ *
+ * <p>By default, the target ranking information is stored in a private
+ * file with the name specified by {@link
+ * #DEFAULT_SHARE_HISTORY_FILE_NAME}. Ordinarily, the share action provider stores
+ * all the history in this single file. However, using a single set of
+ * rankings may not make sense if the
+ * share action provider is used for different kinds of content. For
+ * example, if the activity sometimes shares images and sometimes shares
+ * contacts, you would want to maintain two different sets of rankings.</p>
+ *
+ * <p>To set the history file, call {@link #setShareHistoryFileName
+ * setShareHistoryFileName()} and pass the name of an XML file. The file
+ * you specify is used until the next time you call {@link
+ * #setShareHistoryFileName setShareHistoryFileName()}.</p>
*
* @see ActionProvider
*/
@@ -188,7 +226,8 @@
// Lookup and set the expand action icon.
TypedValue outTypedValue = new TypedValue();
mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
- Drawable drawable = TintManager.getDrawable(mContext, outTypedValue.resourceId);
+ Drawable drawable = AppCompatDrawableManager.get()
+ .getDrawable(mContext, outTypedValue.resourceId);
activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
activityChooserView.setProvider(this);
diff --git a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java b/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
index 6aa55d7..f87109b 100644
--- a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
@@ -32,11 +32,7 @@
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.text.AllCapsTransformationMethod;
-import android.support.v7.internal.widget.DrawableUtils;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ViewUtils;
+import android.support.v7.text.AllCapsTransformationMethod;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
@@ -145,7 +141,7 @@
@SuppressWarnings("hiding")
private final Rect mTempRect = new Rect();
- private final TintManager mTintManager;
+ private final AppCompatDrawableManager mDrawableManager;
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
@@ -216,7 +212,7 @@
setSwitchTextAppearance(context, appearance);
}
- mTintManager = a.getTintManager();
+ mDrawableManager = AppCompatDrawableManager.get();
a.recycle();
@@ -408,7 +404,7 @@
* @param resId Resource ID of a track drawable
*/
public void setTrackResource(int resId) {
- setTrackDrawable(mTintManager.getDrawable(resId));
+ setTrackDrawable(mDrawableManager.getDrawable(getContext(), resId));
}
/**
@@ -438,7 +434,7 @@
* @param resId Resource ID of a thumb drawable
*/
public void setThumbResource(int resId) {
- setThumbDrawable(mTintManager.getDrawable(resId));
+ setThumbDrawable(mDrawableManager.getDrawable(getContext(), resId));
}
/**
@@ -742,14 +738,36 @@
if (newState != oldState) {
playSoundEffect(SoundEffectConstants.CLICK);
- setChecked(newState);
}
+ // Always call setChecked so that the thumb is moved back to the correct edge
+ setChecked(newState);
cancelSuperTouch(ev);
}
- private void animateThumbToCheckedState(boolean newCheckedState) {
- mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1 : 0);
+ private void animateThumbToCheckedState(final boolean newCheckedState) {
+ if (mPositionAnimator != null) {
+ // If there's a current animator running, cancel it
+ cancelPositionAnimator();
+ }
+
+ mPositionAnimator = new ThumbAnimation(mThumbPosition, newCheckedState ? 1f : 0f);
mPositionAnimator.setDuration(THUMB_ANIMATION_DURATION);
+ mPositionAnimator.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {}
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (mPositionAnimator == animation) {
+ // If we're still the active animation, ensure the final position
+ setThumbPosition(newCheckedState ? 1f : 0f);
+ mPositionAnimator = null;
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {}
+ });
startAnimation(mPositionAnimator);
}
@@ -787,7 +805,7 @@
// recursively with a different value, so load the REAL value...
checked = isChecked();
- if (getWindowToken() != null && ViewCompat.isLaidOut(this)) {
+ if (getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown()) {
animateThumbToCheckedState(checked);
} else {
// Immediately move the thumb to the new position.
@@ -881,7 +899,7 @@
int trackTop = switchTop;
int trackRight = switchRight;
int trackBottom = switchBottom;
- if (thumbInsets != null && !thumbInsets.isEmpty()) {
+ if (thumbInsets != null) {
if (thumbInsets.left > padding.left) {
trackLeft += thumbInsets.left - padding.left;
}
@@ -1100,12 +1118,7 @@
mTrackDrawable.jumpToCurrentState();
}
- if (mPositionAnimator != null && !mPositionAnimator.hasEnded()) {
- clearAnimation();
- // Manually set our thumb position to the end state
- setThumbPosition(mPositionAnimator.mEndPosition);
- mPositionAnimator = null;
- }
+ cancelPositionAnimator();
}
}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ThemeUtils.java b/v7/appcompat/src/android/support/v7/widget/ThemeUtils.java
similarity index 97%
rename from v7/appcompat/src/android/support/v7/internal/widget/ThemeUtils.java
rename to v7/appcompat/src/android/support/v7/widget/ThemeUtils.java
index ed5b093..1c0151b 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ThemeUtils.java
+++ b/v7/appcompat/src/android/support/v7/widget/ThemeUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -23,10 +23,7 @@
import android.support.v4.graphics.ColorUtils;
import android.util.TypedValue;
-/**
- * @hide
- */
-public class ThemeUtils {
+class ThemeUtils {
private static final ThreadLocal<TypedValue> TL_TYPED_VALUE = new ThreadLocal<>();
diff --git a/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java b/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
index 8bcc5e1..6016b57 100644
--- a/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
+++ b/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
@@ -22,7 +22,7 @@
import android.content.res.Resources.Theme;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v7.internal.view.ContextThemeWrapper;
+import android.support.v7.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintContextWrapper.java b/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
similarity index 80%
rename from v7/appcompat/src/android/support/v7/internal/widget/TintContextWrapper.java
rename to v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
index 3fdd971..ef12e06 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintContextWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.ContextWrapper;
@@ -24,10 +24,8 @@
/**
* A {@link android.content.ContextWrapper} which returns a tint-aware
* {@link android.content.res.Resources} instance from {@link #getResources()}.
- *
- * @hide
*/
-public class TintContextWrapper extends ContextWrapper {
+class TintContextWrapper extends ContextWrapper {
public static Context wrap(Context context) {
if (!(context instanceof TintContextWrapper)) {
@@ -45,7 +43,7 @@
@Override
public Resources getResources() {
if (mResources == null) {
- mResources = new TintResources(super.getResources(), TintManager.get(this));
+ mResources = new TintResources(super.getResources());
}
return mResources;
}
@@ -53,13 +51,9 @@
/**
* This class allows us to intercept calls so that we can tint resources (if applicable).
*/
- static class TintResources extends ResourcesWrapper {
-
- private final TintManager mTintManager;
-
- public TintResources(Resources resources, TintManager tintManager) {
+ class TintResources extends ResourcesWrapper {
+ public TintResources(Resources resources) {
super(resources);
- mTintManager = tintManager;
}
/**
@@ -71,7 +65,8 @@
public Drawable getDrawable(int id) throws NotFoundException {
Drawable d = super.getDrawable(id);
if (d != null) {
- mTintManager.tintDrawableUsingColorFilter(id, d);
+ AppCompatDrawableManager.get().tintDrawableUsingColorFilter(
+ TintContextWrapper.this, id, d);
}
return d;
}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java b/v7/appcompat/src/android/support/v7/widget/TintInfo.java
similarity index 90%
rename from v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
rename to v7/appcompat/src/android/support/v7/widget/TintInfo.java
index 8eea38d..547220c 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
+++ b/v7/appcompat/src/android/support/v7/widget/TintInfo.java
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
-/**
- * @hide
- */
-public class TintInfo {
+class TintInfo {
public ColorStateList mTintList;
public PorterDuff.Mode mTintMode;
public boolean mHasTintMode;
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintTypedArray.java b/v7/appcompat/src/android/support/v7/widget/TintTypedArray.java
similarity index 92%
rename from v7/appcompat/src/android/support/v7/internal/widget/TintTypedArray.java
rename to v7/appcompat/src/android/support/v7/widget/TintTypedArray.java
index 09e2b56..50e1046 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintTypedArray.java
+++ b/v7/appcompat/src/android/support/v7/widget/TintTypedArray.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -36,8 +36,6 @@
private final Context mContext;
private final TypedArray mWrapped;
- private TintManager mTintManager;
-
public static TintTypedArray obtainStyledAttributes(Context context, AttributeSet set,
int[] attrs) {
TypedArray array = context.obtainStyledAttributes(set, attrs);
@@ -59,7 +57,7 @@
if (mWrapped.hasValue(index)) {
final int resourceId = mWrapped.getResourceId(index, 0);
if (resourceId != 0) {
- return getTintManager().getDrawable(resourceId);
+ return AppCompatDrawableManager.get().getDrawable(mContext, resourceId);
}
}
return mWrapped.getDrawable(index);
@@ -69,7 +67,7 @@
if (mWrapped.hasValue(index)) {
final int resourceId = mWrapped.getResourceId(index, 0);
if (resourceId != 0) {
- return getTintManager().getDrawable(resourceId, true);
+ return AppCompatDrawableManager.get().getDrawable(mContext, resourceId, true);
}
}
return null;
@@ -187,11 +185,4 @@
return mWrapped.getChangingConfigurations();
}
- public TintManager getTintManager() {
- if (mTintManager == null) {
- mTintManager = TintManager.get(mContext);
- }
- return mTintManager;
- }
-
}
diff --git a/v7/appcompat/src/android/support/v7/widget/Toolbar.java b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
index 0e8e318..ca4d199 100644
--- a/v7/appcompat/src/android/support/v7/widget/Toolbar.java
+++ b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
@@ -17,9 +17,6 @@
package android.support.v7.widget;
import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Parcel;
@@ -38,21 +35,13 @@
import android.support.v4.view.ViewCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.appcompat.R;
-import android.support.v7.graphics.drawable.DrawableUtils;
-import android.support.v7.internal.view.SupportMenuInflater;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuItemImpl;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.internal.view.menu.MenuView;
-import android.support.v7.internal.view.menu.SubMenuBuilder;
-import android.support.v7.internal.widget.DecorToolbar;
-import android.support.v7.internal.widget.RtlSpacingHelper;
-import android.support.v7.internal.widget.TintInfo;
-import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
-import android.support.v7.internal.widget.ToolbarWidgetWrapper;
-import android.support.v7.internal.widget.ViewUtils;
import android.support.v7.view.CollapsibleActionView;
+import android.support.v7.view.SupportMenuInflater;
+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.text.Layout;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -197,7 +186,7 @@
}
};
- private final TintManager mTintManager;
+ private final AppCompatDrawableManager mDrawableManager;
public Toolbar(Context context) {
this(context, null);
@@ -306,8 +295,7 @@
}
a.recycle();
- // Keep the TintManager in case we need it later
- mTintManager = a.getTintManager();
+ mDrawableManager = AppCompatDrawableManager.get();
}
/**
@@ -354,7 +342,7 @@
* @param resId ID of a drawable resource
*/
public void setLogo(@DrawableRes int resId) {
- setLogo(mTintManager.getDrawable(resId));
+ setLogo(mDrawableManager.getDrawable(getContext(), resId));
}
/** @hide */
@@ -781,7 +769,7 @@
* @param resId Resource ID of a drawable to set
*/
public void setNavigationIcon(@DrawableRes int resId) {
- setNavigationIcon(mTintManager.getDrawable(resId));
+ setNavigationIcon(mDrawableManager.getDrawable(getContext(), resId));
}
/**
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java b/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
similarity index 90%
rename from v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java
rename to v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
index 50e03c9..0576c153 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
@@ -15,7 +15,7 @@
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.app.ActionBar;
import android.content.Context;
@@ -24,13 +24,11 @@
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
+import android.support.v7.app.WindowDecorActionBar;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.menu.ActionMenuItem;
-import android.support.v7.internal.view.menu.MenuBuilder;
-import android.support.v7.internal.view.menu.MenuPresenter;
-import android.support.v7.widget.ActionMenuPresenter;
-import android.support.v7.widget.AppCompatSpinner;
-import android.support.v7.widget.Toolbar;
+import android.support.v7.view.menu.ActionMenuItem;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPresenter;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -50,7 +48,7 @@
*
* <p>ToolbarWidgetWrapper manages the differences between Toolbar and ActionBarView
* so that either variant acting as a
- * {@link android.support.v7.internal.app.WindowDecorActionBar WindowDecorActionBar} can behave
+ * {@link WindowDecorActionBar WindowDecorActionBar} can behave
* in the same way.</p>
*
* @hide
@@ -85,7 +83,7 @@
private int mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD;
- private final TintManager mTintManager;
+ private final AppCompatDrawableManager mDrawableManager;
private int mDefaultNavigationContentDescription = 0;
private Drawable mDefaultNavigationIcon;
@@ -174,18 +172,16 @@
}
a.recycle();
- // Keep the TintManager in case we need it later
- mTintManager = a.getTintManager();
} else {
mDisplayOpts = detectDisplayOptions();
- // Create a TintManager in case we need it later
- mTintManager = TintManager.get(toolbar.getContext());
}
+ mDrawableManager = AppCompatDrawableManager.get();
+
setDefaultNavigationContentDescription(defaultNavigationContentDescription);
mHomeDescription = mToolbar.getNavigationContentDescription();
- setDefaultNavigationIcon(mTintManager.getDrawable(defaultNavigationIcon));
+ setDefaultNavigationIcon(mDrawableManager.getDrawable(getContext(), defaultNavigationIcon));
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
final ActionMenuItem mNavItem = new ActionMenuItem(mToolbar.getContext(),
@@ -322,7 +318,7 @@
@Override
public void setIcon(int resId) {
- setIcon(resId != 0 ? mTintManager.getDrawable(resId) : null);
+ setIcon(resId != 0 ? mDrawableManager.getDrawable(getContext(), resId) : null);
}
@Override
@@ -333,7 +329,7 @@
@Override
public void setLogo(int resId) {
- setLogo(resId != 0 ? mTintManager.getDrawable(resId) : null);
+ setLogo(resId != 0 ? mDrawableManager.getDrawable(getContext(), resId) : null);
}
@Override
@@ -587,37 +583,31 @@
}
@Override
- public ViewPropertyAnimatorCompat setupAnimatorToVisibility(int visibility, long duration) {
- if (visibility == View.GONE) {
- ViewPropertyAnimatorCompat anim = ViewCompat.animate(mToolbar).alpha(0f);
- anim.setDuration(duration);
- anim.setListener(new ViewPropertyAnimatorListenerAdapter() {
- private boolean mCanceled = false;
- @Override
- public void onAnimationEnd(View view) {
- if (!mCanceled) {
- mToolbar.setVisibility(View.GONE);
- }
- }
+ public ViewPropertyAnimatorCompat setupAnimatorToVisibility(final int visibility,
+ final long duration) {
+ return ViewCompat.animate(mToolbar)
+ .alpha(visibility == View.VISIBLE ? 1f : 0f)
+ .setDuration(duration)
+ .setListener(new ViewPropertyAnimatorListenerAdapter() {
+ private boolean mCanceled = false;
- @Override
- public void onAnimationCancel(View view) {
- mCanceled = true;
- }
- });
- return anim;
- } else if (visibility == View.VISIBLE) {
- ViewPropertyAnimatorCompat anim = ViewCompat.animate(mToolbar).alpha(1f);
- anim.setDuration(duration);
- anim.setListener(new ViewPropertyAnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(View view) {
- mToolbar.setVisibility(View.VISIBLE);
- }
- });
- return anim;
- }
- return null;
+ @Override
+ public void onAnimationStart(View view) {
+ mToolbar.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onAnimationEnd(View view) {
+ if (!mCanceled) {
+ mToolbar.setVisibility(visibility);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(View view) {
+ mCanceled = true;
+ }
+ });
}
@Override
@@ -629,8 +619,7 @@
@Override
public void setNavigationIcon(int resId) {
setNavigationIcon(resId != 0
- ? mTintManager.getDrawable(resId)
- : null);
+ ? AppCompatDrawableManager.get().getDrawable(getContext(), resId) : null);
}
@Override
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ViewStubCompat.java b/v7/appcompat/src/android/support/v7/widget/ViewStubCompat.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/internal/widget/ViewStubCompat.java
rename to v7/appcompat/src/android/support/v7/widget/ViewStubCompat.java
index 10873a7..11cd213 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ViewStubCompat.java
+++ b/v7/appcompat/src/android/support/v7/widget/ViewStubCompat.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.content.Context;
import android.content.res.TypedArray;
@@ -26,7 +26,6 @@
import android.view.ViewGroup;
import android.view.ViewParent;
-
import java.lang.ref.WeakReference;
/**
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ViewUtils.java b/v7/appcompat/src/android/support/v7/widget/ViewUtils.java
similarity index 98%
rename from v7/appcompat/src/android/support/v7/internal/widget/ViewUtils.java
rename to v7/appcompat/src/android/support/v7/widget/ViewUtils.java
index a56cf3f..0ae4951 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ViewUtils.java
+++ b/v7/appcompat/src/android/support/v7/widget/ViewUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.support.v7.internal.widget;
+package android.support.v7.widget;
import android.graphics.Rect;
import android.os.Build;
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
index 8adc940..44f9207 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
@@ -106,10 +106,30 @@
getInstrumentation().waitForIdleSync();
assertTrue("onMenuOpened called", getActivity().wasOnMenuOpenedCalled());
- // TODO Re-enable this in v23
- //getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
- //getInstrumentation().waitForIdleSync();
- //assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled());
+ getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+ getInstrumentation().waitForIdleSync();
+ assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled());
+ }
+
+ @Test
+ public void testBackPressWithMenuInvokesOnPanelClosed() throws InterruptedException {
+ getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+ getInstrumentation().waitForIdleSync();
+
+ getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ getInstrumentation().waitForIdleSync();
+ assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled());
+ }
+
+ @Test
+ public void testBackPressWithEmptyMenuDestroysActivity() throws InterruptedException {
+ repopulateWithEmptyMenu();
+
+ getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+ getInstrumentation().waitForIdleSync();
+
+ getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ waitAssertDestroyed();
}
@Test
@@ -141,4 +161,28 @@
assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_MENU, upEvent.getKeyCode());
}
+ private void waitAssertDestroyed() throws InterruptedException {
+ int count = 0;
+ while (count++ < 10) {
+ if (!getActivity().isDestroyed()) {
+ Thread.sleep(50);
+ } else {
+ break;
+ }
+ }
+ assertTrue("Activity destroyed", getActivity().isDestroyed());
+ }
+
+ private void repopulateWithEmptyMenu() throws InterruptedException {
+ int count = 0;
+ getActivity().setShouldPopulateOptionsMenu(false);
+ while (count++ < 10) {
+ Menu menu = getActivity().getMenu();
+ if (menu == null || menu.size() != 0) {
+ Thread.sleep(50);
+ } else {
+ return;
+ }
+ }
+ }
}
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseTestActivity.java b/v7/appcompat/tests/src/android/support/v7/app/BaseTestActivity.java
index f336e91..ebbd0d5 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BaseTestActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BaseTestActivity.java
@@ -37,6 +37,11 @@
private boolean mOnMenuOpenedCalled;
private boolean mOnPanelClosedCalled;
+ private boolean mShouldPopulateOptionsMenu = true;
+
+ private boolean mOnBackPressedCalled;
+ private boolean mDestroyed;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -113,8 +118,13 @@
@Override
public boolean onCreateOptionsMenu(Menu menu) {
mMenu = menu;
- getMenuInflater().inflate(R.menu.sample_actions, menu);
- return true;
+ if (mShouldPopulateOptionsMenu) {
+ getMenuInflater().inflate(R.menu.sample_actions, menu);
+ return true;
+ } else {
+ menu.clear();
+ return super.onCreateOptionsMenu(menu);
+ }
}
public boolean expandSearchView() {
@@ -140,4 +150,36 @@
mOnMenuOpenedCalled = false;
mOnPanelClosedCalled = false;
}
+
+ public void setShouldPopulateOptionsMenu(boolean populate) {
+ mShouldPopulateOptionsMenu = populate;
+ if (mMenu != null) {
+ supportInvalidateOptionsMenu();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mDestroyed = true;
+ }
+
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ mOnBackPressedCalled = true;
+ }
+
+ public boolean wasOnBackPressedCalled() {
+ return mOnBackPressedCalled;
+ }
+
+ public Menu getMenu() {
+ return mMenu;
+ }
+
+ @Override
+ public boolean isDestroyed() {
+ return mDestroyed;
+ }
}
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 e9ede89..053e971 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
@@ -20,7 +20,6 @@
import android.app.Dialog;
import android.os.Bundle;
-import android.support.v7.internal.app.WindowDecorActionBar;
public class DialogTestCase extends BaseInstrumentationTestCase<WindowDecorActionBarActivity> {
diff --git a/v7/cardview/Android.mk b/v7/cardview/Android.mk
index 91d82b4..dcbc4c6 100644
--- a/v7/cardview/Android.mk
+++ b/v7/cardview/Android.mk
@@ -26,6 +26,8 @@
LOCAL_JAR_EXCLUDE_FILES := none
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files := $(LOCAL_SRC_FILES)
+
# A helper sub-library to resolve cyclic dependencies between CardView and platform dependent
# implementations
include $(CLEAR_VARS)
@@ -34,6 +36,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, base)
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of Eclair MR1 APIs
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-cardview-eclair-mr1
@@ -43,6 +47,8 @@
LOCAL_JAVA_LIBRARIES := android-support-v7-cardview-res
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of JB MR1 APIs
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-cardview-jellybean-mr1
@@ -52,6 +58,8 @@
LOCAL_JAVA_LIBRARIES := android-support-v7-cardview-res
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of L APIs
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-cardview-api21
@@ -62,6 +70,8 @@
LOCAL_JAVA_LIBRARIES := android-support-v7-cardview-res
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# Here is the final static library that apps can link against.
# The R class is automatically excluded from the generated library.
# Applications that use this library must specify LOCAL_RESOURCE_DIR
@@ -74,11 +84,12 @@
LOCAL_JAVA_LIBRARIES := android-support-v7-cardview-res
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# API Check
# ---------------------------------------------
support_module := $(LOCAL_MODULE)
support_module_api_dir := $(LOCAL_PATH)/api
-support_module_src_files := $(LOCAL_SRC_FILES)
-support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES) android-support-v7-cardview
+support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
support_module_java_packages := android.support.v7.widget
include $(SUPPORT_API_CHECK)
diff --git a/v7/cardview/api/23.txt b/v7/cardview/api/23.0.0.txt
similarity index 100%
rename from v7/cardview/api/23.txt
rename to v7/cardview/api/23.0.0.txt
diff --git a/v7/cardview/api/23.txt b/v7/cardview/api/23.1.0.txt
similarity index 100%
copy from v7/cardview/api/23.txt
copy to v7/cardview/api/23.1.0.txt
diff --git a/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java b/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
index 3477761..5dba5d6 100644
--- a/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
+++ b/v7/cardview/api21/android/support/v7/widget/RoundRectDrawable.java
@@ -15,11 +15,15 @@
*/
package android.support.v7.widget;
+import android.content.res.ColorStateList;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -29,7 +33,7 @@
/**
* Very simple drawable that draws a rounded rectangle background with arbitrary corners and also
- * reports proper outline for L.
+ * reports proper outline for Lollipop.
* <p>
* Simpler and uses less resources compared to GradientDrawable or ShapeDrawable.
*/
@@ -42,6 +46,10 @@
private boolean mInsetForPadding = false;
private boolean mInsetForRadius = true;
+ private PorterDuffColorFilter mTintFilter;
+ private ColorStateList mTint;
+ private PorterDuff.Mode mTintMode;
+
public RoundRectDrawable(int backgroundColor, float radius) {
mRadius = radius;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
@@ -68,7 +76,21 @@
@Override
public void draw(Canvas canvas) {
- canvas.drawRoundRect(mBoundsF, mRadius, mRadius, mPaint);
+ final Paint paint = mPaint;
+
+ final boolean clearColorFilter;
+ if (mTintFilter != null && paint.getColorFilter() == null) {
+ paint.setColorFilter(mTintFilter);
+ clearColorFilter = true;
+ } else {
+ clearColorFilter = false;
+ }
+
+ canvas.drawRoundRect(mBoundsF, mRadius, mRadius, paint);
+
+ if (clearColorFilter) {
+ paint.setColorFilter(null);
+ }
}
private void updateBounds(Rect bounds) {
@@ -108,12 +130,12 @@
@Override
public void setAlpha(int alpha) {
- // not supported because older versions do not support
+ mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
- // not supported because older versions do not support
+ mPaint.setColorFilter(cf);
}
@Override
@@ -129,4 +151,44 @@
mPaint.setColor(color);
invalidateSelf();
}
+
+ @Override
+ public void setTintList(ColorStateList tint) {
+ mTint = tint;
+ mTintFilter = createTintFilter(mTint, mTintMode);
+ invalidateSelf();
+ }
+
+ @Override
+ public void setTintMode(PorterDuff.Mode tintMode) {
+ mTintMode = tintMode;
+ mTintFilter = createTintFilter(mTint, mTintMode);
+ invalidateSelf();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ if (mTint != null && mTintMode != null) {
+ mTintFilter = createTintFilter(mTint, mTintMode);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isStateful() {
+ return (mTint != null && mTint.isStateful()) || super.isStateful();
+ }
+
+ /**
+ * Ensures the tint filter is consistent with the current tint color and
+ * mode.
+ */
+ private PorterDuffColorFilter createTintFilter(ColorStateList tint, PorterDuff.Mode tintMode) {
+ if (tint == null || tintMode == null) {
+ return null;
+ }
+ final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
+ return new PorterDuffColorFilter(color, tintMode);
+ }
}
diff --git a/v7/cardview/eclair-mr1/android/support/v7/widget/RoundRectDrawableWithShadow.java b/v7/cardview/eclair-mr1/android/support/v7/widget/RoundRectDrawableWithShadow.java
index 054ada8..505edcc 100644
--- a/v7/cardview/eclair-mr1/android/support/v7/widget/RoundRectDrawableWithShadow.java
+++ b/v7/cardview/eclair-mr1/android/support/v7/widget/RoundRectDrawableWithShadow.java
@@ -131,8 +131,13 @@
}
void setShadowSize(float shadowSize, float maxShadowSize) {
- if (shadowSize < 0 || maxShadowSize < 0) {
- throw new IllegalArgumentException("invalid shadow size");
+ if (shadowSize < 0f) {
+ throw new IllegalArgumentException("Invalid shadow size " + shadowSize +
+ ". Must be >= 0");
+ }
+ if (maxShadowSize < 0f) {
+ throw new IllegalArgumentException("Invalid max shadow size " + maxShadowSize +
+ ". Must be >= 0");
}
shadowSize = toEven(shadowSize);
maxShadowSize = toEven(maxShadowSize);
@@ -184,8 +189,6 @@
@Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
- mCornerShadowPaint.setColorFilter(cf);
- mEdgeShadowPaint.setColorFilter(cf);
}
@Override
@@ -194,6 +197,10 @@
}
void setCornerRadius(float radius) {
+ if (radius < 0f) {
+ throw new IllegalArgumentException("Invalid radius " + radius +
+ ". Must be >= 0");
+ }
radius = (int) (radius + .5f);
if (mCornerRadius == radius) {
return;
diff --git a/v7/cardview/src/android/support/v7/widget/CardView.java b/v7/cardview/src/android/support/v7/widget/CardView.java
index bc992b8..eb181bc 100644
--- a/v7/cardview/src/android/support/v7/widget/CardView.java
+++ b/v7/cardview/src/android/support/v7/widget/CardView.java
@@ -27,33 +27,33 @@
/**
* A FrameLayout with a rounded corner background and shadow.
* <p>
- * CardView uses <code>elevation</code> property on L for shadows and falls back to a custom shadow
- * implementation on older platforms.
+ * CardView uses <code>elevation</code> property on Lollipop for shadows and falls back to a
+ * custom emulated shadow implementation on older platforms.
* <p>
- * Due to expensive nature of rounded corner clipping, on platforms before L, CardView does not
- * clip its children that intersect with rounded corners. Instead, it adds padding to avoid such
+ * Due to expensive nature of rounded corner clipping, on platforms before Lollipop, CardView does
+ * not clip its children that intersect with rounded corners. Instead, it adds padding to avoid such
* intersection (See {@link #setPreventCornerOverlap(boolean)} to change this behavior).
* <p>
- * Before L, CardView adds padding to its content and draws shadows to that area. This padding
- * amount is equal to <code>maxCardElevation + (1 - cos45) * cornerRadius</code> on the sides and
- * <code>maxCardElevation * 1.5 + (1 - cos45) * cornerRadius</code> on top and bottom.
+ * Before Lollipop, CardView adds padding to its content and draws shadows to that area. This
+ * padding amount is equal to <code>maxCardElevation + (1 - cos45) * cornerRadius</code> on the
+ * sides and <code>maxCardElevation * 1.5 + (1 - cos45) * cornerRadius</code> on top and bottom.
* <p>
* Since padding is used to offset content for shadows, you cannot set padding on CardView.
- * Instead,
- * you can use content padding attributes in XML or {@link #setContentPadding(int, int, int, int)}
- * in code to set the padding between the edges of the Card and children of CardView.
+ * Instead, you can use content padding attributes in XML or
+ * {@link #setContentPadding(int, int, int, int)} in code to set the padding between the edges of
+ * the CardView and children of CardView.
* <p>
* Note that, if you specify exact dimensions for the CardView, because of the shadows, its content
- * area will be different between platforms before L and after L. By using api version specific
- * resource values, you can avoid these changes. Alternatively, If you want CardView to add inner
- * padding on platforms L and after as well, you can set {@link #setUseCompatPadding(boolean)} to
- * <code>true</code>.
+ * area will be different between platforms before Lollipop and after Lollipop. By using api version
+ * specific resource values, you can avoid these changes. Alternatively, If you want CardView to add
+ * inner padding on platforms Lollipop and after as well, you can call
+ * {@link #setUseCompatPadding(boolean)} and pass <code>true</code>.
* <p>
* To change CardView's elevation in a backward compatible way, use
- * {@link #setCardElevation(float)}. CardView will use elevation API on L and before L, it will
- * change the shadow size. To avoid moving the View while shadow size is changing, shadow size is
- * clamped by {@link #getMaxCardElevation()}. If you want to change elevation dynamically, you
- * should call {@link #setMaxCardElevation(float)} when CardView is initialized.
+ * {@link #setCardElevation(float)}. CardView will use elevation API on Lollipop and before
+ * Lollipop, it will change the shadow size. To avoid moving the View while shadow size is changing,
+ * shadow size is clamped by {@link #getMaxCardElevation()}. If you want to change elevation
+ * dynamically, you should call {@link #setMaxCardElevation(float)} when CardView is initialized.
*
* @attr ref android.support.v7.cardview.R.styleable#CardView_cardBackgroundColor
* @attr ref android.support.v7.cardview.R.styleable#CardView_cardCornerRadius
@@ -116,10 +116,10 @@
}
/**
- * Returns whether CardView will add inner padding on platforms L and after.
+ * Returns whether CardView will add inner padding on platforms Lollipop and after.
*
- * @return True CardView adds inner padding on platforms L and after to have same dimensions
- * with platforms before L.
+ * @return <code>true</code> if CardView adds inner padding on platforms Lollipop and after to
+ * have same dimensions with platforms before Lollipop.
*/
@Override
public boolean getUseCompatPadding() {
@@ -127,19 +127,19 @@
}
/**
- * CardView adds additional padding to draw shadows on platforms before L.
+ * CardView adds additional padding to draw shadows on platforms before Lollipop.
* <p>
- * This may cause Cards to have different sizes between L and before L. If you need to align
- * CardView with other Views, you may need api version specific dimension resources to account
- * for the changes.
+ * This may cause Cards to have different sizes between Lollipop and before Lollipop. If you
+ * need to align CardView with other Views, you may need api version specific dimension
+ * resources to account for the changes.
* As an alternative, you can set this flag to <code>true</code> and CardView will add the same
- * padding values on platforms L and after.
+ * padding values on platforms Lollipop and after.
* <p>
* Since setting this flag to true adds unnecessary gaps in the UI, default value is
* <code>false</code>.
*
- * @param useCompatPadding True if CardView should add padding for the shadows on platforms L
- * and above.
+ * @param useCompatPadding <code>true></code> if CardView should add padding for the shadows on
+ * platforms Lollipop and above.
* @attr ref android.support.v7.cardview.R.styleable#CardView_cardUseCompatPadding
*/
public void setUseCompatPadding(boolean useCompatPadding) {
@@ -306,13 +306,13 @@
/**
* Updates the backward compatible elevation of the CardView.
*
- * @param radius The backward compatible elevation in pixels.
+ * @param elevation The backward compatible elevation in pixels.
* @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation
* @see #getCardElevation()
* @see #setMaxCardElevation(float)
*/
- public void setCardElevation(float radius) {
- IMPL.setElevation(this, radius);
+ public void setCardElevation(float elevation) {
+ IMPL.setElevation(this, elevation);
}
/**
@@ -327,24 +327,24 @@
}
/**
- * Updates the backward compatible elevation of the CardView.
+ * Updates the backward compatible maximum elevation of the CardView.
* <p>
- * Calling this method has no effect if device OS version is L or newer and
+ * Calling this method has no effect if device OS version is Lollipop or newer and
* {@link #getUseCompatPadding()} is <code>false</code>.
*
- * @param radius The backward compatible elevation in pixels.
- * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation
+ * @param maxElevation The backward compatible maximum elevation in pixels.
+ * @attr ref android.support.v7.cardview.R.styleable#CardView_cardMaxElevation
* @see #setCardElevation(float)
* @see #getMaxCardElevation()
*/
- public void setMaxCardElevation(float radius) {
- IMPL.setMaxElevation(this, radius);
+ public void setMaxCardElevation(float maxElevation) {
+ IMPL.setMaxElevation(this, maxElevation);
}
/**
- * Returns the backward compatible elevation of the CardView.
+ * Returns the backward compatible maximum elevation of the CardView.
*
- * @return Elevation of the CardView
+ * @return Maximum elevation of the CardView
* @see #setMaxCardElevation(float)
* @see #getCardElevation()
*/
@@ -354,9 +354,9 @@
/**
* Returns whether CardView should add extra padding to content to avoid overlaps with rounded
- * corners on API versions 20 and below.
+ * corners on pre-Lollipop platforms.
*
- * @return True if CardView prevents overlaps with rounded corners on platforms before L.
+ * @return True if CardView prevents overlaps with rounded corners on platforms before Lollipop.
* Default value is <code>true</code>.
*/
@Override
@@ -365,11 +365,11 @@
}
/**
- * On API 20 and before, CardView does not clip the bounds of the Card for the rounded corners.
- * Instead, it adds padding to content so that it won't overlap with the rounded corners.
- * You can disable this behavior by setting this field to <code>false</code>.
+ * On pre-Lollipop platforms, CardView does not clip the bounds of the Card for the rounded
+ * corners. Instead, it adds padding to content so that it won't overlap with the rounded
+ * corners. You can disable this behavior by setting this field to <code>false</code>.
* <p>
- * Setting this value on API 21 and above does not have any effect unless you have enabled
+ * Setting this value on Lollipop and above does not have any effect unless you have enabled
* compatibility padding.
*
* @param preventCornerOverlap Whether CardView should add extra padding to content to avoid
diff --git a/v7/gridlayout/api/23.txt b/v7/gridlayout/api/23.0.0.txt
similarity index 100%
rename from v7/gridlayout/api/23.txt
rename to v7/gridlayout/api/23.0.0.txt
diff --git a/v7/gridlayout/api/23.txt b/v7/gridlayout/api/23.1.0.txt
similarity index 100%
copy from v7/gridlayout/api/23.txt
copy to v7/gridlayout/api/23.1.0.txt
diff --git a/v7/gridlayout/src/android/support/v7/widget/GridLayout.java b/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
index cee59eb..a493911 100644
--- a/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
+++ b/v7/gridlayout/src/android/support/v7/widget/GridLayout.java
@@ -1647,7 +1647,8 @@
boolean validSolution = true;
// do a binary search to find the max delta that won't conflict with constraints
while(deltaMin < deltaMax) {
- final int delta = (deltaMin + deltaMax) / 2;
+ // cast to long to prevent overflow.
+ final int delta = (int)(((long)deltaMin + deltaMax) / 2);
invalidateValues();
shareOutDelta(delta, totalWeight);
validSolution = solve(getArcs(), a, false);
diff --git a/v7/mediarouter/Android.mk b/v7/mediarouter/Android.mk
index 03f9f99..9bd9960 100644
--- a/v7/mediarouter/Android.mk
+++ b/v7/mediarouter/Android.mk
@@ -30,6 +30,8 @@
LOCAL_JAR_EXCLUDE_FILES := none
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files := $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of JellyBean APIs.
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-mediarouter-jellybean
@@ -37,6 +39,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, jellybean)
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of JellyBean MR1 APIs.
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-mediarouter-jellybean-mr1
@@ -45,6 +49,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-mediarouter-jellybean
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# A helper sub-library that makes direct use of JellyBean MR2 APIs.
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-mediarouter-jellybean-mr2
@@ -53,6 +59,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-mediarouter-jellybean-mr1
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# Here is the final static library that apps can link against.
# The R class is automatically excluded from the generated library.
# Applications that use this library must specify LOCAL_RESOURCE_DIR
@@ -63,14 +71,17 @@
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-mediarouter-jellybean-mr2
LOCAL_JAVA_LIBRARIES := android-support-v4 android-support-v7-mediarouter-res \
- android-support-v7-appcompat
+ android-support-v7-appcompat \
+ android-support-v7-palette
include $(BUILD_STATIC_JAVA_LIBRARY)
+support_module_src_files += $(LOCAL_SRC_FILES)
+
# API Check
# ---------------------------------------------
support_module := $(LOCAL_MODULE)
support_module_api_dir := $(LOCAL_PATH)/api
support_module_src_files := $(LOCAL_SRC_FILES)
-support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES) android-support-v7-mediarouter
+support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
support_module_java_packages := android.support.v7.app android.support.v7.media
include $(SUPPORT_API_CHECK)
diff --git a/v7/mediarouter/api/23.txt b/v7/mediarouter/api/23.0.0.txt
similarity index 100%
rename from v7/mediarouter/api/23.txt
rename to v7/mediarouter/api/23.0.0.txt
diff --git a/v7/mediarouter/api/23.1.0.txt b/v7/mediarouter/api/23.1.0.txt
new file mode 100644
index 0000000..69fc20e
--- /dev/null
+++ b/v7/mediarouter/api/23.1.0.txt
@@ -0,0 +1,694 @@
+package android.support.v7.app {
+
+ public abstract class ActionBar {
+ ctor public ActionBar();
+ method public abstract void addOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+ method public abstract void addTab(android.support.v7.app.ActionBar.Tab);
+ method public abstract void addTab(android.support.v7.app.ActionBar.Tab, boolean);
+ method public abstract void addTab(android.support.v7.app.ActionBar.Tab, int);
+ method public abstract void addTab(android.support.v7.app.ActionBar.Tab, int, boolean);
+ method public boolean collapseActionView();
+ method public void dispatchMenuVisibilityChanged(boolean);
+ method public abstract android.view.View getCustomView();
+ method public abstract int getDisplayOptions();
+ method public float getElevation();
+ method public abstract int getHeight();
+ method public int getHideOffset();
+ method public abstract int getNavigationItemCount();
+ method public abstract int getNavigationMode();
+ method public abstract int getSelectedNavigationIndex();
+ method public abstract android.support.v7.app.ActionBar.Tab getSelectedTab();
+ method public abstract java.lang.CharSequence getSubtitle();
+ method public abstract android.support.v7.app.ActionBar.Tab getTabAt(int);
+ method public abstract int getTabCount();
+ method public android.content.Context getThemedContext();
+ method public abstract java.lang.CharSequence getTitle();
+ method public abstract void hide();
+ method public boolean invalidateOptionsMenu();
+ method public boolean isHideOnContentScrollEnabled();
+ method public abstract boolean isShowing();
+ method public boolean isTitleTruncated();
+ method public abstract android.support.v7.app.ActionBar.Tab newTab();
+ method public void onConfigurationChanged(android.content.res.Configuration);
+ method public boolean onKeyShortcut(int, android.view.KeyEvent);
+ method public boolean onMenuKeyEvent(android.view.KeyEvent);
+ method public boolean openOptionsMenu();
+ method public abstract void removeAllTabs();
+ method public abstract void removeOnMenuVisibilityListener(android.support.v7.app.ActionBar.OnMenuVisibilityListener);
+ method public abstract void removeTab(android.support.v7.app.ActionBar.Tab);
+ method public abstract void removeTabAt(int);
+ method public abstract void selectTab(android.support.v7.app.ActionBar.Tab);
+ method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public abstract void setCustomView(android.view.View);
+ method public abstract void setCustomView(android.view.View, android.support.v7.app.ActionBar.LayoutParams);
+ method public abstract void setCustomView(int);
+ method public void setDefaultDisplayHomeAsUpEnabled(boolean);
+ method public abstract void setDisplayHomeAsUpEnabled(boolean);
+ method public abstract void setDisplayOptions(int);
+ method public abstract void setDisplayOptions(int, int);
+ method public abstract void setDisplayShowCustomEnabled(boolean);
+ method public abstract void setDisplayShowHomeEnabled(boolean);
+ method public abstract void setDisplayShowTitleEnabled(boolean);
+ method public abstract void setDisplayUseLogoEnabled(boolean);
+ method public void setElevation(float);
+ method public void setHideOffset(int);
+ method public void setHideOnContentScrollEnabled(boolean);
+ method public void setHomeActionContentDescription(java.lang.CharSequence);
+ method public void setHomeActionContentDescription(int);
+ method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+ method public void setHomeAsUpIndicator(int);
+ method public void setHomeButtonEnabled(boolean);
+ method public abstract void setIcon(int);
+ method public abstract void setIcon(android.graphics.drawable.Drawable);
+ method public abstract void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.support.v7.app.ActionBar.OnNavigationListener);
+ method public abstract void setLogo(int);
+ method public abstract void setLogo(android.graphics.drawable.Drawable);
+ method public abstract void setNavigationMode(int);
+ method public abstract void setSelectedNavigationItem(int);
+ method public void setShowHideAnimationEnabled(boolean);
+ method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
+ method public abstract void setSubtitle(java.lang.CharSequence);
+ method public abstract void setSubtitle(int);
+ method public abstract void setTitle(java.lang.CharSequence);
+ method public abstract void setTitle(int);
+ method public void setWindowTitle(java.lang.CharSequence);
+ method public abstract void show();
+ method public android.support.v7.view.ActionMode startActionMode(android.support.v7.view.ActionMode.Callback);
+ field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
+ field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
+ field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
+ field public static final int DISPLAY_SHOW_TITLE = 8; // 0x8
+ field public static final int DISPLAY_USE_LOGO = 1; // 0x1
+ field public static final int NAVIGATION_MODE_LIST = 1; // 0x1
+ field public static final int NAVIGATION_MODE_STANDARD = 0; // 0x0
+ field public static final int NAVIGATION_MODE_TABS = 2; // 0x2
+ }
+
+ public static class ActionBar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public ActionBar.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public ActionBar.LayoutParams(int, int);
+ ctor public ActionBar.LayoutParams(int, int, int);
+ ctor public ActionBar.LayoutParams(int);
+ ctor public ActionBar.LayoutParams(android.support.v7.app.ActionBar.LayoutParams);
+ ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
+ field public int gravity;
+ }
+
+ public static abstract interface ActionBar.OnMenuVisibilityListener {
+ method public abstract void onMenuVisibilityChanged(boolean);
+ }
+
+ public static abstract interface ActionBar.OnNavigationListener {
+ method public abstract boolean onNavigationItemSelected(int, long);
+ }
+
+ public static abstract class ActionBar.Tab {
+ ctor public ActionBar.Tab();
+ method public abstract java.lang.CharSequence getContentDescription();
+ method public abstract android.view.View getCustomView();
+ method public abstract android.graphics.drawable.Drawable getIcon();
+ method public abstract int getPosition();
+ method public abstract java.lang.Object getTag();
+ method public abstract java.lang.CharSequence getText();
+ method public abstract void select();
+ method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(int);
+ method public abstract android.support.v7.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
+ method public abstract android.support.v7.app.ActionBar.Tab setCustomView(android.view.View);
+ method public abstract android.support.v7.app.ActionBar.Tab setCustomView(int);
+ method public abstract android.support.v7.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
+ method public abstract android.support.v7.app.ActionBar.Tab setIcon(int);
+ method public abstract android.support.v7.app.ActionBar.Tab setTabListener(android.support.v7.app.ActionBar.TabListener);
+ method public abstract android.support.v7.app.ActionBar.Tab setTag(java.lang.Object);
+ method public abstract android.support.v7.app.ActionBar.Tab setText(java.lang.CharSequence);
+ method public abstract android.support.v7.app.ActionBar.Tab setText(int);
+ field public static final int INVALID_POSITION = -1; // 0xffffffff
+ }
+
+ public static abstract interface ActionBar.TabListener {
+ method public abstract void onTabReselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+ method public abstract void onTabSelected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+ method public abstract void onTabUnselected(android.support.v7.app.ActionBar.Tab, android.support.v4.app.FragmentTransaction);
+ }
+
+ public class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
+ ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, int, int);
+ ctor public ActionBarDrawerToggle(android.app.Activity, android.support.v4.widget.DrawerLayout, android.support.v7.widget.Toolbar, int, int);
+ method public android.view.View.OnClickListener getToolbarNavigationClickListener();
+ method public boolean isDrawerIndicatorEnabled();
+ method public void onConfigurationChanged(android.content.res.Configuration);
+ method public void onDrawerClosed(android.view.View);
+ method public void onDrawerOpened(android.view.View);
+ method public void onDrawerSlide(android.view.View, float);
+ method public void onDrawerStateChanged(int);
+ method public boolean onOptionsItemSelected(android.view.MenuItem);
+ method public void setDrawerIndicatorEnabled(boolean);
+ method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+ method public void setHomeAsUpIndicator(int);
+ method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
+ method public void syncState();
+ }
+
+ public static abstract interface ActionBarDrawerToggle.Delegate {
+ method public abstract android.content.Context getActionBarThemedContext();
+ method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
+ method public abstract boolean isNavigationVisible();
+ method public abstract void setActionBarDescription(int);
+ method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
+ }
+
+ public class AlertDialog extends android.support.v7.app.AppCompatDialog implements android.content.DialogInterface {
+ ctor protected AlertDialog(android.content.Context);
+ ctor protected AlertDialog(android.content.Context, int);
+ ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+ method public android.widget.Button getButton(int);
+ method public android.widget.ListView getListView();
+ method public void setButton(int, java.lang.CharSequence, android.os.Message);
+ method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+ method public void setCustomTitle(android.view.View);
+ method public void setIcon(int);
+ method public void setIcon(android.graphics.drawable.Drawable);
+ method public void setIconAttribute(int);
+ method public void setMessage(java.lang.CharSequence);
+ method public void setView(android.view.View);
+ method public void setView(android.view.View, int, int, int, int);
+ }
+
+ public abstract interface AppCompatCallback {
+ method public abstract void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+ method public abstract void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+ method public abstract android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ }
+
+ public abstract class AppCompatDelegate {
+ method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public static android.support.v7.app.AppCompatDelegate create(android.app.Activity, android.support.v7.app.AppCompatCallback);
+ method public static android.support.v7.app.AppCompatDelegate create(android.app.Dialog, android.support.v7.app.AppCompatCallback);
+ method public abstract android.view.View createView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+ method public abstract android.support.v7.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
+ method public abstract android.view.MenuInflater getMenuInflater();
+ method public abstract android.support.v7.app.ActionBar getSupportActionBar();
+ method public abstract boolean hasWindowFeature(int);
+ method public abstract void installViewFactory();
+ method public abstract void invalidateOptionsMenu();
+ method public abstract boolean isHandleNativeActionModesEnabled();
+ method public abstract void onConfigurationChanged(android.content.res.Configuration);
+ method public abstract void onCreate(android.os.Bundle);
+ method public abstract void onDestroy();
+ method public abstract void onPostCreate(android.os.Bundle);
+ method public abstract void onPostResume();
+ method public abstract void onStop();
+ method public abstract boolean requestWindowFeature(int);
+ method public abstract void setContentView(android.view.View);
+ method public abstract void setContentView(int);
+ method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public abstract void setHandleNativeActionModesEnabled(boolean);
+ method public abstract void setSupportActionBar(android.support.v7.widget.Toolbar);
+ method public abstract void setTitle(java.lang.CharSequence);
+ method public abstract android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ field public static final int FEATURE_SUPPORT_ACTION_BAR = 108; // 0x6c
+ field public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 109; // 0x6d
+ }
+
+ public class AppCompatDialog extends android.app.Dialog implements android.support.v7.app.AppCompatCallback {
+ ctor public AppCompatDialog(android.content.Context);
+ ctor public AppCompatDialog(android.content.Context, int);
+ ctor protected AppCompatDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+ method public android.support.v7.app.AppCompatDelegate getDelegate();
+ method public android.support.v7.app.ActionBar getSupportActionBar();
+ method public void onSupportActionModeFinished(android.support.v7.view.ActionMode);
+ method public void onSupportActionModeStarted(android.support.v7.view.ActionMode);
+ method public android.support.v7.view.ActionMode onWindowStartingSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ method public boolean supportRequestWindowFeature(int);
+ }
+
+ public class MediaRouteActionProvider extends android.support.v4.view.ActionProvider {
+ ctor public MediaRouteActionProvider(android.content.Context);
+ method public android.support.v7.app.MediaRouteDialogFactory getDialogFactory();
+ method public android.support.v7.app.MediaRouteButton getMediaRouteButton();
+ method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+ method public android.view.View onCreateActionView();
+ method public android.support.v7.app.MediaRouteButton onCreateMediaRouteButton();
+ method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+ method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+ }
+
+ public class MediaRouteButton extends android.view.View {
+ ctor public MediaRouteButton(android.content.Context);
+ ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet);
+ ctor public MediaRouteButton(android.content.Context, android.util.AttributeSet, int);
+ method public android.support.v7.app.MediaRouteDialogFactory getDialogFactory();
+ method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+ method public void setRemoteIndicatorDrawable(android.graphics.drawable.Drawable);
+ method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+ method public boolean showDialog();
+ }
+
+ public class MediaRouteChooserDialog extends android.app.Dialog {
+ ctor public MediaRouteChooserDialog(android.content.Context);
+ ctor public MediaRouteChooserDialog(android.content.Context, int);
+ method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+ method public boolean onFilterRoute(android.support.v7.media.MediaRouter.RouteInfo);
+ method public void onFilterRoutes(java.util.List<android.support.v7.media.MediaRouter.RouteInfo>);
+ method public void refreshRoutes();
+ method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+ }
+
+ public class MediaRouteChooserDialogFragment extends android.support.v4.app.DialogFragment {
+ ctor public MediaRouteChooserDialogFragment();
+ method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+ method public android.support.v7.app.MediaRouteChooserDialog onCreateChooserDialog(android.content.Context, android.os.Bundle);
+ method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+ }
+
+ public class MediaRouteControllerDialog extends android.support.v7.app.AlertDialog {
+ ctor public MediaRouteControllerDialog(android.content.Context);
+ ctor public MediaRouteControllerDialog(android.content.Context, int);
+ method public android.view.View getMediaControlView();
+ method public android.support.v4.media.session.MediaSessionCompat.Token getMediaSession();
+ method public android.support.v7.media.MediaRouter.RouteInfo getRoute();
+ method public boolean isVolumeControlEnabled();
+ method public android.view.View onCreateMediaControlView(android.os.Bundle);
+ method public void setVolumeControlEnabled(boolean);
+ }
+
+ public class MediaRouteControllerDialogFragment extends android.support.v4.app.DialogFragment {
+ ctor public MediaRouteControllerDialogFragment();
+ method public android.support.v7.app.MediaRouteControllerDialog onCreateControllerDialog(android.content.Context, android.os.Bundle);
+ }
+
+ public class MediaRouteDialogFactory {
+ ctor public MediaRouteDialogFactory();
+ method public static android.support.v7.app.MediaRouteDialogFactory getDefault();
+ method public android.support.v7.app.MediaRouteChooserDialogFragment onCreateChooserDialogFragment();
+ method public android.support.v7.app.MediaRouteControllerDialogFragment onCreateControllerDialogFragment();
+ }
+
+ public class MediaRouteDiscoveryFragment extends android.support.v4.app.Fragment {
+ ctor public MediaRouteDiscoveryFragment();
+ method public android.support.v7.media.MediaRouter getMediaRouter();
+ method public android.support.v7.media.MediaRouteSelector getRouteSelector();
+ method public android.support.v7.media.MediaRouter.Callback onCreateCallback();
+ method public int onPrepareCallbackFlags();
+ method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
+ }
+
+}
+
+package android.support.v7.media {
+
+ public final class MediaControlIntent {
+ field public static final java.lang.String ACTION_END_SESSION = "android.media.intent.action.END_SESSION";
+ field public static final java.lang.String ACTION_ENQUEUE = "android.media.intent.action.ENQUEUE";
+ field public static final java.lang.String ACTION_GET_SESSION_STATUS = "android.media.intent.action.GET_SESSION_STATUS";
+ field public static final java.lang.String ACTION_GET_STATUS = "android.media.intent.action.GET_STATUS";
+ field public static final java.lang.String ACTION_PAUSE = "android.media.intent.action.PAUSE";
+ field public static final java.lang.String ACTION_PLAY = "android.media.intent.action.PLAY";
+ field public static final java.lang.String ACTION_REMOVE = "android.media.intent.action.REMOVE";
+ field public static final java.lang.String ACTION_RESUME = "android.media.intent.action.RESUME";
+ field public static final java.lang.String ACTION_SEEK = "android.media.intent.action.SEEK";
+ field public static final java.lang.String ACTION_START_SESSION = "android.media.intent.action.START_SESSION";
+ field public static final java.lang.String ACTION_STOP = "android.media.intent.action.STOP";
+ field public static final java.lang.String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
+ field public static final java.lang.String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
+ field public static final java.lang.String CATEGORY_REMOTE_PLAYBACK = "android.media.intent.category.REMOTE_PLAYBACK";
+ field public static final int ERROR_INVALID_ITEM_ID = 3; // 0x3
+ field public static final int ERROR_INVALID_SESSION_ID = 2; // 0x2
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int ERROR_UNSUPPORTED_OPERATION = 1; // 0x1
+ field public static final java.lang.String EXTRA_ERROR_CODE = "android.media.intent.extra.ERROR_CODE";
+ field public static final java.lang.String EXTRA_ITEM_CONTENT_POSITION = "android.media.intent.extra.ITEM_POSITION";
+ field public static final java.lang.String EXTRA_ITEM_HTTP_HEADERS = "android.media.intent.extra.HTTP_HEADERS";
+ field public static final java.lang.String EXTRA_ITEM_ID = "android.media.intent.extra.ITEM_ID";
+ field public static final java.lang.String EXTRA_ITEM_METADATA = "android.media.intent.extra.ITEM_METADATA";
+ field public static final java.lang.String EXTRA_ITEM_STATUS = "android.media.intent.extra.ITEM_STATUS";
+ field public static final java.lang.String EXTRA_ITEM_STATUS_UPDATE_RECEIVER = "android.media.intent.extra.ITEM_STATUS_UPDATE_RECEIVER";
+ field public static final java.lang.String EXTRA_SESSION_ID = "android.media.intent.extra.SESSION_ID";
+ field public static final java.lang.String EXTRA_SESSION_STATUS = "android.media.intent.extra.SESSION_STATUS";
+ field public static final java.lang.String EXTRA_SESSION_STATUS_UPDATE_RECEIVER = "android.media.intent.extra.SESSION_STATUS_UPDATE_RECEIVER";
+ }
+
+ public final class MediaItemMetadata {
+ field public static final java.lang.String KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+ field public static final java.lang.String KEY_ALBUM_TITLE = "android.media.metadata.ALBUM_TITLE";
+ field public static final java.lang.String KEY_ARTIST = "android.media.metadata.ARTIST";
+ field public static final java.lang.String KEY_ARTWORK_URI = "android.media.metadata.ARTWORK_URI";
+ field public static final java.lang.String KEY_AUTHOR = "android.media.metadata.AUTHOR";
+ field public static final java.lang.String KEY_COMPOSER = "android.media.metadata.COMPOSER";
+ field public static final java.lang.String KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+ field public static final java.lang.String KEY_DURATION = "android.media.metadata.DURATION";
+ field public static final java.lang.String KEY_TITLE = "android.media.metadata.TITLE";
+ field public static final java.lang.String KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+ field public static final java.lang.String KEY_YEAR = "android.media.metadata.YEAR";
+ }
+
+ public final class MediaItemStatus {
+ method public android.os.Bundle asBundle();
+ method public static android.support.v7.media.MediaItemStatus fromBundle(android.os.Bundle);
+ method public long getContentDuration();
+ method public long getContentPosition();
+ method public android.os.Bundle getExtras();
+ method public int getPlaybackState();
+ method public long getTimestamp();
+ field public static final java.lang.String EXTRA_HTTP_RESPONSE_HEADERS = "android.media.status.extra.HTTP_RESPONSE_HEADERS";
+ field public static final java.lang.String EXTRA_HTTP_STATUS_CODE = "android.media.status.extra.HTTP_STATUS_CODE";
+ field public static final int PLAYBACK_STATE_BUFFERING = 3; // 0x3
+ field public static final int PLAYBACK_STATE_CANCELED = 5; // 0x5
+ field public static final int PLAYBACK_STATE_ERROR = 7; // 0x7
+ field public static final int PLAYBACK_STATE_FINISHED = 4; // 0x4
+ field public static final int PLAYBACK_STATE_INVALIDATED = 6; // 0x6
+ field public static final int PLAYBACK_STATE_PAUSED = 2; // 0x2
+ field public static final int PLAYBACK_STATE_PENDING = 0; // 0x0
+ field public static final int PLAYBACK_STATE_PLAYING = 1; // 0x1
+ }
+
+ public static final class MediaItemStatus.Builder {
+ ctor public MediaItemStatus.Builder(int);
+ ctor public MediaItemStatus.Builder(android.support.v7.media.MediaItemStatus);
+ method public android.support.v7.media.MediaItemStatus build();
+ method public android.support.v7.media.MediaItemStatus.Builder setContentDuration(long);
+ method public android.support.v7.media.MediaItemStatus.Builder setContentPosition(long);
+ method public android.support.v7.media.MediaItemStatus.Builder setExtras(android.os.Bundle);
+ method public android.support.v7.media.MediaItemStatus.Builder setPlaybackState(int);
+ method public android.support.v7.media.MediaItemStatus.Builder setTimestamp(long);
+ }
+
+ public final class MediaRouteDescriptor {
+ method public android.os.Bundle asBundle();
+ method public boolean canDisconnectAndKeepPlaying();
+ method public static android.support.v7.media.MediaRouteDescriptor fromBundle(android.os.Bundle);
+ method public int getConnectionState();
+ method public java.util.List<android.content.IntentFilter> getControlFilters();
+ method public java.lang.String getDescription();
+ method public int getDeviceType();
+ method public android.os.Bundle getExtras();
+ method public java.util.List<java.lang.String> getGroupMemberIds();
+ method public android.net.Uri getIconUri();
+ method public java.lang.String getId();
+ method public java.lang.String getName();
+ method public int getPlaybackStream();
+ method public int getPlaybackType();
+ method public int getPresentationDisplayId();
+ method public android.content.IntentSender getSettingsActivity();
+ method public int getVolume();
+ method public int getVolumeHandling();
+ method public int getVolumeMax();
+ method public deprecated boolean isConnecting();
+ method public boolean isEnabled();
+ method public boolean isValid();
+ }
+
+ public static final class MediaRouteDescriptor.Builder {
+ ctor public MediaRouteDescriptor.Builder(java.lang.String, java.lang.String);
+ ctor public MediaRouteDescriptor.Builder(android.support.v7.media.MediaRouteDescriptor);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilter(android.content.IntentFilter);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilters(java.util.Collection<android.content.IntentFilter>);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder addGroupMemberId(java.lang.String);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder addGroupMemberIds(java.util.Collection<java.lang.String>);
+ method public android.support.v7.media.MediaRouteDescriptor build();
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
+ method public deprecated android.support.v7.media.MediaRouteDescriptor.Builder setConnecting(boolean);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setConnectionState(int);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setDescription(java.lang.String);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setDeviceType(int);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setEnabled(boolean);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setExtras(android.os.Bundle);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setIconUri(android.net.Uri);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setId(java.lang.String);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setName(java.lang.String);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackStream(int);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackType(int);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setPresentationDisplayId(int);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setSettingsActivity(android.content.IntentSender);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setVolume(int);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setVolumeHandling(int);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setVolumeMax(int);
+ }
+
+ public final class MediaRouteDiscoveryRequest {
+ ctor public MediaRouteDiscoveryRequest(android.support.v7.media.MediaRouteSelector, boolean);
+ method public android.os.Bundle asBundle();
+ method public static android.support.v7.media.MediaRouteDiscoveryRequest fromBundle(android.os.Bundle);
+ method public android.support.v7.media.MediaRouteSelector getSelector();
+ method public boolean isActiveScan();
+ method public boolean isValid();
+ }
+
+ public abstract class MediaRouteProvider {
+ ctor public MediaRouteProvider(android.content.Context);
+ method public final android.content.Context getContext();
+ method public final android.support.v7.media.MediaRouteProviderDescriptor getDescriptor();
+ method public final android.support.v7.media.MediaRouteDiscoveryRequest getDiscoveryRequest();
+ method public final android.os.Handler getHandler();
+ method public final android.support.v7.media.MediaRouteProvider.ProviderMetadata getMetadata();
+ method public android.support.v7.media.MediaRouteProvider.RouteController onCreateRouteController(java.lang.String);
+ method public void onDiscoveryRequestChanged(android.support.v7.media.MediaRouteDiscoveryRequest);
+ method public final void setCallback(android.support.v7.media.MediaRouteProvider.Callback);
+ method public final void setDescriptor(android.support.v7.media.MediaRouteProviderDescriptor);
+ method public final void setDiscoveryRequest(android.support.v7.media.MediaRouteDiscoveryRequest);
+ }
+
+ public static abstract class MediaRouteProvider.Callback {
+ ctor public MediaRouteProvider.Callback();
+ method public void onDescriptorChanged(android.support.v7.media.MediaRouteProvider, android.support.v7.media.MediaRouteProviderDescriptor);
+ }
+
+ public static final class MediaRouteProvider.ProviderMetadata {
+ method public android.content.ComponentName getComponentName();
+ method public java.lang.String getPackageName();
+ }
+
+ public static abstract class MediaRouteProvider.RouteController {
+ ctor public MediaRouteProvider.RouteController();
+ method public boolean onControlRequest(android.content.Intent, android.support.v7.media.MediaRouter.ControlRequestCallback);
+ method public void onRelease();
+ method public void onSelect();
+ method public void onSetVolume(int);
+ method public void onUnselect();
+ method public void onUnselect(int);
+ method public void onUpdateVolume(int);
+ }
+
+ public final class MediaRouteProviderDescriptor {
+ method public android.os.Bundle asBundle();
+ method public static android.support.v7.media.MediaRouteProviderDescriptor fromBundle(android.os.Bundle);
+ method public java.util.List<android.support.v7.media.MediaRouteDescriptor> getRoutes();
+ method public boolean isValid();
+ }
+
+ public static final class MediaRouteProviderDescriptor.Builder {
+ ctor public MediaRouteProviderDescriptor.Builder();
+ ctor public MediaRouteProviderDescriptor.Builder(android.support.v7.media.MediaRouteProviderDescriptor);
+ method public android.support.v7.media.MediaRouteProviderDescriptor.Builder addRoute(android.support.v7.media.MediaRouteDescriptor);
+ method public android.support.v7.media.MediaRouteProviderDescriptor.Builder addRoutes(java.util.Collection<android.support.v7.media.MediaRouteDescriptor>);
+ method public android.support.v7.media.MediaRouteProviderDescriptor build();
+ }
+
+ public abstract class MediaRouteProviderService extends android.app.Service {
+ ctor public MediaRouteProviderService();
+ method public android.support.v7.media.MediaRouteProvider getMediaRouteProvider();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract android.support.v7.media.MediaRouteProvider onCreateMediaRouteProvider();
+ field public static final java.lang.String SERVICE_INTERFACE = "android.media.MediaRouteProviderService";
+ }
+
+ public final class MediaRouteSelector {
+ method public android.os.Bundle asBundle();
+ method public boolean contains(android.support.v7.media.MediaRouteSelector);
+ method public static android.support.v7.media.MediaRouteSelector fromBundle(android.os.Bundle);
+ method public java.util.List<java.lang.String> getControlCategories();
+ method public boolean hasControlCategory(java.lang.String);
+ method public boolean isEmpty();
+ method public boolean isValid();
+ method public boolean matchesControlFilters(java.util.List<android.content.IntentFilter>);
+ field public static final android.support.v7.media.MediaRouteSelector EMPTY;
+ }
+
+ public static final class MediaRouteSelector.Builder {
+ ctor public MediaRouteSelector.Builder();
+ ctor public MediaRouteSelector.Builder(android.support.v7.media.MediaRouteSelector);
+ method public android.support.v7.media.MediaRouteSelector.Builder addControlCategories(java.util.Collection<java.lang.String>);
+ method public android.support.v7.media.MediaRouteSelector.Builder addControlCategory(java.lang.String);
+ method public android.support.v7.media.MediaRouteSelector.Builder addSelector(android.support.v7.media.MediaRouteSelector);
+ method public android.support.v7.media.MediaRouteSelector build();
+ }
+
+ public final class MediaRouter {
+ method public void addCallback(android.support.v7.media.MediaRouteSelector, android.support.v7.media.MediaRouter.Callback);
+ method public void addCallback(android.support.v7.media.MediaRouteSelector, android.support.v7.media.MediaRouter.Callback, int);
+ method public void addProvider(android.support.v7.media.MediaRouteProvider);
+ method public void addRemoteControlClient(java.lang.Object);
+ method public android.support.v7.media.MediaRouter.RouteInfo getDefaultRoute();
+ method public static android.support.v7.media.MediaRouter getInstance(android.content.Context);
+ method public android.support.v4.media.session.MediaSessionCompat.Token getMediaSessionToken();
+ method public java.util.List<android.support.v7.media.MediaRouter.ProviderInfo> getProviders();
+ method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+ method public android.support.v7.media.MediaRouter.RouteInfo getSelectedRoute();
+ method public boolean isRouteAvailable(android.support.v7.media.MediaRouteSelector, int);
+ method public void removeCallback(android.support.v7.media.MediaRouter.Callback);
+ method public void removeProvider(android.support.v7.media.MediaRouteProvider);
+ method public void removeRemoteControlClient(java.lang.Object);
+ method public void selectRoute(android.support.v7.media.MediaRouter.RouteInfo);
+ method public void setMediaSession(java.lang.Object);
+ method public void setMediaSessionCompat(android.support.v4.media.session.MediaSessionCompat);
+ method public void unselect(int);
+ method public android.support.v7.media.MediaRouter.RouteInfo updateSelectedRoute(android.support.v7.media.MediaRouteSelector);
+ field public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1; // 0x1
+ field public static final int AVAILABILITY_FLAG_REQUIRE_MATCH = 2; // 0x2
+ field public static final int CALLBACK_FLAG_FORCE_DISCOVERY = 8; // 0x8
+ field public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1; // 0x1
+ field public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 4; // 0x4
+ field public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 2; // 0x2
+ field public static final int UNSELECT_REASON_DISCONNECTED = 1; // 0x1
+ field public static final int UNSELECT_REASON_ROUTE_CHANGED = 3; // 0x3
+ field public static final int UNSELECT_REASON_STOPPED = 2; // 0x2
+ field public static final int UNSELECT_REASON_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class MediaRouter.Callback {
+ ctor public MediaRouter.Callback();
+ method public void onProviderAdded(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+ method public void onProviderChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+ method public void onProviderRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.ProviderInfo);
+ method public void onRouteAdded(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+ method public void onRouteChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+ method public void onRoutePresentationDisplayChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+ method public void onRouteRemoved(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+ method public void onRouteSelected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+ method public void onRouteUnselected(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+ method public void onRouteVolumeChanged(android.support.v7.media.MediaRouter, android.support.v7.media.MediaRouter.RouteInfo);
+ }
+
+ public static abstract class MediaRouter.ControlRequestCallback {
+ ctor public MediaRouter.ControlRequestCallback();
+ method public void onError(java.lang.String, android.os.Bundle);
+ method public void onResult(android.os.Bundle);
+ }
+
+ public static final class MediaRouter.ProviderInfo {
+ method public android.content.ComponentName getComponentName();
+ method public java.lang.String getPackageName();
+ method public android.support.v7.media.MediaRouteProvider getProviderInstance();
+ method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+ }
+
+ public static class MediaRouter.RouteGroup extends android.support.v7.media.MediaRouter.RouteInfo {
+ method public android.support.v7.media.MediaRouter.RouteInfo getRouteAt(int);
+ method public int getRouteCount();
+ method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
+ }
+
+ public static class MediaRouter.RouteInfo {
+ method public boolean canDisconnect();
+ method public int getConnectionState();
+ method public java.util.List<android.content.IntentFilter> getControlFilters();
+ method public java.lang.String getDescription();
+ method public int getDeviceType();
+ method public android.os.Bundle getExtras();
+ method public android.net.Uri getIconUri();
+ method public java.lang.String getId();
+ method public java.lang.String getName();
+ method public int getPlaybackStream();
+ method public int getPlaybackType();
+ method public android.view.Display getPresentationDisplay();
+ method public android.support.v7.media.MediaRouter.ProviderInfo getProvider();
+ method public android.content.IntentSender getSettingsIntent();
+ method public int getVolume();
+ method public int getVolumeHandling();
+ method public int getVolumeMax();
+ method public boolean isConnecting();
+ method public boolean isDefault();
+ method public boolean isEnabled();
+ method public boolean isSelected();
+ method public boolean matchesSelector(android.support.v7.media.MediaRouteSelector);
+ method public void requestSetVolume(int);
+ method public void requestUpdateVolume(int);
+ method public void select();
+ method public void sendControlRequest(android.content.Intent, android.support.v7.media.MediaRouter.ControlRequestCallback);
+ method public boolean supportsControlAction(java.lang.String, java.lang.String);
+ method public boolean supportsControlCategory(java.lang.String);
+ method public boolean supportsControlRequest(android.content.Intent);
+ field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
+ field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
+ field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
+ field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+ field public static final int DEVICE_TYPE_TV = 1; // 0x1
+ field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
+ field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
+ field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
+ field public static final int PLAYBACK_VOLUME_VARIABLE = 1; // 0x1
+ }
+
+ public final class MediaSessionStatus {
+ method public android.os.Bundle asBundle();
+ method public static android.support.v7.media.MediaSessionStatus fromBundle(android.os.Bundle);
+ method public android.os.Bundle getExtras();
+ method public int getSessionState();
+ method public long getTimestamp();
+ method public boolean isQueuePaused();
+ field public static final int SESSION_STATE_ACTIVE = 0; // 0x0
+ field public static final int SESSION_STATE_ENDED = 1; // 0x1
+ field public static final int SESSION_STATE_INVALIDATED = 2; // 0x2
+ }
+
+ public static final class MediaSessionStatus.Builder {
+ ctor public MediaSessionStatus.Builder(int);
+ ctor public MediaSessionStatus.Builder(android.support.v7.media.MediaSessionStatus);
+ method public android.support.v7.media.MediaSessionStatus build();
+ method public android.support.v7.media.MediaSessionStatus.Builder setExtras(android.os.Bundle);
+ method public android.support.v7.media.MediaSessionStatus.Builder setQueuePaused(boolean);
+ method public android.support.v7.media.MediaSessionStatus.Builder setSessionState(int);
+ method public android.support.v7.media.MediaSessionStatus.Builder setTimestamp(long);
+ }
+
+ public class RemotePlaybackClient {
+ ctor public RemotePlaybackClient(android.content.Context, android.support.v7.media.MediaRouter.RouteInfo);
+ method public void endSession(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+ method public void enqueue(android.net.Uri, java.lang.String, android.os.Bundle, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+ method public java.lang.String getSessionId();
+ method public void getSessionStatus(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+ method public void getStatus(java.lang.String, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+ method public boolean hasSession();
+ method public boolean isQueuingSupported();
+ method public boolean isRemotePlaybackSupported();
+ method public boolean isSessionManagementSupported();
+ method public void pause(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+ method public void play(android.net.Uri, java.lang.String, android.os.Bundle, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+ method public void release();
+ method public void remove(java.lang.String, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+ method public void resume(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+ method public void seek(java.lang.String, long, android.os.Bundle, android.support.v7.media.RemotePlaybackClient.ItemActionCallback);
+ method public void setSessionId(java.lang.String);
+ method public void setStatusCallback(android.support.v7.media.RemotePlaybackClient.StatusCallback);
+ method public void startSession(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+ method public void stop(android.os.Bundle, android.support.v7.media.RemotePlaybackClient.SessionActionCallback);
+ }
+
+ public static abstract class RemotePlaybackClient.ActionCallback {
+ ctor public RemotePlaybackClient.ActionCallback();
+ method public void onError(java.lang.String, int, android.os.Bundle);
+ }
+
+ public static abstract class RemotePlaybackClient.ItemActionCallback extends android.support.v7.media.RemotePlaybackClient.ActionCallback {
+ ctor public RemotePlaybackClient.ItemActionCallback();
+ method public void onResult(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus, java.lang.String, android.support.v7.media.MediaItemStatus);
+ }
+
+ public static abstract class RemotePlaybackClient.SessionActionCallback extends android.support.v7.media.RemotePlaybackClient.ActionCallback {
+ ctor public RemotePlaybackClient.SessionActionCallback();
+ method public void onResult(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus);
+ }
+
+ public static abstract class RemotePlaybackClient.StatusCallback {
+ ctor public RemotePlaybackClient.StatusCallback();
+ method public void onItemStatusChanged(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus, java.lang.String, android.support.v7.media.MediaItemStatus);
+ method public void onSessionChanged(java.lang.String);
+ method public void onSessionStatusChanged(android.os.Bundle, java.lang.String, android.support.v7.media.MediaSessionStatus);
+ }
+
+}
+
diff --git a/v7/mediarouter/api/current.txt b/v7/mediarouter/api/current.txt
index 95fc9d2..92bbbb3 100644
--- a/v7/mediarouter/api/current.txt
+++ b/v7/mediarouter/api/current.txt
@@ -381,9 +381,12 @@
method public android.os.Bundle asBundle();
method public boolean canDisconnectAndKeepPlaying();
method public static android.support.v7.media.MediaRouteDescriptor fromBundle(android.os.Bundle);
+ method public int getConnectionState();
method public java.util.List<android.content.IntentFilter> getControlFilters();
method public java.lang.String getDescription();
+ method public int getDeviceType();
method public android.os.Bundle getExtras();
+ method public android.net.Uri getIconUri();
method public java.lang.String getId();
method public java.lang.String getName();
method public int getPlaybackStream();
@@ -393,7 +396,7 @@
method public int getVolume();
method public int getVolumeHandling();
method public int getVolumeMax();
- method public boolean isConnecting();
+ method public deprecated boolean isConnecting();
method public boolean isEnabled();
method public boolean isValid();
}
@@ -405,10 +408,13 @@
method public android.support.v7.media.MediaRouteDescriptor.Builder addControlFilters(java.util.Collection<android.content.IntentFilter>);
method public android.support.v7.media.MediaRouteDescriptor build();
method public android.support.v7.media.MediaRouteDescriptor.Builder setCanDisconnect(boolean);
- method public android.support.v7.media.MediaRouteDescriptor.Builder setConnecting(boolean);
+ method public deprecated android.support.v7.media.MediaRouteDescriptor.Builder setConnecting(boolean);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setConnectionState(int);
method public android.support.v7.media.MediaRouteDescriptor.Builder setDescription(java.lang.String);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setDeviceType(int);
method public android.support.v7.media.MediaRouteDescriptor.Builder setEnabled(boolean);
method public android.support.v7.media.MediaRouteDescriptor.Builder setExtras(android.os.Bundle);
+ method public android.support.v7.media.MediaRouteDescriptor.Builder setIconUri(android.net.Uri);
method public android.support.v7.media.MediaRouteDescriptor.Builder setId(java.lang.String);
method public android.support.v7.media.MediaRouteDescriptor.Builder setName(java.lang.String);
method public android.support.v7.media.MediaRouteDescriptor.Builder setPlaybackStream(int);
@@ -567,11 +573,14 @@
method public java.util.List<android.support.v7.media.MediaRouter.RouteInfo> getRoutes();
}
- public static final class MediaRouter.RouteInfo {
+ public static class MediaRouter.RouteInfo {
method public boolean canDisconnect();
+ method public int getConnectionState();
method public java.util.List<android.content.IntentFilter> getControlFilters();
method public java.lang.String getDescription();
+ method public int getDeviceType();
method public android.os.Bundle getExtras();
+ method public android.net.Uri getIconUri();
method public java.lang.String getId();
method public java.lang.String getName();
method public int getPlaybackStream();
@@ -594,6 +603,11 @@
method public boolean supportsControlAction(java.lang.String, java.lang.String);
method public boolean supportsControlCategory(java.lang.String);
method public boolean supportsControlRequest(android.content.Intent);
+ field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
+ field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
+ field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
+ field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
+ field public static final int DEVICE_TYPE_TV = 1; // 0x1
field public static final int PLAYBACK_TYPE_LOCAL = 0; // 0x0
field public static final int PLAYBACK_TYPE_REMOTE = 1; // 0x1
field public static final int PLAYBACK_VOLUME_FIXED = 0; // 0x0
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index a304746..48f4750 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -5,6 +5,7 @@
dependencies {
compile project(':support-appcompat-v7')
+ compile project(':support-palette-v7')
}
// some of the source requires compiling against a newer API.
@@ -56,6 +57,11 @@
androidTest.java.srcDir 'tests/src'
}
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
lintOptions {
// TODO: fix errors and reenable.
abortOnError false
@@ -111,7 +117,7 @@
}
pom.project {
- name 'Android Support Library v4'
+ name 'Android MediaRouter Support Library'
description "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 4 or later."
url 'http://developer.android.com/tools/extras/support-library.html'
inceptionYear '2011'
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png
new file mode 100644
index 0000000..71db6b4
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..d7c8252
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_grey.png b/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_grey.png
new file mode 100644
index 0000000..0493c80
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_white.png b/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_white.png
new file mode 100644
index 0000000..fce1884
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_bluetooth_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-hdpi/ic_cast_grey.png
new file mode 100644
index 0000000..f0960f8
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-hdpi/ic_cast_white.png
new file mode 100644
index 0000000..60d3915
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_close_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_close_dark.png
new file mode 100644
index 0000000..ceb1a1e
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_close_light.png b/v7/mediarouter/res/drawable-hdpi/ic_close_light.png
new file mode 100644
index 0000000..1a9cd75
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_pause_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_pause_dark.png
index 81c32fe..7192ad4 100644
--- a/v7/mediarouter/res/drawable-hdpi/ic_pause_dark.png
+++ b/v7/mediarouter/res/drawable-hdpi/ic_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-hdpi/ic_pause_light.png
index 864d8d2..bb707ea 100644
--- a/v7/mediarouter/res/drawable-hdpi/ic_pause_light.png
+++ b/v7/mediarouter/res/drawable-hdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_play_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_play_dark.png
index 568ae86..547ef30 100644
--- a/v7/mediarouter/res/drawable-hdpi/ic_play_dark.png
+++ b/v7/mediarouter/res/drawable-hdpi/ic_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_play_light.png b/v7/mediarouter/res/drawable-hdpi/ic_play_light.png
index e278033..5345ee3 100644
--- a/v7/mediarouter/res/drawable-hdpi/ic_play_light.png
+++ b/v7/mediarouter/res/drawable-hdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_setting_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_setting_dark.png
deleted file mode 100644
index 3248ad1..0000000
--- a/v7/mediarouter/res/drawable-hdpi/ic_setting_dark.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_setting_light.png b/v7/mediarouter/res/drawable-hdpi/ic_setting_light.png
deleted file mode 100644
index c39fc1f..0000000
--- a/v7/mediarouter/res/drawable-hdpi/ic_setting_light.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_speaker_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_speaker_dark.png
new file mode 100755
index 0000000..0e1da44
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_dark.png
new file mode 100755
index 0000000..b90bb2f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_light.png b/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_light.png
new file mode 100755
index 0000000..afdb9c1
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_speaker_light.png b/v7/mediarouter/res/drawable-hdpi/ic_speaker_light.png
new file mode 100755
index 0000000..e2c88be
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_tv_dark.png b/v7/mediarouter/res/drawable-hdpi/ic_tv_dark.png
new file mode 100755
index 0000000..d1335f6
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_tv_light.png b/v7/mediarouter/res/drawable-hdpi/ic_tv_light.png
new file mode 100755
index 0000000..7330f56
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png
new file mode 100644
index 0000000..dc1200e
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..2cf7e0c
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_grey.png b/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_grey.png
new file mode 100644
index 0000000..ddc8789
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_white.png b/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_white.png
new file mode 100644
index 0000000..27a8a71
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_bluetooth_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-mdpi/ic_cast_grey.png
new file mode 100644
index 0000000..35ffd60
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-mdpi/ic_cast_white.png
new file mode 100644
index 0000000..d62923f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_close_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_close_dark.png
new file mode 100644
index 0000000..af7f828
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_close_light.png b/v7/mediarouter/res/drawable-mdpi/ic_close_light.png
new file mode 100644
index 0000000..40a1a84
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_pause_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_pause_dark.png
index c4218a4..f49aed7 100644
--- a/v7/mediarouter/res/drawable-mdpi/ic_pause_dark.png
+++ b/v7/mediarouter/res/drawable-mdpi/ic_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-mdpi/ic_pause_light.png
index ab26a30..74068ea 100644
--- a/v7/mediarouter/res/drawable-mdpi/ic_pause_light.png
+++ b/v7/mediarouter/res/drawable-mdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_play_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_play_dark.png
index 4446faa..a3c80e7 100644
--- a/v7/mediarouter/res/drawable-mdpi/ic_play_dark.png
+++ b/v7/mediarouter/res/drawable-mdpi/ic_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_play_light.png b/v7/mediarouter/res/drawable-mdpi/ic_play_light.png
index 55b8c5e..f208795 100644
--- a/v7/mediarouter/res/drawable-mdpi/ic_play_light.png
+++ b/v7/mediarouter/res/drawable-mdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_setting_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_setting_dark.png
deleted file mode 100644
index 1f0ba42..0000000
--- a/v7/mediarouter/res/drawable-mdpi/ic_setting_dark.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_setting_light.png b/v7/mediarouter/res/drawable-mdpi/ic_setting_light.png
deleted file mode 100644
index 3744fe4e..0000000
--- a/v7/mediarouter/res/drawable-mdpi/ic_setting_light.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_speaker_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_speaker_dark.png
new file mode 100755
index 0000000..7cc9845
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_dark.png
new file mode 100755
index 0000000..4db7209
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_light.png b/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_light.png
new file mode 100755
index 0000000..d26bb58
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_speaker_light.png b/v7/mediarouter/res/drawable-mdpi/ic_speaker_light.png
new file mode 100755
index 0000000..ae8d47f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_tv_dark.png b/v7/mediarouter/res/drawable-mdpi/ic_tv_dark.png
new file mode 100755
index 0000000..82358a9
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_tv_light.png b/v7/mediarouter/res/drawable-mdpi/ic_tv_light.png
new file mode 100755
index 0000000..ba3f3d5
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png
new file mode 100644
index 0000000..b5c899f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..4778e00
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_grey.png b/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_grey.png
new file mode 100644
index 0000000..c57b9d6
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_white.png b/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_white.png
new file mode 100644
index 0000000..920f5ca
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_bluetooth_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-xhdpi/ic_cast_grey.png
new file mode 100644
index 0000000..dba8992
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-xhdpi/ic_cast_white.png
new file mode 100644
index 0000000..f5f7c14
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_close_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_close_dark.png
new file mode 100644
index 0000000..b7c7ffd
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_close_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_close_light.png
new file mode 100644
index 0000000..6bc4372
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_pause_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_pause_dark.png
index bd7ec0f..660ac65 100644
--- a/v7/mediarouter/res/drawable-xhdpi/ic_pause_dark.png
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_pause_light.png
index e79d7d7..792104ff 100644
--- a/v7/mediarouter/res/drawable-xhdpi/ic_pause_light.png
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_play_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_play_dark.png
index 9a5d45f..be5c062 100644
--- a/v7/mediarouter/res/drawable-xhdpi/ic_play_dark.png
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_play_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_play_light.png
index acaeca6..d12d495 100644
--- a/v7/mediarouter/res/drawable-xhdpi/ic_play_light.png
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_setting_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_setting_dark.png
deleted file mode 100644
index 8db5dbb..0000000
--- a/v7/mediarouter/res/drawable-xhdpi/ic_setting_dark.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_setting_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_setting_light.png
deleted file mode 100644
index bfc30ef..0000000
--- a/v7/mediarouter/res/drawable-xhdpi/ic_setting_light.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_speaker_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_dark.png
new file mode 100755
index 0000000..8f8a552
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_dark.png
new file mode 100755
index 0000000..6227ca2
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_light.png
new file mode 100755
index 0000000..82599f5
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_speaker_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_light.png
new file mode 100755
index 0000000..74f9f6d
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_tv_dark.png b/v7/mediarouter/res/drawable-xhdpi/ic_tv_dark.png
new file mode 100755
index 0000000..cef8ac5
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_tv_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_tv_light.png
new file mode 100755
index 0000000..3131256
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png
new file mode 100644
index 0000000..0546539
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..8e38265
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_grey.png b/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_grey.png
new file mode 100644
index 0000000..8e9aa70
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_white.png b/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_white.png
new file mode 100644
index 0000000..860c758
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_bluetooth_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-xxhdpi/ic_cast_grey.png
new file mode 100644
index 0000000..7582751
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-xxhdpi/ic_cast_white.png
new file mode 100644
index 0000000..7a7673fb
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_close_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_close_dark.png
new file mode 100644
index 0000000..6b717e0
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_close_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_close_light.png
new file mode 100644
index 0000000..51b4401
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_pause_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_pause_dark.png
index 2a96557..3ea7e03 100644
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_pause_dark.png
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_pause_light.png
index bf2560f..dc63538 100644
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_pause_light.png
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_play_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_play_dark.png
index 1ec1995..2745c3a 100644
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_play_dark.png
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_play_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_play_light.png
index a5bd8df..1c57756b 100644
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_play_light.png
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_setting_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_setting_dark.png
deleted file mode 100644
index 1d58233..0000000
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_setting_dark.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_setting_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_setting_light.png
deleted file mode 100644
index 43c9b99b..0000000
--- a/v7/mediarouter/res/drawable-xxhdpi/ic_setting_light.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_dark.png
new file mode 100755
index 0000000..874c961
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_dark.png
new file mode 100755
index 0000000..6869bdc
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_light.png
new file mode 100755
index 0000000..35de6f4
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_light.png
new file mode 100755
index 0000000..65ee187
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_tv_dark.png b/v7/mediarouter/res/drawable-xxhdpi/ic_tv_dark.png
new file mode 100755
index 0000000..a6a4858
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_tv_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_tv_light.png
new file mode 100755
index 0000000..4ca6787
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_grey.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_grey.png
new file mode 100644
index 0000000..d124cb8
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_white.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_white.png
new file mode 100644
index 0000000..bb3539c
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_cast_white.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_close_light.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_close_light.png
new file mode 100644
index 0000000..df42fee
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00000.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00000.png
new file mode 100644
index 0000000..16e4cbc
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00000.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00001.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00001.png
new file mode 100644
index 0000000..6cc54b6
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00001.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00002.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00002.png
new file mode 100644
index 0000000..ae4f8fb
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00002.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00003.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00003.png
new file mode 100644
index 0000000..cd3ffdb
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00003.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00004.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00004.png
new file mode 100644
index 0000000..2285ec7
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00004.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00005.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00005.png
new file mode 100644
index 0000000..8130cb1
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00005.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00006.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00006.png
new file mode 100644
index 0000000..4369a3d
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00006.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00007.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00007.png
new file mode 100644
index 0000000..301e6c7
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00007.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00008.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00008.png
new file mode 100644
index 0000000..442cc82
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00008.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00009.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00009.png
new file mode 100644
index 0000000..78763f6
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00009.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00010.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00010.png
new file mode 100644
index 0000000..1ea59a8
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00010.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00011.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00011.png
new file mode 100644
index 0000000..77ea83a
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00011.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00012.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00012.png
new file mode 100644
index 0000000..4e742f5
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00012.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00013.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00013.png
new file mode 100644
index 0000000..fa49b62
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00013.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00014.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00014.png
new file mode 100644
index 0000000..dc477a2
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00014.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00015.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00015.png
new file mode 100644
index 0000000..dd85400
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_collapse_00015.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00000.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00000.png
new file mode 100644
index 0000000..dd85400
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00000.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00001.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00001.png
new file mode 100644
index 0000000..2586aa0
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00001.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00002.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00002.png
new file mode 100644
index 0000000..4022000
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00002.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00003.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00003.png
new file mode 100644
index 0000000..358b428
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00003.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00004.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00004.png
new file mode 100644
index 0000000..1da8c49
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00004.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00005.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00005.png
new file mode 100644
index 0000000..342d6c7
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00005.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00006.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00006.png
new file mode 100644
index 0000000..738bddd
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00006.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00007.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00007.png
new file mode 100644
index 0000000..48192c4
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00007.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00008.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00008.png
new file mode 100644
index 0000000..ff1a374
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00008.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00009.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00009.png
new file mode 100644
index 0000000..c13afcd
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00009.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00010.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00010.png
new file mode 100644
index 0000000..dde5939
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00010.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00011.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00011.png
new file mode 100644
index 0000000..5c60a08
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00011.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00012.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00012.png
new file mode 100644
index 0000000..5d75964
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00012.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00013.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00013.png
new file mode 100644
index 0000000..cf1c1cd
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00013.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00014.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00014.png
new file mode 100644
index 0000000..12ccc03
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00014.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00015.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00015.png
new file mode 100644
index 0000000..16e4cbc
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_expand_00015.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_pause_light.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_pause_light.png
new file mode 100644
index 0000000..66178aa
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_play_light.png b/v7/mediarouter/res/drawable-xxxhdpi/ic_play_light.png
new file mode 100644
index 0000000..904bbdb
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxxhdpi/ic_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable/ic_collapse.xml b/v7/mediarouter/res/drawable/ic_collapse.xml
new file mode 100644
index 0000000..143e862
--- /dev/null
+++ b/v7/mediarouter/res/drawable/ic_collapse.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_collapse_00000" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00001" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00002" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00003" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00004" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00005" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00006" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00007" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00008" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00009" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00010" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00011" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00012" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00013" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00014" android:duration="13" />
+ <item android:drawable="@drawable/ic_collapse_00015" android:duration="13" />
+</animation-list>
diff --git a/v7/mediarouter/res/drawable/ic_expand.xml b/v7/mediarouter/res/drawable/ic_expand.xml
new file mode 100644
index 0000000..2bd29ae
--- /dev/null
+++ b/v7/mediarouter/res/drawable/ic_expand.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_expand_00000" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00001" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00002" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00003" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00004" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00005" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00006" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00007" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00008" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00009" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00010" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00011" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00012" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00013" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00014" android:duration="13" />
+ <item android:drawable="@drawable/ic_expand_00015" android:duration="13" />
+</animation-list>
diff --git a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml b/v7/mediarouter/res/drawable/mr_dialog_material_background_dark.xml
similarity index 67%
rename from v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
rename to v7/mediarouter/res/drawable/mr_dialog_material_background_dark.xml
index ec7903b..54f348c 100644
--- a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
+++ b/v7/mediarouter/res/drawable/mr_dialog_material_background_dark.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,13 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
+<!-- This is the copy of @drawable/abc_dialog_material_background_dark except for inset
+ which includes unnecessary padding. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval" >
-
- <size
- android:height="@dimen/lb_guidedactions_item_checkmark_diameter"
- android:width="@dimen/lb_guidedactions_item_checkmark_diameter" />
-
- <solid android:color="@color/lb_tv_white" />
-
-</shape>
+ android:shape="rectangle">
+ <corners android:radius="2dp" />
+ <solid android:color="@color/background_floating_material_dark" />
+</shape>
\ No newline at end of file
diff --git a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml b/v7/mediarouter/res/drawable/mr_dialog_material_background_light.xml
similarity index 66%
copy from v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
copy to v7/mediarouter/res/drawable/mr_dialog_material_background_light.xml
index ec7903b..b5d82af 100644
--- a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
+++ b/v7/mediarouter/res/drawable/mr_dialog_material_background_light.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
+<!-- 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.
@@ -14,13 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
+<!-- This is the copy of @drawable/abc_dialog_material_background_light except for inset
+ which includes unnecessary padding. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval" >
-
- <size
- android:height="@dimen/lb_guidedactions_item_checkmark_diameter"
- android:width="@dimen/lb_guidedactions_item_checkmark_diameter" />
-
- <solid android:color="@color/lb_tv_white" />
-
-</shape>
+ android:shape="rectangle">
+ <corners android:radius="2dp" />
+ <solid android:color="@color/background_floating_material_light" />
+</shape>
\ No newline at end of file
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
similarity index 75%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
index a4614f6..05b4a8a 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- 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.
@@ -14,6 +14,6 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_setting_light" />
-</selector>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_audiotrack_light"
+ android:alpha="0.87" />
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v7/mediarouter/res/drawable/mr_ic_close_dark.xml
similarity index 92%
rename from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
rename to v7/mediarouter/res/drawable/mr_ic_close_dark.xml
index a4614f6..4a88cec 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_close_dark.xml
@@ -15,5 +15,5 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_setting_light" />
+ <item android:drawable="@drawable/ic_close_dark" />
</selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml b/v7/mediarouter/res/drawable/mr_ic_close_light.xml
similarity index 85%
copy from v7/mediarouter/res/drawable/mr_ic_settings_light.xml
copy to v7/mediarouter/res/drawable/mr_ic_close_light.xml
index a4614f6..c663ae8 100644
--- a/v7/mediarouter/res/drawable/mr_ic_settings_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_close_light.xml
@@ -15,5 +15,10 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_setting_light" />
+ <item>
+ <bitmap
+ android:src="@drawable/ic_close_light"
+ android:alpha="0.87" />
+ </item>
+
</selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_pause_light.xml b/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
index 9702be8..0cea425 100644
--- a/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
@@ -15,5 +15,9 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_pause_light" />
+ <item>
+ <bitmap
+ android:src="@drawable/ic_pause_light"
+ android:alpha="0.87" />
+ </item>
</selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_play_light.xml b/v7/mediarouter/res/drawable/mr_ic_play_light.xml
index d18cc12..48a7e03 100644
--- a/v7/mediarouter/res/drawable/mr_ic_play_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_play_light.xml
@@ -15,5 +15,9 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_play_light" />
+ <item>
+ <bitmap
+ android:src="@drawable/ic_play_light"
+ android:alpha="0.87" />
+ </item>
</selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_settings_dark.xml b/v7/mediarouter/res/drawable/mr_ic_settings_dark.xml
deleted file mode 100644
index 0fe662e..0000000
--- a/v7/mediarouter/res/drawable/mr_ic_settings_dark.xml
+++ /dev/null
@@ -1,19 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_setting_dark" />
-</selector>
diff --git a/v17/preference-leanback/res/values/ids.xml b/v7/mediarouter/res/interpolator/mr_fast_out_slow_in.xml
similarity index 77%
copy from v17/preference-leanback/res/values/ids.xml
copy to v7/mediarouter/res/interpolator/mr_fast_out_slow_in.xml
index 20c1eda..a51bfce 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v7/mediarouter/res/interpolator/mr_fast_out_slow_in.xml
@@ -15,6 +15,8 @@
~ limitations under the License
-->
-<resources>
- <item name="transitionPosition" type="id" />
-</resources>
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.4"
+ android:controlY1="0"
+ android:controlX2="0.2"
+ android:controlY2="1"/>
diff --git a/v17/preference-leanback/res/values/ids.xml b/v7/mediarouter/res/interpolator/mr_linear_out_slow_in.xml
similarity index 77%
copy from v17/preference-leanback/res/values/ids.xml
copy to v7/mediarouter/res/interpolator/mr_linear_out_slow_in.xml
index 20c1eda..d500c8b 100644
--- a/v17/preference-leanback/res/values/ids.xml
+++ b/v7/mediarouter/res/interpolator/mr_linear_out_slow_in.xml
@@ -15,6 +15,8 @@
~ limitations under the License
-->
-<resources>
- <item name="transitionPosition" type="id" />
-</resources>
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0"
+ android:controlY1="0"
+ android:controlX2="0.2"
+ android:controlY2="1"/>
diff --git a/v7/mediarouter/res/layout-v17/mr_media_route_list_item.xml b/v7/mediarouter/res/layout-v17/mr_media_route_list_item.xml
deleted file mode 100644
index 1b798ee..0000000
--- a/v7/mediarouter/res/layout-v17/mr_media_route_list_item.xml
+++ /dev/null
@@ -1,48 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical">
-
- <LinearLayout android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="start|center_vertical"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:duplicateParentState="true">
-
- <TextView android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:duplicateParentState="true" />
-
- <TextView android:id="@android:id/text2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:duplicateParentState="true" />
- </LinearLayout>
-
-</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_media_route_chooser_dialog.xml b/v7/mediarouter/res/layout/mr_chooser_dialog.xml
similarity index 61%
rename from v7/mediarouter/res/layout/mr_media_route_chooser_dialog.xml
rename to v7/mediarouter/res/layout/mr_chooser_dialog.xml
index afdad71..bda99f5 100644
--- a/v7/mediarouter/res/layout/mr_media_route_chooser_dialog.xml
+++ b/v7/mediarouter/res/layout/mr_chooser_dialog.xml
@@ -14,28 +14,32 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+
+ <ListView android:id="@+id/mr_chooser_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
- <ListView android:id="@+id/media_route_list"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" />
+ android:divider="@android:color/transparent"
+ android:dividerHeight="0dp" />
<LinearLayout android:id="@android:id/empty"
android:layout_width="fill_parent"
- android:layout_height="64dp"
- android:orientation="horizontal"
+ android:layout_height="240dp"
+ android:orientation="vertical"
+ android:paddingTop="90dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:visibility="gone">
- <ProgressBar android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:paddingLeft="16dp"
- android:text="@string/mr_media_route_chooser_searching" />
+ android:text="@string/mr_chooser_searching" />
+ <ProgressBar android:layout_width="150dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ style="?android:attr/progressBarStyleHorizontal" />
</LinearLayout>
-</LinearLayout>
+</FrameLayout>
diff --git a/v7/mediarouter/res/layout/mr_chooser_list_item.xml b/v7/mediarouter/res/layout/mr_chooser_list_item.xml
new file mode 100644
index 0000000..d578560
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_chooser_list_item.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="56dp"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:orientation="horizontal"
+ android:gravity="center_vertical" >
+
+ <ImageView android:id="@+id/mr_chooser_route_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginRight="24dp" />
+
+ <LinearLayout android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="1dp"
+ android:orientation="vertical" >
+
+ <TextView android:id="@+id/mr_chooser_route_name"
+ android:layout_width="fill_parent"
+ android:layout_height="32dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?attr/mediaRouteChooserPrimaryTextStyle" />
+
+ <TextView android:id="@+id/mr_chooser_route_desc"
+ android:layout_width="fill_parent"
+ android:layout_height="24dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?attr/mediaRouteChooserSecondaryTextStyle" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml b/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
new file mode 100644
index 0000000..091f5f8
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
@@ -0,0 +1,96 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/mr_expandable_area"
+ android:background="@android:color/transparent"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <LinearLayout android:id="@+id/mr_dialog_area"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/MediaRouteControllerWindowBackground"
+ android:layout_gravity="center"
+ android:orientation="vertical">
+ <LinearLayout android:id="@+id/mr_title_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="24dp"
+ android:paddingRight="12dp"
+ android:orientation="horizontal" >
+ <TextView android:id="@+id/mr_name"
+ android:layout_width="0dp"
+ android:layout_height="72dp"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="?attr/mediaRouteControllerTitleTextStyle" />
+ <ImageButton android:id="@+id/mr_close"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@string/mr_controller_close_description"
+ android:src="?attr/mediaRouteCloseDrawable"
+ android:background="?attr/selectableItemBackgroundBorderless" />
+ </LinearLayout>
+ <FrameLayout android:id="@+id/mr_custom_control"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+ <FrameLayout android:id="@+id/mr_default_control"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <ImageView android:id="@+id/mr_art"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:adjustViewBounds="true"
+ android:scaleType="fitXY"
+ android:background="?attr/colorPrimary"
+ android:layout_gravity="top"
+ android:visibility="gone" />
+ <LinearLayout android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_gravity="bottom">
+ <LinearLayout android:id="@+id/mr_media_main_control"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:layout_gravity="bottom">
+ <include android:id="@+id/mr_playback_control"
+ layout="@layout/mr_playback_control" />
+ <View android:id="@+id/mr_control_divider"
+ android:layout_width="fill_parent"
+ android:layout_height="8dp"
+ android:visibility="gone" />
+ <include android:id="@+id/mr_volume_control"
+ layout="@layout/mr_volume_control" />
+ </LinearLayout>
+ <ListView android:id="@+id/mr_volume_group_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/mr_controller_volume_group_list_padding_top"
+ android:scrollbarStyle="outsideOverlay"
+ android:clipToPadding="false"
+ android:visibility="gone" />
+ </LinearLayout>
+ </FrameLayout>
+ <include layout="@layout/abc_alert_dialog_button_bar_material" />
+ </LinearLayout>
+</FrameLayout>
diff --git a/v7/mediarouter/res/layout/mr_controller_volume_item.xml b/v7/mediarouter/res/layout/mr_controller_volume_item.xml
new file mode 100644
index 0000000..4d693e2
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_controller_volume_item.xml
@@ -0,0 +1,46 @@
+<?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:layout_width="fill_parent"
+ android:layout_height="@dimen/mr_controller_volume_group_list_item_height"
+ android:paddingLeft="24dp"
+ android:paddingRight="60dp"
+ android:paddingBottom="8dp"
+ android:orientation="vertical" >
+ <TextView android:id="@+id/mr_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?attr/mediaRouteControllerSecondaryTextStyle"
+ android:singleLine="true" />
+ <LinearLayout android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+ <ImageView android:id="@+id/mr_volume_item_icon"
+ android:layout_width="@dimen/mr_controller_volume_group_list_item_icon_size"
+ android:layout_height="@dimen/mr_controller_volume_group_list_item_icon_size"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:scaleType="fitCenter"
+ android:src="?attr/mediaRouteAudioTrackDrawable" />
+ <android.support.v7.app.MediaRouteVolumeSlider android:id="@+id/mr_volume_slider"
+ android:layout_width="fill_parent"
+ android:layout_height="40dp"
+ android:minHeight="40dp"
+ android:maxHeight="40dp" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml b/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
deleted file mode 100644
index 3e5f7d9..0000000
--- a/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
+++ /dev/null
@@ -1,141 +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.
--->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <LinearLayout android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <LinearLayout android:id="@+id/title_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView android:id="@+id/route_name"
- android:layout_width="0dp"
- android:layout_height="72dp"
- android:layout_weight="1"
- android:layout_marginLeft="24dip"
- android:layout_marginRight="24dip"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:ellipsize="end"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorPrimary" />
- <ImageButton android:id="@+id/settings"
- android:layout_width="48dip"
- android:layout_height="48dip"
- android:padding="12dip"
- android:layout_marginTop="12dip"
- android:layout_marginBottom="12dip"
- android:layout_marginRight="12dip"
- android:contentDescription="@string/mr_media_route_controller_settings_description"
- android:src="?attr/mediaRouteSettingsDrawable"
- android:background="?attr/selectableItemBackgroundBorderless"
- android:visibility="gone" />
- </LinearLayout>
- <FrameLayout android:id="@+id/media_route_control_frame"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
- <RelativeLayout android:id="@+id/default_control_frame"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?attr/colorPrimary" >
- <ImageView android:id="@+id/art"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxHeight="@dimen/mr_media_route_controller_art_max_height"
- android:adjustViewBounds="true"
- android:scaleType="centerCrop"/>
- <ImageButton android:id="@+id/play_pause"
- android:layout_width="48dip"
- android:layout_height="48dip"
- android:padding="12dip"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
- android:layout_alignParentRight="true"
- android:layout_below="@id/art"
- android:contentDescription="@string/mr_media_route_controller_play"
- android:background="?attr/selectableItemBackgroundBorderless"/>
- <LinearLayout android:orientation="vertical"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:minHeight="64dip"
- android:layout_marginLeft="24dip"
- android:gravity="center_vertical"
- android:layout_toLeftOf="@id/play_pause"
- android:layout_below="@id/art"
- android:layout_alignParentLeft="true" >
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
- android:textStyle="bold"
- android:singleLine="true" />
- <TextView android:id="@+id/subtitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"
- android:singleLine="true" />
- </LinearLayout>
- </RelativeLayout>
- </FrameLayout>
- <!-- Optional volume slider section. -->
- <LinearLayout android:id="@+id/media_route_volume_layout"
- android:layout_width="fill_parent"
- android:layout_height="64dp"
- android:gravity="center_vertical"
- android:padding="8dp"
- android:visibility="gone">
- <ImageView android:layout_width="48dp"
- android:layout_height="48dp"
- android:src="?attr/mediaRouteCastDrawable"
- android:gravity="center"
- android:scaleType="center" />
- <SeekBar android:id="@+id/media_route_volume_slider"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp" />
- </LinearLayout>
- <LinearLayout android:id="@+id/buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <Button android:id="@+id/disconnect"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:layout_weight="1"
- android:background="?attr/selectableItemBackgroundBorderless"
- android:text="@string/mr_media_route_controller_disconnect"
- android:visibility="gone" />
- <Button android:id="@+id/stop"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:layout_weight="1"
- android:textColor="?attr/colorAccent"
- android:background="?attr/selectableItemBackgroundBorderless"
- android:text="@string/mr_media_route_controller_stop" />
- </LinearLayout>
- </LinearLayout>
-</ScrollView>
diff --git a/v7/mediarouter/res/layout/mr_media_route_list_item.xml b/v7/mediarouter/res/layout/mr_media_route_list_item.xml
deleted file mode 100644
index 6c63a12..0000000
--- a/v7/mediarouter/res/layout/mr_media_route_list_item.xml
+++ /dev/null
@@ -1,48 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="64dp"
- android:gravity="center_vertical">
-
- <LinearLayout android:layout_width="0dp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="left|center_vertical"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:duplicateParentState="true">
-
- <TextView android:id="@android:id/text1"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:duplicateParentState="true" />
-
- <TextView android:id="@android:id/text2"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:duplicateParentState="true" />
- </LinearLayout>
-
-</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_playback_control.xml b/v7/mediarouter/res/layout/mr_playback_control.xml
new file mode 100644
index 0000000..9ee2191
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_playback_control.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingLeft="24dp"
+ android:paddingRight="12dp" >
+ <ImageButton android:id="@+id/mr_control_play_pause"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:contentDescription="@string/mr_controller_play"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:visibility="gone" />
+ <LinearLayout android:id="@+id/mr_control_title_container"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/mr_control_play_pause"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true">
+ <TextView android:id="@+id/mr_control_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?attr/mediaRouteControllerPrimaryTextStyle"
+ android:singleLine="true" />
+ <TextView android:id="@+id/mr_control_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?attr/mediaRouteControllerSecondaryTextStyle"
+ android:singleLine="true" />
+ </LinearLayout>
+</RelativeLayout>
diff --git a/v7/mediarouter/res/layout/mr_volume_control.xml b/v7/mediarouter/res/layout/mr_volume_control.xml
new file mode 100644
index 0000000..f22cbf6
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_volume_control.xml
@@ -0,0 +1,48 @@
+<?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:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:gravity="center_vertical"
+ android:paddingLeft="24dp"
+ android:paddingRight="12dp">
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:src="?attr/mediaRouteAudioTrackDrawable"
+ android:gravity="center"
+ android:scaleType="center"/>
+ <!-- Since dialog's top layout mr_expandable_area is clickable, it propagates pressed state
+ to its non-clickable children. Specify android:clickable="true" to prevent volume slider
+ from having false pressed state. -->
+ <android.support.v7.app.MediaRouteVolumeSlider
+ android:id="@+id/mr_volume_slider"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:maxHeight="48dp"
+ android:layout_weight="1"
+ android:clickable="true" />
+ <android.support.v7.app.MediaRouteExpandCollapseButton
+ android:id="@+id/mr_group_expand_collapse"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="12dp"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:visibility="gone"/>
+</LinearLayout>
diff --git a/v7/mediarouter/res/values-af/strings.xml b/v7/mediarouter/res/values-af/strings.xml
index 8f44f51..024a99c 100644
--- a/v7/mediarouter/res/values-af/strings.xml
+++ b/v7/mediarouter/res/values-af/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Stelsel"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Toestelle"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Saai uit"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Koppel aan toestel"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Soek tans vir toestelle…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ontkoppel"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Hou op uitsaai"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Roete-instellings"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Speel"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Laat wag"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Geen inligting beskikbaar nie"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knoppie"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Hou op uitsaai"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Maak toe"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Speel"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Laat wag"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/res/values-am/strings.xml
index ec3fa64..4456b45 100644
--- a/v7/mediarouter/res/values-am/strings.xml
+++ b/v7/mediarouter/res/values-am/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ስርዓት"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"መሣሪያዎች"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ውሰድ"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ከመሳሪያ ጋር ያገናኙ"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"መሳሪያዎችን በመፈለግ ላይ…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ግንኙነት አቋርጥ"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"መውሰድ አቁም"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"የመንገድ ቅንብሮች"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"አጫውት"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ለአፍታ አቁም"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ምንም መረጃ አይገኝም"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"የ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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Cast ማድረግ አቁም"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"ዝጋ"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"አጫውት"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"ለአፍታ አቁም"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"አስፋ"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ሰብስብ"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
index 078a9bf..7222590 100644
--- a/v7/mediarouter/res/values-ar/strings.xml
+++ b/v7/mediarouter/res/values-ar/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"النظام"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"الأجهزة"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"إرسال"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"الاتصال بجهاز"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"جارٍ البحث عن الأجهزة…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"قطع الاتصال"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"إيقاف الإرسال"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"إعدادات المسار"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"تشغيل"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"إيقاف مؤقت"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"لا تتوفر أية معلومات"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"زر الإرسال"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"إيقاف الإرسال"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"إغلاق"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"تشغيل"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"إيقاف مؤقت"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"توسيع"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"تصغير"</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>
</resources>
diff --git a/v7/mediarouter/res/values-az-rAZ/strings.xml b/v7/mediarouter/res/values-az-rAZ/strings.xml
index 27b4a91..aa3a70f 100644
--- a/v7/mediarouter/res/values-az-rAZ/strings.xml
+++ b/v7/mediarouter/res/values-az-rAZ/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"İştirakçılar"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Cihaza qoş"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Cihazları axtarır..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Bağlantını kəs"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Yayımı dayandır"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Marşrut parametrləri"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Göstər"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Fasilə ver"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Əlçatan info yoxdur"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Yayım düyməsi"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Yayımı dayandırın"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Qapadın"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Oynadın"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Durdurun"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-bg/strings.xml b/v7/mediarouter/res/values-bg/strings.xml
index 90e3b53..de49179 100644
--- a/v7/mediarouter/res/values-bg/strings.xml
+++ b/v7/mediarouter/res/values-bg/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Предаване"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Свързване с устройство"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Търсят се устройства…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Прекратяване на връзката"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Спиране на предаването"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Настройки за маршрута"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Пускане"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Поставяне на пауза"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Няма налична информация"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Бутон за предаване"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Спиране на предаването"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Затваряне"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Пускане"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Поставяне на пауза"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Разгъване"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свиване"</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>
</resources>
diff --git a/v7/mediarouter/res/values-bn-rBD/strings.xml b/v7/mediarouter/res/values-bn-rBD/strings.xml
index 5382752..7eb5301 100644
--- a/v7/mediarouter/res/values-bn-rBD/strings.xml
+++ b/v7/mediarouter/res/values-bn-rBD/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"সিস্টেম"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ডিভাইসগুলি"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"কাস্ট করুন"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ডিভাইসে সংযোগ করুন"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ডিভাইসগুলি অনুসন্ধান করা হচ্ছে…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"সংযোগ বিচ্ছিন্ন করুন"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"কাস্ট করা বন্ধ করুন"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"সেটিংস রুট করুন"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"চালান"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"বিরাম দিন"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"কোনো তথ্য উপলব্ধ নেই"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"কাস্ট করার বোতাম"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"কাস্ট করা বন্ধ করুন"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"বন্ধ করুন"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"চালান"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"বিরাম দিন"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"প্রসারিত করুন"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"সঙ্কুচিত করুন"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
index c3b9bd5..ab8809a 100644
--- a/v7/mediarouter/res/values-ca/strings.xml
+++ b/v7/mediarouter/res/values-ca/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositius"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Emet"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connecta al dispositiu"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"S\'estan cercant dispositius…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconnecta"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Atura l\'emissió"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuració de la ruta"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reprodueix"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Posa en pausa"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No hi ha informació disponible"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Botó d\'emetre"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Atura l\'emissió"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Tanca"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Reprodueix"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Posa en pausa"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Desplega"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Replega"</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>
</resources>
diff --git a/v7/mediarouter/res/values-cs/strings.xml b/v7/mediarouter/res/values-cs/strings.xml
index e85c3e2..57c1594 100644
--- a/v7/mediarouter/res/values-cs/strings.xml
+++ b/v7/mediarouter/res/values-cs/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Odeslat"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Připojení k zařízení"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Vyhledávání zařízení…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Odpojit"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ukončit odesílání"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavení trasy"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Přehrát"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pozastavit"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Žádné informace"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačítko odesílání"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Zastavit odesílání"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Zavřít"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Přehrát"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pozastavit"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbalit"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sbalit"</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>
</resources>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
index c0f2322..eb6c8fa 100644
--- a/v7/mediarouter/res/values-da/strings.xml
+++ b/v7/mediarouter/res/values-da/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheder"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Opret forbindelse til enheden"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Søger efter enheder..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Afbryd forbindelsen"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop med at caste"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ruteindstillinger"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Afspil"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sæt på pause"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Der er ingen tilgængelige oplysninger"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knap"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Stop med at caste"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Luk"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Afspil"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Sæt på pause"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Udvid"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</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>
</resources>
diff --git a/v7/mediarouter/res/values-de/strings.xml b/v7/mediarouter/res/values-de/strings.xml
index 22b3e1a..17a84af 100644
--- a/v7/mediarouter/res/values-de/strings.xml
+++ b/v7/mediarouter/res/values-de/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Übertragen"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Mit Gerät verbinden"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Geräte werden gesucht…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Verbindung aufheben"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Übertragung stoppen"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Routingeinstellungen"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Wiedergabe"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Keine Informationen verfügbar"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-Symbol"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Streaming stoppen"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Schließen"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Wiedergeben"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausieren"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Maximieren"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minimieren"</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>
</resources>
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/res/values-el/strings.xml
index 5b4fff1..9258296 100644
--- a/v7/mediarouter/res/values-el/strings.xml
+++ b/v7/mediarouter/res/values-el/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Σύστημα"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Συσκευές"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Μετάδοση"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Σύνδεση με τη συσκευή"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Αναζήτηση συσκευών…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Αποσύνδεση"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Διακοπή μετάδοσης"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ρυθμίσεις διαδρομής"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Αναπαραγωγή"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Παύση"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Δεν υπάρχουν διαθέσιμες πληροφορίες"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Κουμπί 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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Διακοπή μετάδοσης"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Κλείσιμο"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Αναπαραγωγή"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Παύση"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ανάπτυξη"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Σύμπτυξη"</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>
</resources>
diff --git a/v7/mediarouter/res/values-en-rAU/strings.xml b/v7/mediarouter/res/values-en-rAU/strings.xml
index 21f25a9..5edd79b 100644
--- a/v7/mediarouter/res/values-en-rAU/strings.xml
+++ b/v7/mediarouter/res/values-en-rAU/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No info available"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Stop casting"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</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>
</resources>
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/res/values-en-rGB/strings.xml
index 21f25a9..5edd79b 100644
--- a/v7/mediarouter/res/values-en-rGB/strings.xml
+++ b/v7/mediarouter/res/values-en-rGB/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No info available"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Stop casting"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</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>
</resources>
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/res/values-en-rIN/strings.xml
index 21f25a9..5edd79b 100644
--- a/v7/mediarouter/res/values-en-rIN/strings.xml
+++ b/v7/mediarouter/res/values-en-rIN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No info available"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Stop casting"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Close"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Play"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</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>
</resources>
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/res/values-es-rUS/strings.xml
index e9f1707..b0a0a61 100644
--- a/v7/mediarouter/res/values-es-rUS/strings.xml
+++ b/v7/mediarouter/res/values-es-rUS/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar al dispositivo"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Detener transmisión"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuración de ruta"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproducir"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausar"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No hay información disponible"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Botón para transmitir"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Detener la transmisión"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Cerrar"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Reproducir"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</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>
</resources>
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/res/values-es/strings.xml
index 44aa935..3a1eaeb 100644
--- a/v7/mediarouter/res/values-es/strings.xml
+++ b/v7/mediarouter/res/values-es/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Enviar contenido"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar a dispositivo"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Dejar de enviar contenido"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ajustes de ruta"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproducir"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"No hay información disponible"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de enviar"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Dejar de enviar contenido"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Cerrar"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Reproducir"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</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>
</resources>
diff --git a/v7/mediarouter/res/values-et-rEE/strings.xml b/v7/mediarouter/res/values-et-rEE/strings.xml
index d0a4263..9058dcf 100644
--- a/v7/mediarouter/res/values-et-rEE/strings.xml
+++ b/v7/mediarouter/res/values-et-rEE/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Ülekandmine"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Seadmega ühendamine"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Seadmete otsimine …"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Katkesta ühendus"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Lõpeta ülekanne"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Marsruudi seaded"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Esitamine"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Peatamine"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Teave pole saadaval"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Ülekandenupp"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Peata ülekanne"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Sulgemine"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Esitamine"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Peatamine"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laiendamine"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ahendamine"</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>
</resources>
diff --git a/v7/mediarouter/res/values-eu-rES/strings.xml b/v7/mediarouter/res/values-eu-rES/strings.xml
index 463a56d..ad85c5a 100644
--- a/v7/mediarouter/res/values-eu-rES/strings.xml
+++ b/v7/mediarouter/res/values-eu-rES/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Gailuak"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Igorri"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Konektatu gailura"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Gailuak bilatzen…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Deskonektatu"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Utzi igortzeari"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ibilbidearen ezarpenak"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Erreproduzitu"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausatu"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Ez dago informaziorik"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Igorri botoia"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Utzi igortzeari"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Itxi"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Erreproduzitu"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausatu"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zabaldu"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tolestu"</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>
</resources>
diff --git a/v7/mediarouter/res/values-fa/strings.xml b/v7/mediarouter/res/values-fa/strings.xml
index 191fc832..87a81ba 100644
--- a/v7/mediarouter/res/values-fa/strings.xml
+++ b/v7/mediarouter/res/values-fa/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"سیستم"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"دستگاهها"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"فرستادن"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"برقراری ارتباط با دستگاه"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"در حال جستجو برای دستگاهها..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"قطع ارتباط"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"توقف فرستادن"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"تنظیمات مسیر"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"پخش"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"مکث"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"اطلاعات دردسترس نیست"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"دکمه ارسال محتوا"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"توقف ارسال محتوا"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"بستن"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"پخش"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"توقف موقت"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"بزرگ کردن"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"کوچک کردن"</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>
</resources>
diff --git a/v7/mediarouter/res/values-fi/strings.xml b/v7/mediarouter/res/values-fi/strings.xml
index b5960ab..a93d74e 100644
--- a/v7/mediarouter/res/values-fi/strings.xml
+++ b/v7/mediarouter/res/values-fi/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Lähetä"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Yhdistä laitteeseen"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Etsitään laitteita…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Katkaise yhteys"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Lopeta suoratoisto"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Reitin asetukset"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Toista"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Keskeytä"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Tietoja ei ole saatavilla"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-painike"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Lopeta suoratoisto"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Sulje"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Toista"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Keskeytä"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laajenna"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tiivistä"</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>
</resources>
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/res/values-fr-rCA/strings.xml
index 799cc7e..f0c6976 100644
--- a/v7/mediarouter/res/values-fr-rCA/strings.xml
+++ b/v7/mediarouter/res/values-fr-rCA/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Diffuser"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connexion au périphérique"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Recherche d\'appareils en cours…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Déconnecter"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Arrêter la diffusion"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Paramètres de l\'itinéraire"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Lecture"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Suspendre"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Aucune information disponible"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Bouton Diffuser"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Arrêter la diffusion"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Fermer"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Lire"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Interrompre"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/res/values-fr/strings.xml
index fec6833..de94f18 100644
--- a/v7/mediarouter/res/values-fr/strings.xml
+++ b/v7/mediarouter/res/values-fr/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Caster"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connecter à l\'appareil"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Recherche d\'appareils en cours…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Déconnecter"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Arrêter la diffusion"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Paramètres de l\'itinéraire"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Lecture"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Aucune information disponible"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Icône Cast"</string>
+ <string name="mr_chooser_title" msgid="414301941546135990">"Diffuser 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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Arrêter de diffuser"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Fermer"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Lecture"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pause"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-gl-rES/strings.xml b/v7/mediarouter/res/values-gl-rES/strings.xml
index 56ce29c..fb76c68 100644
--- a/v7/mediarouter/res/values-gl-rES/strings.xml
+++ b/v7/mediarouter/res/values-gl-rES/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Emitir"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar co dispositivo"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Parar de emitir"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuración da ruta"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduce"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Non hai información dispoñible"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de emitir"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Parar de emitir"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Pechar"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Reproduce"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ampliar"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Contraer"</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>
</resources>
diff --git a/v7/mediarouter/res/values-gu-rIN/strings.xml b/v7/mediarouter/res/values-gu-rIN/strings.xml
index 3d1c36e3..211f836 100644
--- a/v7/mediarouter/res/values-gu-rIN/strings.xml
+++ b/v7/mediarouter/res/values-gu-rIN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"સિસ્ટમ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ઉપકરણો"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"કાસ્ટ કરો"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ઉપકરણ સાથે કનેક્ટ કરો"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ઉપકરણો માટે શોધી રહ્યું છે…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ડિસ્કનેક્ટ કરો"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"કાસ્ટ કરવાનું રોકો"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"રૂટ સેટિંગ્સ"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ચલાવો"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"થોભો"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"કોઈ માહિતી ઉપલબ્ધ નથી"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"કાસ્ટ કરો બટન"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"કાસ્ટ કરવાનું રોકો"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"બંધ કરો"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"ચલાવો"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"થોભાવો"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"વિસ્તૃત કરો"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"સંકુચિત કરો"</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>
</resources>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index d1fa0ba..e2c7a43 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"डिवाइस"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्ट करें"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"डिवाइस से कनेक्ट करें"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"डिवाइस की खोज हो रही है…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"डिस्कनेक्ट करें"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्ट करना बंद करें"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिंग"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"चलाएं"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"रोकें"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"कोई जानकारी उपलब्ध नहीं"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट करें बटन"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"कास्ट करना बंद करें"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"बंद करें"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"चलाएं"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"रोकें"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करें"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त करें"</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>
</resources>
diff --git a/v7/mediarouter/res/values-hr/strings.xml b/v7/mediarouter/res/values-hr/strings.xml
index 7030acc..d79258fbf 100644
--- a/v7/mediarouter/res/values-hr/strings.xml
+++ b/v7/mediarouter/res/values-hr/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Emitiranje"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Povezivanje s uređajem"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Traženje uređaja…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Prekini vezu"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zaustavi emitiranje"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Postavke rute"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reprodukcija"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pauziraj"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Informacije nisu dostupne"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za emitiranje"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Zaustavi emitiranje"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Zatvaranje"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Reprodukcija"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pauziranje"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/res/values-hu/strings.xml
index 25c2518..7686fea 100644
--- a/v7/mediarouter/res/values-hu/strings.xml
+++ b/v7/mediarouter/res/values-hu/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Tartalomátküldés"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Csatlakozás adott eszközhöz"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Eszközkeresés…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Leválasztás"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Átküldés leállítása"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Útvonal-beállítások"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Indítás"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Szüneteltetés"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nincs információ"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Átküldés gomb"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Átküldés leállítása"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Bezárás"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Lejátszás"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Szüneteltetés"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-hy-rAM/strings.xml b/v7/mediarouter/res/values-hy-rAM/strings.xml
index ac02c1a..85bd488 100644
--- a/v7/mediarouter/res/values-hy-rAM/strings.xml
+++ b/v7/mediarouter/res/values-hy-rAM/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Համակարգ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Սարքեր"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Հեռարձակում"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Միանալ սարքին"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Որոնվում են սարքեր..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Անջատել"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Դադարեցնել հեռարձակումը"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ֆայլերի փոխանցման կարգավորումներ"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Նվագարկել"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Դադար"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Տեղեկությունները հասանելի չեն"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Հեռարձակման կոճակ"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Դադարեցնել հեռարձակումը"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Փակել"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Նվագարկել"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Դադար"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ընդարձակել"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Կոծկել"</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>
</resources>
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
index 96e08b5..3d01880 100644
--- a/v7/mediarouter/res/values-in/strings.xml
+++ b/v7/mediarouter/res/values-in/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Perangkat"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmisi"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Sambungkan ke perangkat"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Menelusuri perangkat…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Putuskan sambungan"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Hentikan transmisi"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Setelan rute"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Putar"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Jeda"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Tidak ada info yang tersedia"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Tombol transmisi"</string>
+ <string name="mr_chooser_title" msgid="414301941546135990">"Transmisi ke"</string>
+ <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari perangkat"</string>
+ <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Hentikan transmisi"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Putar"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Luaskan"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ciutkan"</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>
</resources>
diff --git a/v7/mediarouter/res/values-is-rIS/strings.xml b/v7/mediarouter/res/values-is-rIS/strings.xml
index 66d5ca5..366f6f6 100644
--- a/v7/mediarouter/res/values-is-rIS/strings.xml
+++ b/v7/mediarouter/res/values-is-rIS/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Senda út"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Tengjast tæki"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Leitar að tækjum…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Aftengja"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stöðva útsendingu"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Leiðarstillingar"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spila"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Hlé"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Engar upplýsingar í boði"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Útsendingarhnappur"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Stöðva útsendingu"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Loka"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Spila"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Hlé"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/res/values-it/strings.xml
index c04f408..9febd99 100644
--- a/v7/mediarouter/res/values-it/strings.xml
+++ b/v7/mediarouter/res/values-it/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivi"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Trasmetti"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connetti al dispositivo"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Ricerca di dispositivi…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnetti"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Interrompi trasmissione"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Impostazioni percorso"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Riproduci"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nessuna informazione disponibile"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Pulsante Trasmetti"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Interrompi trasmissione"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Chiudi"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Riproduci"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Espandi"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Comprimi"</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>
</resources>
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/res/values-iw/strings.xml
index 60fdc53..d1698a5 100644
--- a/v7/mediarouter/res/values-iw/strings.xml
+++ b/v7/mediarouter/res/values-iw/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"מערכת"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"מכשירים"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"העבר"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"התחבר למכשיר"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"מחפש מכשירים…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"התנתק"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"עצור העברה"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"הגדרות נתיב"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"הפעל"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"השהה"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"אין מידע זמין"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"לחצן הפעלת 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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"עצור העברה"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"סגור"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"הפעל"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"השהה"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"הרחב"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"כווץ"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ja/strings.xml b/v7/mediarouter/res/values-ja/strings.xml
index 0b39a09..ea8d838 100644
--- a/v7/mediarouter/res/values-ja/strings.xml
+++ b/v7/mediarouter/res/values-ja/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"システム"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"端末"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"キャスト"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"端末に接続"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"端末を検索しています…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"接続を解除"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"キャストを停止"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ルーティング設定"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"再生"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"一時停止"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"情報がありません"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"キャストアイコン"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"キャストを停止"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"閉じる"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"再生"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"一時停止"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折りたたむ"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ka-rGE/strings.xml b/v7/mediarouter/res/values-ka-rGE/strings.xml
index 9f0761b..2182b64 100644
--- a/v7/mediarouter/res/values-ka-rGE/strings.xml
+++ b/v7/mediarouter/res/values-ka-rGE/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"სისტემა"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"მოწყობილობები"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"მსახიობები"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"მოწყობილობასთან დაკავშირება"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"მოწყობილობების ძიება…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"კავშირის გაწყვეტა"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ტრანსლაციის შეჩერება"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"მარშრუტის პარამეტრები"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"დაკვრა"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"პაუზა"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ინფორმაცია არ არის ხელმისაწვდომი"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ტრანსლირების ღილაკი"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"ტრანსლირების შეჩერება"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"დახურვა"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"დაკვრა"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"პაუზა"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"გაშლა"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ჩაკეცვა"</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>
</resources>
diff --git a/v7/mediarouter/res/values-kk-rKZ/strings.xml b/v7/mediarouter/res/values-kk-rKZ/strings.xml
index 2fea3dd..5c72c5f 100644
--- a/v7/mediarouter/res/values-kk-rKZ/strings.xml
+++ b/v7/mediarouter/res/values-kk-rKZ/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Жүйе"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Құрылғылар"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Трансляциялау"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Құрылғыға жалғау"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Құрылғыларды іздеуде…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ажырату"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Трансляциялауды тоқтату"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Жол параметрлері"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ойнату"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Кідірту"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Қолжетімді ақпарат жоқ"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Трансляциялау түймесі"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Трансляциялауды тоқтату"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Жабу"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Ойнату"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Кідірту"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Жаю"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жию"</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>
</resources>
diff --git a/v7/mediarouter/res/values-km-rKH/strings.xml b/v7/mediarouter/res/values-km-rKH/strings.xml
index 0a62013..cdf94db 100644
--- a/v7/mediarouter/res/values-km-rKH/strings.xml
+++ b/v7/mediarouter/res/values-km-rKH/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ប្រព័ន្ធ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ឧបករណ៍"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"បញ្ជូន"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ភ្ជាប់ឧបករណ៍"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"កំពុងស្វែងរកឧបករណ៍..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ផ្ដាច់"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"បញ្ឈប់ការខាស"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ការកំណត់ផ្លូវ"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ចាក់"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ផ្អាក"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"មិនមានព័ត៌មានទេ"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ប៊ូតុងខាស"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"បញ្ឈប់ការខាស"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"បិទ"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"ចាក់"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"ផ្អាក"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"ពង្រីក"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"បង្រួម"</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>
</resources>
diff --git a/v7/mediarouter/res/values-kn-rIN/strings.xml b/v7/mediarouter/res/values-kn-rIN/strings.xml
index 887b2ec..970dc41 100644
--- a/v7/mediarouter/res/values-kn-rIN/strings.xml
+++ b/v7/mediarouter/res/values-kn-rIN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ಸಿಸ್ಟಂ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ಸಾಧನಗಳು"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ಪಾತ್ರ"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಿ"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ಬಿತ್ತರಿಸುವಿಕೆ ನಿಲ್ಲಿಸು"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ಮಾರ್ಗ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ಪ್ಲೇ ಮಾಡು"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ವಿರಾಮ"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ಯಾವುದೇ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ಬಿತ್ತರಿಸು ಬಟನ್"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"ಬಿತ್ತರಿಸುವಿಕೆ ನಿಲ್ಲಿಸು"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"ಮುಚ್ಚು"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"ಪ್ಲೇ ಮಾಡಿ"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"ವಿರಾಮ"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"ವಿಸ್ತರಿಸು"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ಸಂಕುಚಿಸು"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ko/strings.xml b/v7/mediarouter/res/values-ko/strings.xml
index b3a6983e..2b3455f 100644
--- a/v7/mediarouter/res/values-ko/strings.xml
+++ b/v7/mediarouter/res/values-ko/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"시스템"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"기기"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"전송"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"기기에 연결"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"기기 검색 중…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"연결 해제"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"전송 중지"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"경로 설정"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"재생"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"일시중지"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"정보가 없습니다."</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"전송 버튼"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"전송 중지"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"닫기"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"재생"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"일시중지"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"펼치기"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"접기"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ky-rKG/strings.xml b/v7/mediarouter/res/values-ky-rKG/strings.xml
index f7df56c..d7409db 100644
--- a/v7/mediarouter/res/values-ky-rKG/strings.xml
+++ b/v7/mediarouter/res/values-ky-rKG/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Түзмөктөр"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Тандалгандар"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Түзмөккө туташуу"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Түзмөктөр изделүүдө..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ажыратуу"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Тышк экранга чыгарну токтотуу"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Багыт жөндөөлөрү"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ойнотуу"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Тындыруу"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Эч маалымат жок"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Тышкы экранга чыгаруу баскычы"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Тышк экранга чыгарну токтотуу"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Жабуу"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Ойнотуу"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Тындыруу"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Жайып көрсөтүү"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жыйыштыруу"</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>
</resources>
diff --git a/v7/mediarouter/res/values-land/dimens.xml b/v7/mediarouter/res/values-land/dimens.xml
new file mode 100644
index 0000000..ee606aa
--- /dev/null
+++ b/v7/mediarouter/res/values-land/dimens.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<resources>
+ <!-- MediaRouteController's volume group list -->
+ <eat-comment />
+ <!-- Maximum height of volume group list. -->
+ <dimen name="mr_controller_volume_group_list_max_height">132dp</dimen>
+ <!-- Height of volume group item. -->
+ <dimen name="mr_controller_volume_group_list_item_height">61dp</dimen>
+ <!-- Size of an item's icon. -->
+ <dimen name="mr_controller_volume_group_list_item_icon_size">18dp</dimen>
+</resources>
diff --git a/v7/mediarouter/res/values-lo-rLA/strings.xml b/v7/mediarouter/res/values-lo-rLA/strings.xml
index 6f8e010..a19dd69 100644
--- a/v7/mediarouter/res/values-lo-rLA/strings.xml
+++ b/v7/mediarouter/res/values-lo-rLA/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ລະບົບ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ອຸປະກອນ"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ສົ່ງສັນຍານ"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ເຊື່ອມຕໍ່ຫາອຸປະກອນ"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ກຳລັງຊອກຫາອຸປະກອນ..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ຕັດການເຊື່ອມຕໍ່"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ຢຸດການສົ່ງສັນຍານ"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ການຕັ້ງຄ່າເສັ້ນທາງ"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ຫຼິ້ນ"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ຢຸດຊົ່ວຄາວ"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ບໍ່ມີຂໍ້ມູນຢູ່"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ປຸ່ມຄາສທ໌"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"ຢຸດການຄາສທ໌"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"ປິດ"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"ຫຼິ້ນ"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"ຢຸດຊົ່ວຄາວ"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"ຂະຫຍາຍ"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ຫຍໍ້ລົງ"</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>
</resources>
diff --git a/v7/mediarouter/res/values-lt/strings.xml b/v7/mediarouter/res/values-lt/strings.xml
index 0832d64..d286e0c 100644
--- a/v7/mediarouter/res/values-lt/strings.xml
+++ b/v7/mediarouter/res/values-lt/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Įrenginiai"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Perduoti"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Prijungimas prie įrenginio"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Ieškoma įrenginių…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Atjungti"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Sustabdyti perdavimą"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Maršruto nustatymai"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Leisti"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pristabdyti"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Informacija nepasiekiama"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Perdavimo mygtukas"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Sustabdyti perdavimą"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Uždaryti"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Leisti"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pristabdyti"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/res/values-lv/strings.xml
index 1c20c9b..8f49d85 100644
--- a/v7/mediarouter/res/values-lv/strings.xml
+++ b/v7/mediarouter/res/values-lv/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Apraidīt"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Savienojuma izveide ar ierīci"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Notiek ierīču meklēšana..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Atvienot"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Pārtraukt apraidi"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Maršruta iestatījumi"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Atskaņot"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Apturēt"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nav pieejama informācija"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Apraides poga"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Pārtraukt apraidi"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Aizvērt"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Atskaņot"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Apturēt"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-mk-rMK/strings.xml b/v7/mediarouter/res/values-mk-rMK/strings.xml
index 1b2756f..e8ff3e7 100644
--- a/v7/mediarouter/res/values-mk-rMK/strings.xml
+++ b/v7/mediarouter/res/values-mk-rMK/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Уреди"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Емитувај"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Поврзи се со уредот"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Се пребаруваат уреди..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Исклучи се"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Запри префрлување"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Поставки на маршрутата"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Репродуцирај"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Пауза"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Нема достапни информации"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Копчето за 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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Запри го емитувањето"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Затвори"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Репродуцирај"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Паузирај"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Собери"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ml-rIN/strings.xml b/v7/mediarouter/res/values-ml-rIN/strings.xml
index 57b23f8..7dbdf5d 100644
--- a/v7/mediarouter/res/values-ml-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ml-rIN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"സിസ്റ്റം"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ഉപകരണങ്ങൾ"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"കാസ്റ്റുചെയ്യുക"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ഉപകരണത്തിലേക്ക് കണക്റ്റുചെയ്യുക"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ഉപകരണങ്ങൾക്കായി തിരയുന്നു…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"വിച്ഛേദിക്കുക"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"കാസ്റ്റുചെയ്യൽ നിർത്തുക"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"റൂട്ട് ക്രമീകരണം"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"പ്ലേ ചെയ്യുക"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"താൽക്കാലികമായി നിർത്തുക"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ടാപ്പുചെയ്യുക"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"കാസ്റ്റുചെയ്യൽ നിർത്തുക"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"അടയ്ക്കുക"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"പ്ലേ ചെയ്യുക"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"തൽക്കാലം നിർത്തൂ"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"വികസിപ്പിക്കുക"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ചുരുക്കുക"</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>
</resources>
diff --git a/v7/mediarouter/res/values-mn-rMN/strings.xml b/v7/mediarouter/res/values-mn-rMN/strings.xml
index 1bba4d5..db6d599 100644
--- a/v7/mediarouter/res/values-mn-rMN/strings.xml
+++ b/v7/mediarouter/res/values-mn-rMN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Төхөөрөмжүүд"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Дамжуулах"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Төхөөрөмжтэй холбох"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Төхөөрөмжүүдийг хайж байна…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Салгах"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Нэвтрүүлэхийг зогсоох"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Маршрут тохиргоо"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Тоглуулах"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Түр зогсоох"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Мэдээлэл байхгүй байна"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Дамжуулах товчлуур"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Дамжуулахыг зогсоох"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Хаах"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Тоглуулах"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Түр зогсоох"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Дэлгэх"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Хураах"</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>
</resources>
diff --git a/v7/mediarouter/res/values-mr-rIN/strings.xml b/v7/mediarouter/res/values-mr-rIN/strings.xml
index 6b607cc..b3f9264 100644
--- a/v7/mediarouter/res/values-mr-rIN/strings.xml
+++ b/v7/mediarouter/res/values-mr-rIN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"डिव्हाइसेस"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्ट करा"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"डिव्हाइसला कनेक्ट करा"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"डिव्हाइसेस शोधत आहे…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"डिस्कनेक्ट करा"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्ट करणे थांबवा"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिंग्ज"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"प्ले करा"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"विराम द्या"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"कोणतीही माहिती उपलब्ध नाही"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट बटण"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"कास्ट करणे थांबवा"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"बंद करा"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"प्ले करा"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"विराम"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करा"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संकुचित करा"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ms-rMY/strings.xml b/v7/mediarouter/res/values-ms-rMY/strings.xml
index 946a514..4d7a0c8 100644
--- a/v7/mediarouter/res/values-ms-rMY/strings.xml
+++ b/v7/mediarouter/res/values-ms-rMY/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Peranti"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Barisan pelakon"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Sambung kepada peranti"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Mencari peranti..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Putuskan sambungan"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Berhenti menghantar"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Tetapan laluan"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Main"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Jeda"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Maklumat tidak tersedia"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Butang Hantar"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Berhenti menghantar"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Main"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Kembangkan"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Runtuhkan"</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>
</resources>
diff --git a/v7/mediarouter/res/values-my-rMM/strings.xml b/v7/mediarouter/res/values-my-rMM/strings.xml
index db4a72b..9447089 100644
--- a/v7/mediarouter/res/values-my-rMM/strings.xml
+++ b/v7/mediarouter/res/values-my-rMM/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"စနစ်"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"စက်ပစ္စည်းများ"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"သရုပ်ဆောင်များ"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"စက်တစ်ခုကို ချိတ်ဆက်ပါ"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"စက်ပစ္စည်းများကို ရှာဖွေနေပါသည်"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ချိတ်ဆက်ခြင်းရပ်တန့်ရန်"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ပုံစံသွင်းမှု ရပ်ရန်"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"လမ်းကြောင်း အပြင်အဆင်များ"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ဖွင့်ရန်"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ခဏရပ်ရန်"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"အချက်အလက် မရရှိနိုင်ပါ"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ကာစ်တ်လုပ်ရန် ခလုတ်"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"ကာစ်တ်လုပ်ခြင်း ရပ်တန့်ရန်"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"ပိတ်ရန်"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"ဖွင့်ရန်"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"ခဏရပ်ရန်"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"ဖြန့်ချရန်၃"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ခေါက်သိမ်းရန်..."</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>
</resources>
diff --git a/v7/mediarouter/res/values-nb/strings.xml b/v7/mediarouter/res/values-nb/strings.xml
index 018c02f..aea341f 100644
--- a/v7/mediarouter/res/values-nb/strings.xml
+++ b/v7/mediarouter/res/values-nb/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Koble til enheten"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Søker etter enheter …"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Koble fra"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stopp castingen"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ruteinnstillinger"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spill av"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sett på pause"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Ingen informasjon er tilgjengelig"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-ikonet"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Stopp castingen"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Lukk"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Spill av"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Sett på pause"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Utvid"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ne-rNP/strings.xml b/v7/mediarouter/res/values-ne-rNP/strings.xml
index 84ca24e..d261553 100644
--- a/v7/mediarouter/res/values-ne-rNP/strings.xml
+++ b/v7/mediarouter/res/values-ne-rNP/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"प्रणाली"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"उपकरणहरू"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्ट"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"उपकरणसँग जडान गर्नुहोस्"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"उपकरणहरूका लागि खोजी गरिँदै..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"विच्छेदन गर्नुहोस्"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्टिंग रोक्नुहोस्"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिङ"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"बजाउनुहोस्"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"रोक्नुहोस्"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"जानकारी उपलब्ध छैन"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"casting रोक्नुहोस्"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"बन्द गर्नुहोस्"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"बजाउनुहोस्"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"रोक्नुहोस्"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तार गर्नुहोस्"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त पार्नुहोस्"</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>
</resources>
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/res/values-nl/strings.xml
index c317820e..7843b52 100644
--- a/v7/mediarouter/res/values-nl/strings.xml
+++ b/v7/mediarouter/res/values-nl/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Systeem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Apparaten"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Casten"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Verbinding maken met apparaat"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Zoeken naar apparaten…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Verbinding verbreken"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Casten stoppen"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route-instellingen"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Afspelen"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Onderbreken"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Geen informatie beschikbaar"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-icoon"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Casten stoppen"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Sluiten"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Afspelen"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Onderbreken"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Uitvouwen"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Samenvouwen"</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>
</resources>
diff --git a/v7/mediarouter/res/values-pa-rIN/strings.xml b/v7/mediarouter/res/values-pa-rIN/strings.xml
index dc4e9d0..55dfd88 100644
--- a/v7/mediarouter/res/values-pa-rIN/strings.xml
+++ b/v7/mediarouter/res/values-pa-rIN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ਸਿਸਟਮ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ਡਿਵਾਈਸਾਂ"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ਜੋੜੋ"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ਡਿਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ਡਿਵਾਈਸਾਂ ਦੀ ਖੋਜ ਕਰ ਰਿਹਾ ਹੈ…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ਜੋੜਨਾ ਰੋਕੋ"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ਰੂਟ ਸੈਟਿੰਗਾਂ"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ਪਲੇ ਕਰੋ"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ਰੋਕੋ"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ਕੋਈ ਜਾਣਕਾਰੀ ਉਪਲਬਧ ਨਹੀਂ"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ਕਾਸਟ ਬਟਨ"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"ਜੋੜਨਾ ਰੋਕੋ"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"ਬੰਦ ਕਰੋ"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"ਪਲੇ ਕਰੋ"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"ਰੋਕੋ"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"ਵਿਸਤਾਰ ਕਰੋ"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ਬੰਦ ਕਰੋ"</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>
</resources>
diff --git a/v7/mediarouter/res/values-pl/strings.xml b/v7/mediarouter/res/values-pl/strings.xml
index e6f4780..c6e7f8a 100644
--- a/v7/mediarouter/res/values-pl/strings.xml
+++ b/v7/mediarouter/res/values-pl/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Przesyłaj"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Połącz z urządzeniem"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Szukam urządzeń…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Rozłącz"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zakończ przesyłanie"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ustawienia trasy"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Odtwórz"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Wstrzymaj"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Brak informacji"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Przycisk Cast"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Zatrzymaj przesyłanie"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Zamknij"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Odtwórz"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Wstrzymaj"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozwiń"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zwiń"</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>
</resources>
diff --git a/v7/mediarouter/res/values-pt-rBR/strings.xml b/v7/mediarouter/res/values-pt-rBR/strings.xml
index 629c63f..17e64f0 100644
--- a/v7/mediarouter/res/values-pt-rBR/strings.xml
+++ b/v7/mediarouter/res/values-pt-rBR/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar ao dispositivo"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Procurando dispositivos…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Interromper transmissão"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configurações de rota"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduzir"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausar"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nenhuma informação disponível"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Interromper transmissão"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</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>
</resources>
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/res/values-pt-rPT/strings.xml
index 90ce270..3c9d4cb 100644
--- a/v7/mediarouter/res/values-pt-rPT/strings.xml
+++ b/v7/mediarouter/res/values-pt-rPT/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Ligar ao dispositivo"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"A pesquisar dispositivos…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desassociar"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Parar a transmissão"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Definições de trajeto"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduzir"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Colocar em pausa"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nenhuma informação disponível"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Interromper a transmissão"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Interromper"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Reduzir"</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>
</resources>
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/res/values-pt/strings.xml
index 629c63f..17e64f0 100644
--- a/v7/mediarouter/res/values-pt/strings.xml
+++ b/v7/mediarouter/res/values-pt/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar ao dispositivo"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Procurando dispositivos…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Interromper transmissão"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configurações de rota"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduzir"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausar"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nenhuma informação disponível"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Interromper transmissão"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Fechar"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Reproduzir"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausar"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/res/values-ro/strings.xml
index 9e7fdb9..20c3b71 100644
--- a/v7/mediarouter/res/values-ro/strings.xml
+++ b/v7/mediarouter/res/values-ro/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispozitive"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Trimiteți"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectați-vă la dispozitiv"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Se caută dispozitive..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Deconectați-vă"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Nu mai proiectați"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Setări pentru traseu"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Redați"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Întrerupeți"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nu sunt disponibile informații"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Butonul de proiecție"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Opriți proiecția"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Închideți"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Redați"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Întrerupeți"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/res/values-ru/strings.xml
index 381f5ec..5a47ec6 100644
--- a/v7/mediarouter/res/values-ru/strings.xml
+++ b/v7/mediarouter/res/values-ru/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Транслировать."</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Подключение к устройству"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Поиск устройств…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Отключить"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Остановить трансляцию"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Настройки передачи файлов"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Воспроизвести."</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Приостановить."</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Данных нет"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляции"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Остановить трансляцию"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Закрыть"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Воспроизвести"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Приостановить"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Развернуть"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свернуть"</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>
</resources>
diff --git a/v7/mediarouter/res/values-si-rLK/strings.xml b/v7/mediarouter/res/values-si-rLK/strings.xml
index b8949ec..45f67ff 100644
--- a/v7/mediarouter/res/values-si-rLK/strings.xml
+++ b/v7/mediarouter/res/values-si-rLK/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"පද්ධතිය"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"උපාංග"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"උපාංගයට සම්බන්ධ වන්න"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"උපාංග සඳහා සොයමින්…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"විසන්ධි කරන්න"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"කාස්ට් කිරීම නවත්වන්න"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ගමන් මගේ සැකසීම්"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ධාවනය කරන්න"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"විරාමය"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ලබා ගත හැකි තොරතුරු නොමැත"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"විකාශ බොත්තම"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"විකාශ කිරීම නවත්වන්න"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"වසන්න"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"ධාවනය කරන්න"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"විරාම ගන්වන්න"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"දිග හරින්න"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"හකුළන්න"</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>
</resources>
diff --git a/v7/mediarouter/res/values-sk/strings.xml b/v7/mediarouter/res/values-sk/strings.xml
index cc9336e..df95e00 100644
--- a/v7/mediarouter/res/values-sk/strings.xml
+++ b/v7/mediarouter/res/values-sk/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Prenášať"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Pripojenie k zariadeniu"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Prebieha vyhľadávanie zariadení…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Odpojiť"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zastaviť prenášanie"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavenia trasy"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Prehrať"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pozastaviť"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nie sú k dispozícii žiadne informácie"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačidlo prenosu"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Zastaviť prenos"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Zavrieť"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Prehrať"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pozastaviť"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbaliť"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zbaliť"</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>
</resources>
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/res/values-sl/strings.xml
index f5da487..6425222 100644
--- a/v7/mediarouter/res/values-sl/strings.xml
+++ b/v7/mediarouter/res/values-sl/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Naprave"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Predvajanje"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Povezovanje z napravo"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Iskanje naprav …"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Prekini povezavo"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ustavi predvajanje"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavitve poti"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Predvajaj"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Zaustavi"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Podatki niso na voljo"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za predvajanje"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Ustavi predvajanje"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Zapri"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Predvajanje"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Zaustavi"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-sq-rAL/strings.xml b/v7/mediarouter/res/values-sq-rAL/strings.xml
index de3a1c8..6f375cf 100644
--- a/v7/mediarouter/res/values-sq-rAL/strings.xml
+++ b/v7/mediarouter/res/values-sq-rAL/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistemi"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Pajisjet"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmeto"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Lidhu me pajisjen"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Po kërkon për pajisje…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Shkëputu"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ndalo transmetimin"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Cilësimet e rrugës"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Luaj"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pauzë"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Nuk jepet asnjë informacion"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Butoni i transmetimit"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Ndalo transmetimin"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Mbyll"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Luaj"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pauzë"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zgjeroje"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Palose"</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>
</resources>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
index 1ca7107..26a36a9 100644
--- a/v7/mediarouter/res/values-sr/strings.xml
+++ b/v7/mediarouter/res/values-sr/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Уређаји"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Пребацуј"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Повежите са уређајем"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Претраживање уређаја…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Прекини везу"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Заустави пребацивање"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Подешавања путање"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Пусти"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Паузирај"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Нису доступне никакве информације"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Дугме Пребаци"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Заустави пребацивање"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Затвори"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Пусти"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Паузирај"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Скупи"</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>
</resources>
diff --git a/v7/mediarouter/res/values-sv/strings.xml b/v7/mediarouter/res/values-sv/strings.xml
index 3721864..3e8c47b 100644
--- a/v7/mediarouter/res/values-sv/strings.xml
+++ b/v7/mediarouter/res/values-sv/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Casta"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Anslut till enhet"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Söker efter enheter ..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Koppla från"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Sluta casta"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Inställningar för omdirigering"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spela upp"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Det finns ingen information"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knappen"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Sluta casta"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Stäng"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Spela upp"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/res/values-sw/strings.xml
index b9208f3..38fdb45 100644
--- a/v7/mediarouter/res/values-sw/strings.xml
+++ b/v7/mediarouter/res/values-sw/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Mfumo"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Vifaa"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Tuma"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Unganisha kwenye kifaa"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Inatafuta vifaa..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Tenganisha"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Acha kutuma"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Mipangilio ya njia"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Google Play"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sitisha"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Hakuna maelezo yaliyopatikana"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Kitufe cha kutuma"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Acha kutuma"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Funga"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Cheza"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Sitisha"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Panua"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Kunja"</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>
</resources>
diff --git a/v7/mediarouter/res/values-sw600dp/dimens.xml b/v7/mediarouter/res/values-sw600dp/dimens.xml
index 5b29058..ee07732 100644
--- a/v7/mediarouter/res/values-sw600dp/dimens.xml
+++ b/v7/mediarouter/res/values-sw600dp/dimens.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- 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.
@@ -15,5 +15,10 @@
-->
<resources>
- <dimen name="mr_media_route_controller_art_max_height">480dp</dimen>
-</resources>
\ No newline at end of file
+ <!-- The platform's desired fixed width for a dialog along the major axis
+ (the screen is in landscape). This may be either a fraction or a dimension.-->
+ <item type="dimen" name="mr_dialog_fixed_width_major">60%</item>
+ <!-- The platform's desired fixed width for a dialog along the minor axis
+ (the screen is in portrait). This may be either a fraction or a dimension.-->
+ <item type="dimen" name="mr_dialog_fixed_width_minor">90%</item>
+</resources>
diff --git a/v7/mediarouter/res/values-sw720dp/dimens.xml b/v7/mediarouter/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000..ab6131f
--- /dev/null
+++ b/v7/mediarouter/res/values-sw720dp/dimens.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<resources>
+ <!-- The platform's desired fixed width for a dialog along the major axis
+ (the screen is in landscape). This may be either a fraction or a dimension.-->
+ <item type="dimen" name="mr_dialog_fixed_width_major">50%</item>
+ <!-- The platform's desired fixed width for a dialog along the minor axis
+ (the screen is in portrait). This may be either a fraction or a dimension.-->
+ <item type="dimen" name="mr_dialog_fixed_width_minor">70%</item>
+</resources>
diff --git a/v7/mediarouter/res/values-ta-rIN/strings.xml b/v7/mediarouter/res/values-ta-rIN/strings.xml
index 7b0c13b..6147b75 100644
--- a/v7/mediarouter/res/values-ta-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ta-rIN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"அமைப்பு"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"அனுப்பு"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"சாதனத்துடன் இணைக்கவும்"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"சாதனங்களைத் தேடுகிறது..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"துண்டி"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"அனுப்புவதை நிறுத்து"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"வழி அமைப்புகள்"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"இயக்கு"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"இடைநிறுத்து"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"தகவல் எதுவுமில்லை"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"அனுப்புதல் பொத்தான்"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"அனுப்புவதை நிறுத்து"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"மூடும்"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"இயக்கும்"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"இடைநிறுத்தும்"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"விரிவாக்கு"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"சுருக்கு"</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>
</resources>
diff --git a/v7/mediarouter/res/values-te-rIN/strings.xml b/v7/mediarouter/res/values-te-rIN/strings.xml
index 97b2510..73c75f4 100644
--- a/v7/mediarouter/res/values-te-rIN/strings.xml
+++ b/v7/mediarouter/res/values-te-rIN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"సిస్టమ్"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"పరికరాలు"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ప్రసారం చేయండి"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"పరికరానికి కనెక్ట్ చేయండి"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"పరికరాల కోసం శోధిస్తోంది…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"డిస్కనెక్ట్ చేయి"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ప్రసారాన్ని ఆపివేయి"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"మార్గ సెట్టింగ్లు"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ప్లే చేయి"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"పాజ్ చేయి"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"సమాచారం అందుబాటులో లేదు"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ప్రసారం చేయి బటన్"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"ప్రసారాన్ని ఆపివేయి"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"మూసివేస్తుంది"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"ప్లే చేస్తుంది"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"పాజ్ చేస్తుంది"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"విస్తరింపజేస్తుంది"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"కుదిస్తుంది"</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>
</resources>
diff --git a/v7/mediarouter/res/values-th/strings.xml b/v7/mediarouter/res/values-th/strings.xml
index 9122e27..fdf0957 100644
--- a/v7/mediarouter/res/values-th/strings.xml
+++ b/v7/mediarouter/res/values-th/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ระบบ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"อุปกรณ์"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"แคสต์"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"เชื่อมต่อกับอุปกรณ์"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"กำลังค้นหาอุปกรณ์…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ยกเลิกการเชื่อมต่อ"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"หยุดการส่ง"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"การตั้งค่าเส้นทาง"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"เล่น"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"หยุดชั่วคราว"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"ไม่มีข้อมูล"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"ปุ่ม \"แคสต์\""</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"หยุดการแคสต์"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"ปิด"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"เล่น"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"หยุดชั่วคราว"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"ขยาย"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ยุบ"</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>
</resources>
diff --git a/v7/mediarouter/res/values-tl/strings.xml b/v7/mediarouter/res/values-tl/strings.xml
index b6ce45e..7c04b33 100644
--- a/v7/mediarouter/res/values-tl/strings.xml
+++ b/v7/mediarouter/res/values-tl/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"I-cast"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Kumonekta sa device"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Naghahanap ng mga device…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Idiskonekta"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Itigil ang pagca-cast"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Mga setting ng ruta"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"I-play"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"I-pause"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Walang available na impormasyon"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Button na I-cast"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Itigil ang pagca-cast"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Isara"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"I-play"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"I-pause"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
index d8d398c..f8316f4 100644
--- a/v7/mediarouter/res/values-tr/strings.xml
+++ b/v7/mediarouter/res/values-tr/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Yayınla"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Cihaza bağlanın"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Cihaz arayın…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Bağlantıyı kes"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Yayını durdur"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Rota ayarları"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Oynat"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Duraklat"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Bilgi yok"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Yayın düğmesi"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Yayını durdur"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Kapat"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Oynat"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Duraklat"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-uk/strings.xml b/v7/mediarouter/res/values-uk/strings.xml
index beab592..fd4e0d0 100644
--- a/v7/mediarouter/res/values-uk/strings.xml
+++ b/v7/mediarouter/res/values-uk/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Пристрої"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Транслювати"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Під’єднатися до пристрою"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Пошук пристроїв…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Від’єднатися"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Зупинити трансляцію"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Налаштування маршруту"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Відтворити"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Призупинити"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Немає даних"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляції"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Припинити трансляцію"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Закрити"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Відтворити"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Призупинити"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Розгорнути"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Згорнути"</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>
</resources>
diff --git a/v7/mediarouter/res/values-ur-rPK/strings.xml b/v7/mediarouter/res/values-ur-rPK/strings.xml
index 9784c4a..afd5534 100644
--- a/v7/mediarouter/res/values-ur-rPK/strings.xml
+++ b/v7/mediarouter/res/values-ur-rPK/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"سسٹم"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"آلات"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"کاسٹ کریں"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"آلہ سے مربوط ہوں"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"آلات تلاش کر رہا ہے…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"غیر مربوط کریں"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"کاسٹ کرنا بند کریں"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"روٹ کی ترتیبات"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"چلائیں"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"موقوف کریں"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"کوئی معلومات دستیاب نہیں"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"کاسٹ کرنے کا بٹن"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"کاسٹ کرنا بند کریں"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"بند کریں"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"چلائیں"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"موقوف کریں"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"پھیلائیں"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"سکیڑیں"</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>
</resources>
diff --git a/v7/mediarouter/res/values-uz-rUZ/strings.xml b/v7/mediarouter/res/values-uz-rUZ/strings.xml
index e39a3a8..c13b06b 100644
--- a/v7/mediarouter/res/values-uz-rUZ/strings.xml
+++ b/v7/mediarouter/res/values-uz-rUZ/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Tizim"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Qurilmalar"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Translatsiya qilish"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Qurilmaga ulanish"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Qurilmalar izlanmoqda…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Uzish"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Translatsiyani to‘xtatish"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Yo‘naltirish sozlamalari"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ijro qilish"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"To‘xtatib turish"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Hech qanday ma’lumot yo‘q"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Translatsiya tugmasi"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Translatsiyani to‘xtatish"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Yopish"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Boshlash"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"To‘xtatib turish"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/res/values-vi/strings.xml
index b2c8abd..3301cee 100644
--- a/v7/mediarouter/res/values-vi/strings.xml
+++ b/v7/mediarouter/res/values-vi/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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_media_route_button_content_description" msgid="8327680881775995150">"Truyền"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Kết nối với thiết bị"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Đang tìm kiếm thiết bị…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ngắt kết nối"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ngừng truyền"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Cài đặt tuyến đường"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Phát"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Tạm dừng"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Không có thông tin nào"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Nút truyền"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Dừng truyền"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Đóng"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Phát"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Tạm dừng"</string>
+ <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_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>
</resources>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
index c58162f..cdd66f53 100644
--- a/v7/mediarouter/res/values-zh-rCN/strings.xml
+++ b/v7/mediarouter/res/values-zh-rCN/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"系统"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"设备"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投射"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"连接到设备"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜索设备…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"断开连接"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投射"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由设置"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暂停"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"没有任何相关信息"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"投射按钮"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"停止投射"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"关闭"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"播放"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"暂停"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"展开"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折叠"</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>
</resources>
diff --git a/v7/mediarouter/res/values-zh-rHK/strings.xml b/v7/mediarouter/res/values-zh-rHK/strings.xml
index 2c9f671..873e5ce 100644
--- a/v7/mediarouter/res/values-zh-rHK/strings.xml
+++ b/v7/mediarouter/res/values-zh-rHK/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投放"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"連線至裝置"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜尋裝置…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"中斷連線"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投放"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由設定"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暫停"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"沒有詳細資料"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"停止投放"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"關閉"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"播放"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"暫停"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</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>
</resources>
diff --git a/v7/mediarouter/res/values-zh-rTW/strings.xml b/v7/mediarouter/res/values-zh-rTW/strings.xml
index 13dfd11..27755e7 100644
--- a/v7/mediarouter/res/values-zh-rTW/strings.xml
+++ b/v7/mediarouter/res/values-zh-rTW/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投放"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"連線至裝置"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜尋裝置..."</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"中斷連線"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投放"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由設定"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暫停"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"沒有可用的資訊"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"停止投放"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"關閉"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"播放"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"暫停"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</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>
</resources>
diff --git a/v7/mediarouter/res/values-zu/strings.xml b/v7/mediarouter/res/values-zu/strings.xml
index ec9a68a..f513fd4 100644
--- a/v7/mediarouter/res/values-zu/strings.xml
+++ b/v7/mediarouter/res/values-zu/strings.xml
@@ -18,13 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Isistimu"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Amadivayisi"</string>
- <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Abalingisi"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Xhumeka kudivayisi"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Iseshela amadivayisi…"</string>
- <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Nqamula"</string>
- <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Misa ukusakaza"</string>
- <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Izilungiselelo zomzila"</string>
- <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Dlala"</string>
- <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Misa isikhashana"</string>
- <string name="mr_media_route_controller_no_info_available" msgid="3641544772007543920">"Alukho ulwazi olutholakalayo"</string>
+ <string name="mr_button_content_description" msgid="3698378085901466129">"Inkinobho ye-Cast"</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>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Misa ukusakaza"</string>
+ <string name="mr_controller_close_description" msgid="7333862312480583260">"Vala"</string>
+ <string name="mr_controller_play" msgid="683634565969987458">"Dlala"</string>
+ <string name="mr_controller_pause" msgid="5451884435510905406">"Misa isikhashana"</string>
+ <string name="mr_controller_expand_group" msgid="8062427022744266907">"Nweba"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Goqa"</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>
</resources>
diff --git a/v7/mediarouter/res/values/attrs.xml b/v7/mediarouter/res/values/attrs.xml
index 9f5f8ac..81073dc 100644
--- a/v7/mediarouter/res/values/attrs.xml
+++ b/v7/mediarouter/res/values/attrs.xml
@@ -26,12 +26,26 @@
<attr name="android:minHeight" />
</declare-styleable>
+ <attr name="MediaRouteControllerWindowBackground" format="reference" />
<attr name="mediaRouteButtonStyle" format="reference" />
<attr name="mediaRouteOffDrawable" format="reference" />
<attr name="mediaRouteConnectingDrawable" format="reference" />
<attr name="mediaRouteOnDrawable" format="reference" />
- <attr name="mediaRouteSettingsDrawable" format="reference" />
+ <attr name="mediaRouteCloseDrawable" format="reference" />
<attr name="mediaRoutePlayDrawable" format="reference" />
<attr name="mediaRoutePauseDrawable" format="reference" />
<attr name="mediaRouteCastDrawable" format="reference" />
-</resources>
\ No newline at end of file
+ <attr name="mediaRouteAudioTrackDrawable" format="reference" />
+ <attr name="mediaRouteDefaultIconDrawable" format="reference" />
+ <attr name="mediaRouteBluetoothIconDrawable" format="reference" />
+ <attr name="mediaRouteTvIconDrawable" format="reference" />
+ <attr name="mediaRouteSpeakerIconDrawable" format="reference" />
+ <attr name="mediaRouteSpeakerGroupIconDrawable" format="reference" />
+ <attr name="mediaRouteChooserPrimaryTextStyle" format="reference" />
+ <attr name="mediaRouteChooserSecondaryTextStyle" format="reference" />
+ <attr name="mediaRouteControllerTitleTextStyle" format="reference" />
+ <attr name="mediaRouteControllerPrimaryTextStyle" format="reference" />
+ <attr name="mediaRouteControllerSecondaryTextStyle" format="reference" />
+ <attr name="mediaRouteExpandGroupDrawable" format="reference" />
+ <attr name="mediaRouteCollapseGroupDrawable" format="reference" />
+</resources>
diff --git a/v7/mediarouter/res/values/dimens.xml b/v7/mediarouter/res/values/dimens.xml
index e687c82..10e5751 100644
--- a/v7/mediarouter/res/values/dimens.xml
+++ b/v7/mediarouter/res/values/dimens.xml
@@ -15,5 +15,25 @@
-->
<resources>
- <dimen name="mr_media_route_controller_art_max_height">320dp</dimen>
-</resources>
\ No newline at end of file
+ <!-- Dialog size -->
+ <eat-comment />
+ <!-- The platform's desired fixed width for a dialog along the major axis
+ (the screen is in landscape). This may be either a fraction or a dimension.-->
+ <dimen name="mr_dialog_fixed_width_major">320dp</dimen>
+ <!-- The platform's desired fixed width for a dialog along the minor axis
+ (the screen is in portrait). This may be either a fraction or a dimension.-->
+ <dimen name="mr_dialog_fixed_width_minor">320dp</dimen>
+
+ <!-- MediaRouteController's volume group list -->
+ <eat-comment />
+ <!-- Maximum height of volume group list. -->
+ <dimen name="mr_controller_volume_group_list_max_height">288dp</dimen>
+ <!-- Height of volume group item. -->
+ <dimen name="mr_controller_volume_group_list_item_height">68dp</dimen>
+ <!-- Size of an item's icon. -->
+ <dimen name="mr_controller_volume_group_list_item_icon_size">24dp</dimen>
+
+ <dimen name="mr_controller_volume_group_list_padding_top">16dp</dimen>
+ <!-- Group list expand/collapse animation duration. -->
+ <integer name="mr_controller_volume_group_list_animation_duration_ms">200</integer>
+</resources>
diff --git a/v7/mediarouter/res/values/strings.xml b/v7/mediarouter/res/values/strings.xml
index a87ce4f..fad0408 100644
--- a/v7/mediarouter/res/values/strings.xml
+++ b/v7/mediarouter/res/values/strings.xml
@@ -23,29 +23,41 @@
<!-- Content description of a MediaRouteButton for accessibility support.
Cast is the standard android verb for sending content to a remote device. [CHAR LIMIT=50] -->
- <string name="mr_media_route_button_content_description">Cast</string>
+ <string name="mr_button_content_description">Cast button</string>
<!-- Title of the media route chooser dialog. [CHAR LIMIT=30] -->
- <string name="mr_media_route_chooser_title">Connect to device</string>
+ <string name="mr_chooser_title">Cast to</string>
<!-- Placeholder text to show when no devices have been found. [CHAR LIMIT=50] -->
- <string name="mr_media_route_chooser_searching">Searching for devices\u2026</string>
+ <string name="mr_chooser_searching">Finding devices</string>
<!-- Button to disconnect from a media route. [CHAR LIMIT=30] -->
- <string name="mr_media_route_controller_disconnect">Disconnect</string>
+ <string name="mr_controller_disconnect">Disconnect</string>
- <!-- Button to stop playback and disconnect from a media route. [CHAR LIMIT=30] -->
- <string name="mr_media_route_controller_stop">Stop casting</string>
+ <!-- Button to stop playback and disconnect from a media route. [CHAR LIMIT=30] -->
+ <string name="mr_controller_stop">Stop casting</string>
- <!-- Description for a button that takes you to settings for the active route -->
- <string name="mr_media_route_controller_settings_description">Route settings</string>
+ <!-- Content description for accessibility (not shown on the screen): dialog close button. [CHAR LIMIT=NONE] -->
+ <string name="mr_controller_close_description">Close</string>
- <!-- Accessibility description for the play button -->
- <string name="mr_media_route_controller_play">Play</string>
+ <!-- Content description for accessibility (not shown on the screen): media play button. [CHAR LIMIT=NONE] -->
+ <string name="mr_controller_play">Play</string>
- <!-- Accessibility description for the pause button -->
- <string name="mr_media_route_controller_pause">Pause</string>
+ <!-- Content description for accessibility (not shown on the screen): media pause button. [CHAR LIMIT=NONE] -->
+ <string name="mr_controller_pause">Pause</string>
+
+ <!-- Content description for accessibility (not shown on the screen): group expand button. Pressing button shows group members of a selected route group. [CHAR LIMIT=NONE] -->
+ <string name="mr_controller_expand_group">Expand</string>
+
+ <!-- Content description for accessibility (not shown on the screen): group collapse button. Pressing button hides group members of a selected route group. [CHAR LIMIT=NONE] -->
+ <string name="mr_controller_collapse_group">Collapse</string>
+
+ <!-- Placeholder text to show when no media have been selected for playback. [CHAR LIMIT=50] -->
+ <string name="mr_controller_no_media_selected">No media selected</string>
<!-- Placeholder text to show when no title/description have been found for a given song/video. [CHAR LIMIT=50] -->
- <string name="mr_media_route_controller_no_info_available">No info available</string>
+ <string name="mr_controller_no_info_available">No info available</string>
+
+ <!-- Placeholder text indicating that the user is currently casting screen. [CHAR LIMIT=50] -->
+ <string name="mr_controller_casting_screen">Casting screen</string>
</resources>
diff --git a/v7/mediarouter/res/values/styles.xml b/v7/mediarouter/res/values/styles.xml
index 9be8545..18f954d 100644
--- a/v7/mediarouter/res/values/styles.xml
+++ b/v7/mediarouter/res/values/styles.xml
@@ -17,21 +17,83 @@
<resources>
<style name="Widget.MediaRouter.MediaRouteButton"
parent="Widget.AppCompat.ActionButton">
- <item name="android:minWidth">56dp</item>
- <item name="android:minHeight">48dp</item>
- <item name="android:padding">0dp</item>
- <item name="android:focusable">true</item>
- <item name="android:contentDescription">@string/mr_media_route_button_content_description</item>
+ <item name="android:contentDescription">@string/mr_button_content_description</item>
<item name="externalRouteEnabledDrawable">@drawable/mr_ic_media_route_mono_dark</item>
</style>
<style name="Widget.MediaRouter.Light.MediaRouteButton"
parent="Widget.AppCompat.Light.ActionButton">
- <item name="android:minWidth">56dp</item>
- <item name="android:minHeight">48dp</item>
- <item name="android:padding">0dp</item>
- <item name="android:focusable">true</item>
- <item name="android:contentDescription">@string/mr_media_route_button_content_description</item>
+ <item name="android:contentDescription">@string/mr_button_content_description</item>
<item name="externalRouteEnabledDrawable">@drawable/mr_ic_media_route_mono_light</item>
</style>
-</resources>
\ No newline at end of file
+
+ <!-- MediaRouteChooserDialog text styles -->
+ <style name="Widget.MediaRouter.ChooserText" parent="">
+ <item name="android:fontFamily">sans-serif</item>
+ <item name="android:textStyle">normal</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ChooserText.Primary">
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ChooserText.Secondary">
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ChooserText.Primary.Dark">
+ <item name="android:textColor">#FFFFFFFF</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ChooserText.Primary.Light">
+ <item name="android:textColor">#DE000000</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ChooserText.Secondary.Dark">
+ <item name="android:textColor">#8AFFFFFF</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ChooserText.Secondary.Light">
+ <item name="android:textColor">#8A000000</item>
+ </style>
+
+ <!-- MediaRouteControllerDialog text styles -->
+ <style name="Widget.MediaRouter.ControllerText" parent="Widget.MediaRouter.ChooserText" />
+
+ <style name="Widget.MediaRouter.ControllerText.Title">
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:textSize">20sp</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ControllerText.Primary">
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ControllerText.Secondary">
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ControllerText.Title.Dark">
+ <item name="android:textColor">#FFFFFFFF</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ControllerText.Title.Light">
+ <item name="android:textColor">#DE000000</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ControllerText.Primary.Dark">
+ <item name="android:textColor">#FFFFFFFF</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ControllerText.Primary.Light">
+ <item name="android:textColor">#DE000000</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ControllerText.Secondary.Dark">
+ <item name="android:textColor">#FFFFFFFF</item>
+ </style>
+
+ <style name="Widget.MediaRouter.ControllerText.Secondary.Light">
+ <item name="android:textColor">#DE000000</item>
+ </style>
+</resources>
diff --git a/v7/mediarouter/res/values/themes.xml b/v7/mediarouter/res/values/themes.xml
index 85d0a8b..95aac1c 100644
--- a/v7/mediarouter/res/values/themes.xml
+++ b/v7/mediarouter/res/values/themes.xml
@@ -17,27 +17,70 @@
<resources>
<style name="Theme.MediaRouter" parent="">
+ <item name="android:windowNoTitle">false</item>
<item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.MediaRouteButton</item>
+ <item name="MediaRouteControllerWindowBackground">@drawable/mr_dialog_material_background_dark</item>
<item name="mediaRouteOffDrawable">@drawable/ic_media_route_off_mono_dark</item>
<item name="mediaRouteConnectingDrawable">@drawable/mr_ic_media_route_connecting_mono_dark</item>
<item name="mediaRouteOnDrawable">@drawable/ic_media_route_on_mono_dark</item>
- <item name="mediaRouteSettingsDrawable">@drawable/mr_ic_settings_dark</item>
+ <item name="mediaRouteCloseDrawable">@drawable/mr_ic_close_dark</item>
<item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_dark</item>
<item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_dark</item>
<item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_dark</item>
+ <item name="mediaRouteAudioTrackDrawable">@drawable/ic_audiotrack</item>
+ <item name="mediaRouteDefaultIconDrawable">@drawable/ic_cast_white</item>
+ <item name="mediaRouteBluetoothIconDrawable">@drawable/ic_bluetooth_white</item>
+ <item name="mediaRouteTvIconDrawable">@drawable/ic_tv_dark</item>
+ <item name="mediaRouteSpeakerIconDrawable">@drawable/ic_speaker_dark</item>
+ <item name="mediaRouteSpeakerGroupIconDrawable">@drawable/ic_speaker_group_dark</item>
+ <item name="mediaRouteChooserPrimaryTextStyle">@style/Widget.MediaRouter.ChooserText.Primary.Dark</item>
+ <item name="mediaRouteChooserSecondaryTextStyle">@style/Widget.MediaRouter.ChooserText.Secondary.Dark</item>
+ <item name="mediaRouteControllerTitleTextStyle">@style/Widget.MediaRouter.ControllerText.Title.Dark</item>
+ <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Dark</item>
+ <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Dark</item>
</style>
- <style name="Theme.MediaRouter.Light" parent="">
- <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.Light.MediaRouteButton</item>
-
- <item name="mediaRouteOffDrawable">@drawable/ic_cast_off_light</item>
- <item name="mediaRouteConnectingDrawable">@drawable/mr_ic_media_route_connecting_mono_light</item>
- <item name="mediaRouteOnDrawable">@drawable/ic_cast_on_light</item>
- <item name="mediaRouteSettingsDrawable">@drawable/mr_ic_settings_light</item>
+ <style name="Theme.MediaRouter.LightControlPanel">
<item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_light</item>
<item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_light</item>
<item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_light</item>
+ <item name="mediaRouteAudioTrackDrawable">@drawable/mr_ic_audiotrack_light</item>
+ <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Light</item>
+ <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Light</item>
+ </style>
+
+ <style name="Theme.MediaRouter.Light">
+ <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.Light.MediaRouteButton</item>
+
+ <item name="MediaRouteControllerWindowBackground">@drawable/mr_dialog_material_background_light</item>
+ <item name="mediaRouteOffDrawable">@drawable/ic_cast_off_light</item>
+ <item name="mediaRouteConnectingDrawable">@drawable/mr_ic_media_route_connecting_mono_light</item>
+ <item name="mediaRouteOnDrawable">@drawable/ic_cast_on_light</item>
+ <item name="mediaRouteCloseDrawable">@drawable/mr_ic_close_light</item>
+ <item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_light</item>
+ <item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_light</item>
+ <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_light</item>
+ <item name="mediaRouteAudioTrackDrawable">@drawable/mr_ic_audiotrack_light</item>
+ <item name="mediaRouteDefaultIconDrawable">@drawable/ic_cast_grey</item>
+ <item name="mediaRouteBluetoothIconDrawable">@drawable/ic_bluetooth_grey</item>
+ <item name="mediaRouteTvIconDrawable">@drawable/ic_tv_light</item>
+ <item name="mediaRouteSpeakerIconDrawable">@drawable/ic_speaker_light</item>
+ <item name="mediaRouteSpeakerGroupIconDrawable">@drawable/ic_speaker_group_light</item>
+ <item name="mediaRouteChooserPrimaryTextStyle">@style/Widget.MediaRouter.ChooserText.Primary.Light</item>
+ <item name="mediaRouteChooserSecondaryTextStyle">@style/Widget.MediaRouter.ChooserText.Secondary.Light</item>
+ <item name="mediaRouteControllerTitleTextStyle">@style/Widget.MediaRouter.ControllerText.Title.Light</item>
+ <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Light</item>
+ <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Light</item>
+ </style>
+
+ <style name="Theme.MediaRouter.Light.DarkControlPanel">
+ <item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_dark</item>
+ <item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_dark</item>
+ <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_dark</item>
+ <item name="mediaRouteAudioTrackDrawable">@drawable/ic_audiotrack</item>
+ <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Dark</item>
+ <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Dark</item>
</style>
</resources>
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
index 379ba80..c44e8d2 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
@@ -120,7 +120,8 @@
}
public MediaRouteButton(Context context, AttributeSet attrs, int defStyleAttr) {
- super(MediaRouterThemeHelper.createThemedContext(context), attrs, defStyleAttr);
+ super(MediaRouterThemeHelper.createThemedContext(context, defStyleAttr), attrs,
+ defStyleAttr);
context = getContext();
mRouter = MediaRouter.getInstance(context);
@@ -431,40 +432,40 @@
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- final int minWidth = Math.max(mMinWidth,
- mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicWidth() : 0);
- final int minHeight = Math.max(mMinHeight,
- mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicHeight() : 0);
+ final int width = Math.max(mMinWidth, mRemoteIndicator != null ?
+ mRemoteIndicator.getIntrinsicWidth() + getPaddingLeft() + getPaddingRight() : 0);
+ final int height = Math.max(mMinHeight, mRemoteIndicator != null ?
+ mRemoteIndicator.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom() : 0);
- int width;
+ int measuredWidth;
switch (widthMode) {
case MeasureSpec.EXACTLY:
- width = widthSize;
+ measuredWidth = widthSize;
break;
case MeasureSpec.AT_MOST:
- width = Math.min(widthSize, minWidth + getPaddingLeft() + getPaddingRight());
+ measuredWidth = Math.min(widthSize, width);
break;
default:
case MeasureSpec.UNSPECIFIED:
- width = minWidth + getPaddingLeft() + getPaddingRight();
+ measuredWidth = width;
break;
}
- int height;
+ int measuredHeight;
switch (heightMode) {
case MeasureSpec.EXACTLY:
- height = heightSize;
+ measuredHeight = heightSize;
break;
case MeasureSpec.AT_MOST:
- height = Math.min(heightSize, minHeight + getPaddingTop() + getPaddingBottom());
+ measuredHeight = Math.min(heightSize, height);
break;
default:
case MeasureSpec.UNSPECIFIED:
- height = minHeight + getPaddingTop() + getPaddingBottom();
+ measuredHeight = height;
break;
}
- setMeasuredDimension(width, height);
+ setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
index 779ae8b..5856f38 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
@@ -16,26 +16,40 @@
package android.support.v7.app;
+import static android.support.v7.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTED;
+import static android.support.v7.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTING;
+
import android.app.Dialog;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Bundle;
+import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
-import android.support.v7.media.MediaRouter;
import android.support.v7.media.MediaRouteSelector;
+import android.support.v7.media.MediaRouter;
import android.support.v7.mediarouter.R;
import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
/**
@@ -48,6 +62,8 @@
* @see MediaRouteActionProvider
*/
public class MediaRouteChooserDialog extends Dialog {
+ private static final String TAG = "MediaRouteChooserDialog";
+
private final MediaRouter mRouter;
private final MediaRouterCallback mCallback;
@@ -62,7 +78,7 @@
}
public MediaRouteChooserDialog(Context context, int theme) {
- super(MediaRouterThemeHelper.createThemedContext(context), theme);
+ super(MediaRouterThemeHelper.createThemedContext(context, theme), theme);
context = getContext();
mRouter = MediaRouter.getInstance(context);
@@ -138,22 +154,25 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
+ setContentView(R.layout.mr_chooser_dialog);
+ setTitle(R.string.mr_chooser_title);
- setContentView(R.layout.mr_media_route_chooser_dialog);
- setTitle(R.string.mr_media_route_chooser_title);
-
- // Must be called after setContentView.
- getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
- MediaRouterThemeHelper.getThemeResource(
- getContext(), R.attr.mediaRouteOffDrawable));
-
- mRoutes = new ArrayList<MediaRouter.RouteInfo>();
+ mRoutes = new ArrayList<>();
mAdapter = new RouteAdapter(getContext(), mRoutes);
- mListView = (ListView)findViewById(R.id.media_route_list);
+ mListView = (ListView)findViewById(R.id.mr_chooser_list);
mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(mAdapter);
mListView.setEmptyView(findViewById(android.R.id.empty));
+
+ updateLayout();
+ }
+
+ /**
+ * Sets the width of the dialog. Also called when configuration changes.
+ */
+ void updateLayout() {
+ getWindow().setLayout(MediaRouteDialogHelper.getDialogWidth(getContext()),
+ ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
@@ -181,6 +200,7 @@
mRoutes.clear();
mRoutes.addAll(mRouter.getRoutes());
onFilterRoutes(mRoutes);
+ RouteComparator.loadRouteUsageScores(getContext(), mRoutes);
Collections.sort(mRoutes, RouteComparator.sInstance);
mAdapter.notifyDataSetChanged();
}
@@ -189,10 +209,27 @@
private final class RouteAdapter extends ArrayAdapter<MediaRouter.RouteInfo>
implements ListView.OnItemClickListener {
private final LayoutInflater mInflater;
+ private final Drawable mDefaultIcon;
+ private final Drawable mBluetoothIcon;
+ private final Drawable mTvIcon;
+ private final Drawable mSpeakerIcon;
+ private final Drawable mSpeakerGroupIcon;
public RouteAdapter(Context context, List<MediaRouter.RouteInfo> routes) {
super(context, 0, routes);
mInflater = LayoutInflater.from(context);
+ TypedArray styledAttributes = getContext().obtainStyledAttributes(new int[] {
+ R.attr.mediaRouteDefaultIconDrawable,
+ R.attr.mediaRouteBluetoothIconDrawable,
+ R.attr.mediaRouteTvIconDrawable,
+ R.attr.mediaRouteSpeakerIconDrawable,
+ R.attr.mediaRouteSpeakerGroupIconDrawable});
+ mDefaultIcon = styledAttributes.getDrawable(0);
+ mBluetoothIcon = styledAttributes.getDrawable(1);
+ mTvIcon = styledAttributes.getDrawable(2);
+ mSpeakerIcon = styledAttributes.getDrawable(3);
+ mSpeakerGroupIcon = styledAttributes.getDrawable(4);
+ styledAttributes.recycle();
}
@Override
@@ -209,21 +246,32 @@
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
- view = mInflater.inflate(R.layout.mr_media_route_list_item, parent, false);
+ view = mInflater.inflate(R.layout.mr_chooser_list_item, parent, false);
}
+
MediaRouter.RouteInfo route = getItem(position);
- TextView text1 = (TextView)view.findViewById(android.R.id.text1);
- TextView text2 = (TextView)view.findViewById(android.R.id.text2);
+ TextView text1 = (TextView) view.findViewById(R.id.mr_chooser_route_name);
+ TextView text2 = (TextView) view.findViewById(R.id.mr_chooser_route_desc);
text1.setText(route.getName());
String description = route.getDescription();
- if (TextUtils.isEmpty(description)) {
- text2.setVisibility(View.GONE);
- text2.setText("");
- } else {
+ boolean isConnectedOrConnecting =
+ route.getConnectionState() == CONNECTION_STATE_CONNECTED
+ || route.getConnectionState() == CONNECTION_STATE_CONNECTING;
+ if (isConnectedOrConnecting && !TextUtils.isEmpty(description)) {
+ text1.setGravity(Gravity.BOTTOM);
text2.setVisibility(View.VISIBLE);
text2.setText(description);
+ } else {
+ text1.setGravity(Gravity.CENTER_VERTICAL);
+ text2.setVisibility(View.GONE);
+ text2.setText("");
}
view.setEnabled(route.isEnabled());
+
+ ImageView iconView = (ImageView) view.findViewById(R.id.mr_chooser_route_icon);
+ if (iconView != null) {
+ iconView.setImageDrawable(getIconDrawable(route));
+ }
return view;
}
@@ -232,9 +280,49 @@
MediaRouter.RouteInfo route = getItem(position);
if (route.isEnabled()) {
route.select();
+ RouteComparator.storeRouteUsageScores(getContext(), route.getId());
dismiss();
}
}
+
+ private Drawable getIconDrawable(MediaRouter.RouteInfo route) {
+ Uri iconUri = route.getIconUri();
+ if (iconUri != null) {
+ try {
+ InputStream is = getContext().getContentResolver().openInputStream(iconUri);
+ Drawable drawable = Drawable.createFromStream(is, null);
+ if (drawable != null) {
+ return drawable;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to load " + iconUri, e);
+ // Falls back.
+ }
+ }
+ return getDefaultIconDrawable(route);
+ }
+
+ private Drawable getDefaultIconDrawable(MediaRouter.RouteInfo route) {
+ // If the type of the receiver device is specified, use it.
+ switch (route.getDeviceType()) {
+ case MediaRouter.RouteInfo.DEVICE_TYPE_BLUETOOTH:
+ return mBluetoothIcon;
+ case MediaRouter.RouteInfo.DEVICE_TYPE_TV:
+ return mTvIcon;
+ case MediaRouter.RouteInfo.DEVICE_TYPE_SPEAKER:
+ return mSpeakerIcon;
+ }
+
+ // Otherwise, make the best guess based on other route information.
+ if (route instanceof MediaRouter.RouteGroup) {
+ // Only speakers can be grouped for now.
+ return mSpeakerGroupIcon;
+ }
+ if (route.isDeviceTypeBluetooth()) {
+ return mBluetoothIcon;
+ }
+ return mDefaultIcon;
+ }
}
private final class MediaRouterCallback extends MediaRouter.Callback {
@@ -260,11 +348,87 @@
}
private static final class RouteComparator implements Comparator<MediaRouter.RouteInfo> {
+ private static final String PREF_ROUTE_IDS =
+ "android.support.v7.app.MediaRouteChooserDialog_route_ids";
+ private static final String PREF_USAGE_SCORE_PREFIX =
+ "android.support.v7.app.MediaRouteChooserDialog_route_usage_score_";
+ // Routes with the usage score less than MIN_USAGE_SCORE are decayed.
+ private static final float MIN_USAGE_SCORE = 0.1f;
+ private static final float USAGE_SCORE_DECAY_FACTOR = 0.95f;
+
public static final RouteComparator sInstance = new RouteComparator();
+ public static final HashMap<String, Float> sRouteUsageScoreMap = new HashMap();
@Override
public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) {
+ if (lhs == null) {
+ return rhs == null ? 0 : -1;
+ } else if (rhs == null) {
+ return 1;
+ }
+ if (lhs.isDeviceTypeBluetooth()) {
+ if (!rhs.isDeviceTypeBluetooth()) {
+ return 1;
+ }
+ } else if (rhs.isDeviceTypeBluetooth()) {
+ return -1;
+ }
+ Float lhsUsageScore = sRouteUsageScoreMap.get(lhs.getId());
+ if (lhsUsageScore == null) {
+ lhsUsageScore = 0f;
+ }
+ Float rhsUsageScore = sRouteUsageScoreMap.get(rhs.getId());
+ if (rhsUsageScore == null) {
+ rhsUsageScore = 0f;
+ }
+ if (!lhsUsageScore.equals(rhsUsageScore)) {
+ return lhsUsageScore > rhsUsageScore ? -1 : 1;
+ }
return lhs.getName().compareTo(rhs.getName());
}
+
+ private static void loadRouteUsageScores(
+ Context context, List<MediaRouter.RouteInfo> routes) {
+ sRouteUsageScoreMap.clear();
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+ for (MediaRouter.RouteInfo route : routes) {
+ sRouteUsageScoreMap.put(route.getId(),
+ preferences.getFloat(PREF_USAGE_SCORE_PREFIX + route.getId(), 0f));
+ }
+ }
+
+ private static void storeRouteUsageScores(Context context, String selectedRouteId) {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor prefEditor = preferences.edit();
+ List<String> routeIds = new ArrayList<String>(
+ Arrays.asList(preferences.getString(PREF_ROUTE_IDS, "").split(",")));
+ if (!routeIds.contains(selectedRouteId)) {
+ routeIds.add(selectedRouteId);
+ }
+ StringBuilder routeIdsBuilder = new StringBuilder();
+ for (String routeId : routeIds) {
+ // The new route usage score is calculated as follows:
+ // 1) usageScore * USAGE_SCORE_DECAY_FACTOR + 1, if the route is selected,
+ // 2) 0, if usageScore * USAGE_SCORE_DECAY_FACTOR < MIN_USAGE_SCORE, or
+ // 3) usageScore * USAGE_SCORE_DECAY_FACTOR, otherwise,
+ String routeUsageScoreKey = PREF_USAGE_SCORE_PREFIX + routeId;
+ float newUsageScore = preferences.getFloat(routeUsageScoreKey, 0f)
+ * USAGE_SCORE_DECAY_FACTOR;
+ if (selectedRouteId.equals(routeId)) {
+ newUsageScore += 1f;
+ }
+ if (newUsageScore < MIN_USAGE_SCORE) {
+ prefEditor.remove(routeId);
+ } else {
+ prefEditor.putFloat(routeUsageScoreKey, newUsageScore);
+ if (routeIdsBuilder.length() > 0) {
+ routeIdsBuilder.append(',');
+ }
+ routeIdsBuilder.append(routeId);
+ }
+ }
+ prefEditor.putString(PREF_ROUTE_IDS, routeIdsBuilder.toString());
+ prefEditor.commit();
+ }
}
}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java
index 3b5239a..835b613 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java
@@ -18,6 +18,7 @@
import android.app.Dialog;
import android.content.Context;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v7.media.MediaRouteSelector;
@@ -32,6 +33,7 @@
public class MediaRouteChooserDialogFragment extends DialogFragment {
private final String ARGUMENT_SELECTOR = "selector";
+ private MediaRouteChooserDialog mDialog;
private MediaRouteSelector mSelector;
/**
@@ -108,8 +110,16 @@
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- MediaRouteChooserDialog dialog = onCreateChooserDialog(getActivity(), savedInstanceState);
- dialog.setRouteSelector(getRouteSelector());
- return dialog;
+ mDialog = onCreateChooserDialog(getActivity(), savedInstanceState);
+ mDialog.setRouteSelector(getRouteSelector());
+ return mDialog;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mDialog != null) {
+ mDialog.updateLayout();
+ }
}
}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
index f98e6b2..1f375a0 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
@@ -16,9 +16,16 @@
package android.support.v7.app;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
import android.content.Context;
-import android.content.IntentSender;
-import android.graphics.drawable.Drawable;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.v4.media.MediaDescriptionCompat;
@@ -26,21 +33,40 @@
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
+import android.support.v4.view.accessibility.AccessibilityEventCompat;
+import android.support.v7.graphics.Palette;
import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;
import android.support.v7.mediarouter.R;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* This class implements the route controller dialog for {@link MediaRouter}.
* <p>
@@ -56,53 +82,87 @@
// Time to wait before updating the volume when the user lets go of the seek bar
// to allow the route provider time to propagate the change and publish a new
// route descriptor.
- private static final int VOLUME_UPDATE_DELAY_MILLIS = 250;
+ private static final int VOLUME_UPDATE_DELAY_MILLIS = 500;
+
+ private static final int BUTTON_NEUTRAL_RES_ID = android.R.id.button3;
+ private static final int BUTTON_DISCONNECT_RES_ID = android.R.id.button2;
+ private static final int BUTTON_STOP_RES_ID = android.R.id.button1;
private final MediaRouter mRouter;
private final MediaRouterCallback mCallback;
private final MediaRouter.RouteInfo mRoute;
+ private Context mContext;
private boolean mCreated;
private boolean mAttachedToWindow;
- private Drawable mMediaRouteConnectingDrawable;
- private Drawable mMediaRouteOnDrawable;
- private View mControlView;
+ private int mDialogContentWidth;
+
+ private View mCustomControlView;
private Button mDisconnectButton;
private Button mStopCastingButton;
private ImageButton mPlayPauseButton;
- private ImageButton mSettingsButton;
+ private ImageButton mCloseButton;
+ private MediaRouteExpandCollapseButton mGroupExpandCollapseButton;
+ private FrameLayout mExpandableAreaLayout;
+ private LinearLayout mDialogAreaLayout;
+ private FrameLayout mDefaultControlLayout;
+ private FrameLayout mCustomControlLayout;
private ImageView mArtView;
private TextView mTitleView;
private TextView mSubtitleView;
- private TextView mRouteNameView;
+ private TextView mRouteNameTextView;
private boolean mVolumeControlEnabled = true;
- private LinearLayout mVolumeLayout;
+ // Layout for media controllers including play/pause button and the main volume slider.
+ private LinearLayout mMediaMainControlLayout;
+ private RelativeLayout mPlaybackControlLayout;
+ private LinearLayout mVolumeControlLayout;
+ private View mDividerView;
+
+ private ListView mVolumeGroupList;
private SeekBar mVolumeSlider;
- private boolean mVolumeSliderTouched;
+ private VolumeChangeListener mVolumeChangeListener;
+ private MediaRouter.RouteInfo mRouteInVolumeSliderTouched;
+ private int mVolumeGroupListItemIconSize;
+ private int mVolumeGroupListItemHeight;
+ private int mVolumeGroupListMaxHeight;
+ private final int mVolumeGroupListPaddingTop;
+ private Map<MediaRouter.RouteInfo, SeekBar> mVolumeSliderMap;
private MediaControllerCompat mMediaController;
private MediaControllerCallback mControllerCallback;
private PlaybackStateCompat mState;
private MediaDescriptionCompat mDescription;
+ private FetchArtTask mFetchArtTask;
+ private Bitmap mArtIconBitmap;
+ private Uri mArtIconUri;
+ private boolean mIsGroupExpanded;
+ private boolean mIsGroupListAnimationNeeded;
+ private int mGroupListAnimationDurationMs;
+
+ private final AccessibilityManager mAccessibilityManager;
public MediaRouteControllerDialog(Context context) {
this(context, 0);
}
public MediaRouteControllerDialog(Context context, int theme) {
- super(MediaRouterThemeHelper.createThemedContext(context), theme);
- context = getContext();
+ super(MediaRouterThemeHelper.createThemedContext(context, theme), theme);
+ mContext = getContext();
mControllerCallback = new MediaControllerCallback();
- mRouter = MediaRouter.getInstance(context);
+ mRouter = MediaRouter.getInstance(mContext);
mCallback = new MediaRouterCallback();
mRoute = mRouter.getSelectedRoute();
setMediaSession(mRouter.getMediaSessionToken());
+ mVolumeGroupListPaddingTop = mContext.getResources().getDimensionPixelSize(
+ R.dimen.mr_controller_volume_group_list_padding_top);
+ mAccessibilityManager =
+ (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
/**
@@ -112,10 +172,16 @@
return mRoute;
}
+ private MediaRouter.RouteGroup getGroup() {
+ if (mRoute instanceof MediaRouter.RouteGroup) {
+ return (MediaRouter.RouteGroup) mRoute;
+ }
+ return null;
+ }
+
/**
- * Provides the subclass an opportunity to create a view that will
- * be included within the body of the dialog to offer additional media controls
- * for the currently playing content.
+ * Provides the subclass an opportunity to create a view that will replace the default media
+ * controls for the currently playing content.
*
* @param savedInstanceState The dialog's saved instance state.
* @return The media control view, or null if none.
@@ -130,7 +196,7 @@
* @return The media control view, or null if none.
*/
public View getMediaControlView() {
- return mControlView;
+ return mCustomControlView;
}
/**
@@ -144,7 +210,7 @@
if (mVolumeControlEnabled != enable) {
mVolumeControlEnabled = enable;
if (mCreated) {
- updateVolume();
+ updateVolumeControlLayout();
}
}
}
@@ -176,7 +242,7 @@
return;
}
try {
- mMediaController = new MediaControllerCompat(getContext(), sessionToken);
+ mMediaController = new MediaControllerCompat(mContext, sessionToken);
} catch (RemoteException e) {
Log.e(TAG, "Error creating media controller in setMediaSession.", e);
}
@@ -191,9 +257,9 @@
}
/**
- * Gets the description being used by the default UI.
+ * Gets the session to use for metadata and transport controls.
*
- * @return The current description.
+ * @return The token for the session to use or null if none.
*/
public MediaSessionCompat.Token getMediaSession() {
return mMediaController == null ? null : mMediaController.getSessionToken();
@@ -203,73 +269,142 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.mr_media_route_controller_material_dialog_b);
+ getWindow().setBackgroundDrawableResource(android.R.color.transparent);
+ setContentView(R.layout.mr_controller_material_dialog_b);
+
+ // Remove the neutral button.
+ findViewById(BUTTON_NEUTRAL_RES_ID).setVisibility(View.GONE);
ClickListener listener = new ClickListener();
- mDisconnectButton = (Button) findViewById(R.id.disconnect);
- mDisconnectButton.setOnClickListener(listener);
-
- mStopCastingButton = (Button) findViewById(R.id.stop);
- mStopCastingButton.setOnClickListener(listener);
-
- mSettingsButton = (ImageButton) findViewById(R.id.settings);
- mSettingsButton.setOnClickListener(listener);
-
- mArtView = (ImageView) findViewById(R.id.art);
- mTitleView = (TextView) findViewById(R.id.title);
- mSubtitleView = (TextView) findViewById(R.id.subtitle);
- mPlayPauseButton = (ImageButton) findViewById(R.id.play_pause);
- mPlayPauseButton.setOnClickListener(listener);
- mRouteNameView = (TextView) findViewById(R.id.route_name);
- mVolumeLayout = (LinearLayout)findViewById(R.id.media_route_volume_layout);
- mVolumeSlider = (SeekBar)findViewById(R.id.media_route_volume_slider);
- mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- private final Runnable mStopTrackingTouch = new Runnable() {
- @Override
- public void run() {
- if (mVolumeSliderTouched) {
- mVolumeSliderTouched = false;
- updateVolume();
- }
- }
- };
-
+ mExpandableAreaLayout = (FrameLayout) findViewById(R.id.mr_expandable_area);
+ mExpandableAreaLayout.setOnClickListener(new View.OnClickListener() {
@Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- if (mVolumeSliderTouched) {
- mVolumeSlider.removeCallbacks(mStopTrackingTouch);
- } else {
- mVolumeSliderTouched = true;
- }
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- // Defer resetting mVolumeSliderTouched to allow the media route provider
- // a little time to settle into its new state and publish the final
- // volume update.
- mVolumeSlider.postDelayed(mStopTrackingTouch, VOLUME_UPDATE_DELAY_MILLIS);
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (fromUser) {
- mRoute.requestSetVolume(progress);
- }
+ public void onClick(View v) {
+ dismiss();
}
});
-
- mCreated = true;
- if (update()) {
- mControlView = onCreateMediaControlView(savedInstanceState);
- FrameLayout controlFrame =
- (FrameLayout)findViewById(R.id.media_route_control_frame);
- if (mControlView != null) {
- controlFrame.findViewById(R.id.default_control_frame).setVisibility(View.GONE);
- controlFrame.addView(mControlView);
+ mDialogAreaLayout = (LinearLayout) findViewById(R.id.mr_dialog_area);
+ mDialogAreaLayout.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Eat unhandled touch events.
}
+ });
+ int color = MediaRouterThemeHelper.getButtonTextColor(mContext);
+ mDisconnectButton = (Button) findViewById(BUTTON_DISCONNECT_RES_ID);
+ mDisconnectButton.setText(R.string.mr_controller_disconnect);
+ mDisconnectButton.setTextColor(color);
+ mDisconnectButton.setOnClickListener(listener);
+
+ mStopCastingButton = (Button) findViewById(BUTTON_STOP_RES_ID);
+ mStopCastingButton.setText(R.string.mr_controller_stop);
+ mStopCastingButton.setTextColor(color);
+ mStopCastingButton.setOnClickListener(listener);
+
+ mRouteNameTextView = (TextView) findViewById(R.id.mr_name);
+ mCloseButton = (ImageButton) findViewById(R.id.mr_close);
+ mCloseButton.setOnClickListener(listener);
+ mCustomControlLayout = (FrameLayout) findViewById(R.id.mr_custom_control);
+ mDefaultControlLayout = (FrameLayout) findViewById(R.id.mr_default_control);
+
+ // Start the session activity when a content item (album art, title or subtitle) is clicked.
+ View.OnClickListener onClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mMediaController != null) {
+ PendingIntent pi = mMediaController.getSessionActivity();
+ if (pi != null) {
+ try {
+ pi.send();
+ dismiss();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, pi + " was not sent, it had been canceled.");
+ }
+ }
+ }
+ }
+ };
+ mArtView = (ImageView) findViewById(R.id.mr_art);
+ mArtView.setOnClickListener(onClickListener);
+ findViewById(R.id.mr_control_title_container).setOnClickListener(onClickListener);
+
+ mMediaMainControlLayout = (LinearLayout) findViewById(R.id.mr_media_main_control);
+ mDividerView = findViewById(R.id.mr_control_divider);
+
+ mPlaybackControlLayout = (RelativeLayout) findViewById(R.id.mr_playback_control);
+ mTitleView = (TextView) findViewById(R.id.mr_control_title);
+ mSubtitleView = (TextView) findViewById(R.id.mr_control_subtitle);
+ mPlayPauseButton = (ImageButton) findViewById(R.id.mr_control_play_pause);
+ mPlayPauseButton.setOnClickListener(listener);
+
+ mVolumeControlLayout = (LinearLayout) findViewById(R.id.mr_volume_control);
+ mVolumeControlLayout.setVisibility(View.GONE);
+ mVolumeSlider = (SeekBar) findViewById(R.id.mr_volume_slider);
+ mVolumeSlider.setTag(mRoute);
+ mVolumeChangeListener = new VolumeChangeListener();
+ mVolumeSlider.setOnSeekBarChangeListener(mVolumeChangeListener);
+
+ mVolumeGroupList = (ListView) findViewById(R.id.mr_volume_group_list);
+ MediaRouterThemeHelper.setMediaControlsBackgroundColor(mContext,
+ mMediaMainControlLayout, mVolumeGroupList, getGroup() != null);
+ MediaRouterThemeHelper.setVolumeSliderColor(mContext,
+ (MediaRouteVolumeSlider) mVolumeSlider, mMediaMainControlLayout);
+ mVolumeSliderMap = new HashMap<>();
+ mVolumeSliderMap.put(mRoute, mVolumeSlider);
+
+ mGroupExpandCollapseButton =
+ (MediaRouteExpandCollapseButton) findViewById(R.id.mr_group_expand_collapse);
+ mGroupExpandCollapseButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mIsGroupExpanded = !mIsGroupExpanded;
+ if (mIsGroupExpanded) {
+ mVolumeGroupList.setVisibility(View.VISIBLE);
+ mVolumeGroupList.setAdapter(
+ new VolumeGroupAdapter(mContext, getGroup().getRoutes()));
+ } else {
+ // Request layout to update UI based on {@code mIsGroupExpanded}.
+ mDefaultControlLayout.requestLayout();
+ }
+ mIsGroupListAnimationNeeded = true;
+ updateLayoutHeight();
+ }
+ });
+ mGroupListAnimationDurationMs = mContext.getResources().getInteger(
+ R.integer.mr_controller_volume_group_list_animation_duration_ms);
+
+ mCustomControlView = onCreateMediaControlView(savedInstanceState);
+ if (mCustomControlView != null) {
+ mCustomControlLayout.addView(mCustomControlView);
+ mCustomControlLayout.setVisibility(View.VISIBLE);
}
+ mCreated = true;
+ updateLayout();
+ }
+
+ /**
+ * Sets the width of the dialog. Also called when configuration changes.
+ */
+ void updateLayout() {
+ int width = MediaRouteDialogHelper.getDialogWidth(mContext);
+ getWindow().setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ View decorView = getWindow().getDecorView();
+ mDialogContentWidth = width - decorView.getPaddingLeft() - decorView.getPaddingRight();
+
+ Resources res = mContext.getResources();
+ mVolumeGroupListItemIconSize = res.getDimensionPixelSize(
+ R.dimen.mr_controller_volume_group_list_item_icon_size);
+ mVolumeGroupListItemHeight = res.getDimensionPixelSize(
+ R.dimen.mr_controller_volume_group_list_item_height);
+ mVolumeGroupListMaxHeight = res.getDimensionPixelSize(
+ R.dimen.mr_controller_volume_group_list_max_height);
+
+ // Ensure the mArtView is updated.
+ mArtIconBitmap = null;
+ mArtIconUri = null;
+ update();
}
@Override
@@ -309,122 +444,331 @@
return super.onKeyUp(keyCode, event);
}
- private boolean update() {
+ private void update() {
if (!mRoute.isSelected() || mRoute.isDefault()) {
dismiss();
- return false;
+ return;
}
if (!mCreated) {
- return false;
+ return;
}
- updateVolume();
+ mRouteNameTextView.setText(mRoute.getName());
+ mDisconnectButton.setVisibility(mRoute.canDisconnect() ? View.VISIBLE : View.GONE);
- mRouteNameView.setText(mRoute.getName());
+ if (mCustomControlView == null) {
+ if (mFetchArtTask != null) {
+ mFetchArtTask.cancel(true);
+ }
+ mFetchArtTask = new FetchArtTask();
+ mFetchArtTask.execute();
+ }
+ updateVolumeControlLayout();
+ updatePlaybackControlLayout();
+ }
- if (mRoute.canDisconnect()) {
- mDisconnectButton.setVisibility(View.VISIBLE);
+ private boolean canShowPlaybackControlLayout() {
+ return mCustomControlView == null && (mDescription != null || mState != null);
+ }
+
+ /**
+ * Returns the height of main media controller which includes playback control and master
+ * volume control.
+ */
+ private int getMainControllerHeight(boolean showPlaybackControl) {
+ int height = 0;
+ if (showPlaybackControl || mVolumeControlLayout.getVisibility() == View.VISIBLE) {
+ height += mMediaMainControlLayout.getPaddingTop()
+ + mMediaMainControlLayout.getPaddingBottom();
+ if (showPlaybackControl) {
+ height += mPlaybackControlLayout.getMeasuredHeight();
+ }
+ if (mVolumeControlLayout.getVisibility() == View.VISIBLE) {
+ height += mVolumeControlLayout.getMeasuredHeight();
+ }
+ if (showPlaybackControl && mVolumeControlLayout.getVisibility() == View.VISIBLE) {
+ height += mDividerView.getMeasuredHeight();
+ }
+ }
+ return height;
+ }
+
+ private void updateMediaControlVisibility(boolean canShowPlaybackControlLayout) {
+ // TODO: Update the top and bottom padding of the control layout according to the display
+ // height.
+ mDividerView.setVisibility((mVolumeControlLayout.getVisibility() == View.VISIBLE
+ && canShowPlaybackControlLayout) ? View.VISIBLE : View.GONE);
+ mMediaMainControlLayout.setVisibility((mVolumeControlLayout.getVisibility() == View.GONE
+ && !canShowPlaybackControlLayout) ? View.GONE : View.VISIBLE);
+ }
+
+ private void updateLayoutHeight() {
+ // We need to defer the update until the first layout has occurred, as we don't yet know the
+ // overall visible display size in which the window this view is attached to has been
+ // positioned in.
+ ViewTreeObserver observer = mDefaultControlLayout.getViewTreeObserver();
+ observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ mDefaultControlLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+ updateLayoutHeightInternal();
+ }
+ });
+ }
+
+ /**
+ * Updates the height of views and hide artwork or metadata if space is limited.
+ */
+ private void updateLayoutHeightInternal() {
+ // Measure the size of widgets and get the height of main components.
+ int oldHeight = getLayoutHeight(mMediaMainControlLayout);
+ setLayoutHeight(mMediaMainControlLayout, ViewGroup.LayoutParams.FILL_PARENT);
+ updateMediaControlVisibility(canShowPlaybackControlLayout());
+ View decorView = getWindow().getDecorView();
+ decorView.measure(
+ MeasureSpec.makeMeasureSpec(getWindow().getAttributes().width, MeasureSpec.EXACTLY),
+ MeasureSpec.UNSPECIFIED);
+ setLayoutHeight(mMediaMainControlLayout, oldHeight);
+ int artViewHeight = 0;
+ if (mCustomControlView == null && mArtView.getDrawable() instanceof BitmapDrawable) {
+ Bitmap art = ((BitmapDrawable) mArtView.getDrawable()).getBitmap();
+ if (art != null) {
+ artViewHeight = getDesiredArtHeight(art.getWidth(), art.getHeight());
+ mArtView.setScaleType(art.getWidth() >= art.getHeight()
+ ? ImageView.ScaleType.FIT_XY : ImageView.ScaleType.FIT_CENTER);
+ }
+ }
+ int mainControllerHeight = getMainControllerHeight(canShowPlaybackControlLayout());
+ int volumeGroupListCount = mVolumeGroupList.getAdapter() != null
+ ? mVolumeGroupList.getAdapter().getCount() : 0;
+ // Scale down volume group list items in landscape mode.
+ for (int i = 0; i < mVolumeGroupList.getChildCount(); i++) {
+ updateVolumeGroupItemHeight(mVolumeGroupList.getChildAt(i));
+ }
+ int expandedGroupListHeight = mVolumeGroupListItemHeight * volumeGroupListCount;
+ if (volumeGroupListCount > 0) {
+ expandedGroupListHeight += mVolumeGroupListPaddingTop;
+ }
+ expandedGroupListHeight = Math.min(expandedGroupListHeight, mVolumeGroupListMaxHeight);
+ int visibleGroupListHeight = mIsGroupExpanded ? expandedGroupListHeight : 0;
+
+ int desiredControlLayoutHeight =
+ Math.max(artViewHeight, visibleGroupListHeight) + mainControllerHeight;
+ Rect visibleRect = new Rect();
+ decorView.getWindowVisibleDisplayFrame(visibleRect);
+ // Height of non-control views in decor view.
+ // This includes title bar, button bar, and dialog's vertical padding which should be
+ // always shown.
+ int nonControlViewHeight = mDialogAreaLayout.getMeasuredHeight()
+ - mDefaultControlLayout.getMeasuredHeight();
+ // Maximum allowed height for controls to fit screen.
+ int maximumControlViewHeight = visibleRect.height() - nonControlViewHeight;
+
+ // Show artwork if it fits the screen.
+ if (mCustomControlView == null && artViewHeight > 0
+ && desiredControlLayoutHeight <= maximumControlViewHeight) {
+ mArtView.setVisibility(View.VISIBLE);
+ setLayoutHeight(mArtView, artViewHeight);
} else {
- mDisconnectButton.setVisibility(View.GONE);
- }
-
- if (mRoute.getSettingsIntent() != null) {
- mSettingsButton.setVisibility(View.VISIBLE);
- } else {
- mSettingsButton.setVisibility(View.GONE);
- }
-
- if (mControlView == null) {
- if (mDescription != null && mDescription.getIconBitmap() != null) {
- mArtView.setImageBitmap(mDescription.getIconBitmap());
- mArtView.setVisibility(View.VISIBLE);
- } else if (mDescription != null && mDescription.getIconUri() != null) {
- // TODO replace with background load of icon
- mArtView.setImageURI(mDescription.getIconUri());
- mArtView.setVisibility(View.VISIBLE);
- } else {
- mArtView.setImageDrawable(null);
+ if (getLayoutHeight(mVolumeGroupList) + mMediaMainControlLayout.getMeasuredHeight()
+ >= mDefaultControlLayout.getMeasuredHeight()) {
mArtView.setVisibility(View.GONE);
}
+ artViewHeight = 0;
+ desiredControlLayoutHeight = visibleGroupListHeight + mainControllerHeight;
+ }
+ // Show the playback control if it fits the screen.
+ if (canShowPlaybackControlLayout()
+ && desiredControlLayoutHeight <= maximumControlViewHeight) {
+ mPlaybackControlLayout.setVisibility(View.VISIBLE);
+ } else {
+ mPlaybackControlLayout.setVisibility(View.GONE);
+ }
+ updateMediaControlVisibility(mPlaybackControlLayout.getVisibility() == View.VISIBLE);
+ mainControllerHeight = getMainControllerHeight(
+ mPlaybackControlLayout.getVisibility() == View.VISIBLE);
+ desiredControlLayoutHeight =
+ Math.max(artViewHeight, visibleGroupListHeight) + mainControllerHeight;
+ // Limit the volume group list height to fit the screen.
+ if (desiredControlLayoutHeight > maximumControlViewHeight) {
+ visibleGroupListHeight -= (desiredControlLayoutHeight - maximumControlViewHeight);
+ desiredControlLayoutHeight = maximumControlViewHeight;
+ }
+ // Update the layouts with the computed heights.
+ mMediaMainControlLayout.clearAnimation();
+ mVolumeGroupList.clearAnimation();
+ mDefaultControlLayout.clearAnimation();
+ if (mIsGroupListAnimationNeeded) {
+ animateLayoutHeight(mMediaMainControlLayout, mainControllerHeight);
+ animateLayoutHeight(mVolumeGroupList, visibleGroupListHeight);
+ animateLayoutHeight(mDefaultControlLayout, desiredControlLayoutHeight);
+ } else {
+ setLayoutHeight(mMediaMainControlLayout, mainControllerHeight);
+ setLayoutHeight(mVolumeGroupList, visibleGroupListHeight);
+ setLayoutHeight(mDefaultControlLayout, desiredControlLayoutHeight);
+ }
+ mIsGroupListAnimationNeeded = false;
+ // Maximize the window size with a transparent layout in advance for smooth animation.
+ setLayoutHeight(mExpandableAreaLayout, visibleRect.height());
+ }
+
+ private void updateVolumeGroupItemHeight(View item) {
+ setLayoutHeight(item, mVolumeGroupListItemHeight);
+ View icon = item.findViewById(R.id.mr_volume_item_icon);
+ ViewGroup.LayoutParams lp = icon.getLayoutParams();
+ lp.width = mVolumeGroupListItemIconSize;
+ lp.height = mVolumeGroupListItemIconSize;
+ icon.setLayoutParams(lp);
+ }
+
+ private void animateLayoutHeight(final View view, int targetHeight) {
+ final int startValue = getLayoutHeight(view);
+ final int endValue = targetHeight;
+ Animation anim = new Animation() {
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ int height = startValue - (int) ((startValue - endValue) * interpolatedTime);
+ setLayoutHeight(view, height);
+ }
+ };
+ anim.setDuration(mGroupListAnimationDurationMs);
+ if (android.os.Build.VERSION.SDK_INT >= 21) {
+ anim.setInterpolator(mContext, mIsGroupExpanded ? R.interpolator.mr_linear_out_slow_in
+ : R.interpolator.mr_fast_out_slow_in);
+ }
+ if (view == mVolumeGroupList) {
+ anim.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ mVolumeGroupList.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ mVolumeGroupList.setTranscriptMode(ListView.TRANSCRIPT_MODE_DISABLED);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) { }
+ });
+ }
+ view.startAnimation(anim);
+ }
+
+ private void updateVolumeControlLayout() {
+ if (isVolumeControlAvailable(mRoute)) {
+ if (mVolumeControlLayout.getVisibility() == View.GONE) {
+ mVolumeControlLayout.setVisibility(View.VISIBLE);
+ mVolumeSlider.setMax(mRoute.getVolumeMax());
+ mVolumeSlider.setProgress(mRoute.getVolume());
+ if (getGroup() == null) {
+ mGroupExpandCollapseButton.setVisibility(View.GONE);
+ } else {
+ mGroupExpandCollapseButton.setVisibility(View.VISIBLE);
+ VolumeGroupAdapter adapter =
+ (VolumeGroupAdapter) mVolumeGroupList.getAdapter();
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+ } else {
+ mVolumeControlLayout.setVisibility(View.GONE);
+ }
+ updateLayoutHeight();
+ }
+
+ private void updatePlaybackControlLayout() {
+ if (canShowPlaybackControlLayout()) {
CharSequence title = mDescription == null ? null : mDescription.getTitle();
boolean hasTitle = !TextUtils.isEmpty(title);
CharSequence subtitle = mDescription == null ? null : mDescription.getSubtitle();
boolean hasSubtitle = !TextUtils.isEmpty(subtitle);
- if (!hasTitle && !hasSubtitle) {
- mTitleView.setText(R.string.mr_media_route_controller_no_info_available);
- mTitleView.setEnabled(false);
- mTitleView.setVisibility(View.VISIBLE);
- mSubtitleView.setVisibility(View.GONE);
+ boolean showTitle = false;
+ boolean showSubtitle = false;
+ if (mRoute.getPresentationDisplayId()
+ != MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE) {
+ // The user is currently casting screen.
+ mTitleView.setText(R.string.mr_controller_casting_screen);
+ showTitle = true;
+ } else if (mState == null || mState.getState() == PlaybackStateCompat.STATE_NONE) {
+ // Show "No media selected" as we don't yet know the playback state.
+ // (Only exception is bluetooth where we don't show anything.)
+ if (!mRoute.isDeviceTypeBluetooth()) {
+ mTitleView.setText(R.string.mr_controller_no_media_selected);
+ showTitle = true;
+ }
+ } else if (!hasTitle && !hasSubtitle) {
+ mTitleView.setText(R.string.mr_controller_no_info_available);
+ showTitle = true;
} else {
- mTitleView.setText(title);
- mTitleView.setEnabled(hasTitle);
- mTitleView.setVisibility(hasTitle ? View.VISIBLE : View.GONE);
- mSubtitleView.setText(subtitle);
- mSubtitleView.setVisibility(hasSubtitle ? View.VISIBLE : View.GONE);
+ if (hasTitle) {
+ mTitleView.setText(title);
+ showTitle = true;
+ }
+ if (hasSubtitle) {
+ mSubtitleView.setText(subtitle);
+ showSubtitle = true;
+ }
}
+ mTitleView.setVisibility(showTitle ? View.VISIBLE : View.GONE);
+ mSubtitleView.setVisibility(showSubtitle ? View.VISIBLE : View.GONE);
+
if (mState != null) {
boolean isPlaying = mState.getState() == PlaybackStateCompat.STATE_BUFFERING
|| mState.getState() == PlaybackStateCompat.STATE_PLAYING;
boolean supportsPlay = (mState.getActions() & (PlaybackStateCompat.ACTION_PLAY
| PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
boolean supportsPause = (mState.getActions() & (PlaybackStateCompat.ACTION_PAUSE
- | PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
+ | PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
if (isPlaying && supportsPause) {
mPlayPauseButton.setVisibility(View.VISIBLE);
mPlayPauseButton.setImageResource(MediaRouterThemeHelper.getThemeResource(
- getContext(), R.attr.mediaRoutePauseDrawable));
- mPlayPauseButton.setContentDescription(getContext().getResources()
- .getText(R.string.mr_media_route_controller_pause));
+ mContext, R.attr.mediaRoutePauseDrawable));
+ mPlayPauseButton.setContentDescription(mContext.getResources()
+ .getText(R.string.mr_controller_pause));
} else if (!isPlaying && supportsPlay) {
mPlayPauseButton.setVisibility(View.VISIBLE);
mPlayPauseButton.setImageResource(MediaRouterThemeHelper.getThemeResource(
- getContext(), R.attr.mediaRoutePlayDrawable));
- mPlayPauseButton.setContentDescription(getContext().getResources()
- .getText(R.string.mr_media_route_controller_play));
+ mContext, R.attr.mediaRoutePlayDrawable));
+ mPlayPauseButton.setContentDescription(mContext.getResources()
+ .getText(R.string.mr_controller_play));
} else {
mPlayPauseButton.setVisibility(View.GONE);
}
- } else {
- mPlayPauseButton.setVisibility(View.GONE);
}
}
- return true;
+ updateLayoutHeight();
}
- private Drawable getIconDrawable() {
- if (mRoute.isConnecting()) {
- if (mMediaRouteConnectingDrawable == null) {
- mMediaRouteConnectingDrawable = MediaRouterThemeHelper.getThemeDrawable(
- getContext(), R.attr.mediaRouteConnectingDrawable);
- }
- return mMediaRouteConnectingDrawable;
- } else {
- if (mMediaRouteOnDrawable == null) {
- mMediaRouteOnDrawable = MediaRouterThemeHelper.getThemeDrawable(
- getContext(), R.attr.mediaRouteOnDrawable);
- }
- return mMediaRouteOnDrawable;
+ private boolean isVolumeControlAvailable(MediaRouter.RouteInfo route) {
+ return mVolumeControlEnabled && route.getVolumeHandling()
+ == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+ }
+
+ private static int getLayoutHeight(View view) {
+ return view.getLayoutParams().height;
+ }
+
+ private static void setLayoutHeight(View view, int height) {
+ ViewGroup.LayoutParams lp = view.getLayoutParams();
+ lp.height = height;
+ view.setLayoutParams(lp);
+ }
+
+ /**
+ * Returns desired art height to fit into controller dialog.
+ */
+ private int getDesiredArtHeight(int originalWidth, int originalHeight) {
+ if (originalWidth >= originalHeight) {
+ // For landscape art, fit width to dialog width.
+ return (int) ((float) mDialogContentWidth * originalHeight / originalWidth + 0.5f);
}
- }
-
- private void updateVolume() {
- if (!mVolumeSliderTouched) {
- if (isVolumeControlAvailable()) {
- mVolumeLayout.setVisibility(View.VISIBLE);
- mVolumeSlider.setMax(mRoute.getVolumeMax());
- mVolumeSlider.setProgress(mRoute.getVolume());
- } else {
- mVolumeLayout.setVisibility(View.GONE);
- }
- }
- }
-
- private boolean isVolumeControlAvailable() {
- return mVolumeControlEnabled && mRoute.getVolumeHandling() ==
- MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+ // For portrait art, fit height to 16:9 ratio case's height.
+ return (int) ((float) mDialogContentWidth * 9 / 16 + 0.5f);
}
private final class MediaRouterCallback extends MediaRouter.Callback {
@@ -440,8 +784,9 @@
@Override
public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) {
- if (route == mRoute) {
- updateVolume();
+ SeekBar volumeSlider = mVolumeSliderMap.get(route);
+ if (volumeSlider != null && mRouteInVolumeSliderTouched != route) {
+ volumeSlider.setProgress(route.getVolume());
}
}
}
@@ -472,31 +817,228 @@
@Override
public void onClick(View v) {
int id = v.getId();
- if (id == R.id.stop || id == R.id.disconnect) {
+ if (id == BUTTON_STOP_RES_ID || id == BUTTON_DISCONNECT_RES_ID) {
if (mRoute.isSelected()) {
- mRouter.unselect(id == R.id.stop ?
+ mRouter.unselect(id == BUTTON_STOP_RES_ID ?
MediaRouter.UNSELECT_REASON_STOPPED :
MediaRouter.UNSELECT_REASON_DISCONNECTED);
}
dismiss();
- } else if (id == R.id.play_pause) {
+ } else if (id == R.id.mr_control_play_pause) {
if (mMediaController != null && mState != null) {
- if (mState.getState() == PlaybackStateCompat.STATE_PLAYING) {
+ boolean isPlaying = mState.getState() == PlaybackStateCompat.STATE_PLAYING;
+ if (isPlaying) {
mMediaController.getTransportControls().pause();
} else {
mMediaController.getTransportControls().play();
}
- }
- } else if (id == R.id.settings) {
- IntentSender is = mRoute.getSettingsIntent();
- if (is != null) {
- try {
- is.sendIntent(null, 0, null, null, null);
- dismiss();
- } catch (Exception e) {
- Log.e(TAG, "Error opening route settings.", e);
+ // Announce the action for accessibility.
+ if (mAccessibilityManager != null && mAccessibilityManager.isEnabled()) {
+ AccessibilityEvent event = AccessibilityEvent.obtain(
+ AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
+ event.setPackageName(mContext.getPackageName());
+ event.setClassName(getClass().getName());
+ int resId = isPlaying ?
+ R.string.mr_controller_pause : R.string.mr_controller_play;
+ event.getText().add(mContext.getString(resId));
+ mAccessibilityManager.sendAccessibilityEvent(event);
}
}
+ } else if (id == R.id.mr_close) {
+ dismiss();
+ }
+ }
+ }
+
+ private class VolumeChangeListener implements SeekBar.OnSeekBarChangeListener {
+ private final Runnable mStopTrackingTouch = new Runnable() {
+ @Override
+ public void run() {
+ if (mRouteInVolumeSliderTouched != null) {
+ SeekBar volumeSlider = mVolumeSliderMap.get(mRouteInVolumeSliderTouched);
+ volumeSlider.setProgress(mRouteInVolumeSliderTouched.getVolume());
+ mRouteInVolumeSliderTouched = null;
+ }
+ }
+ };
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ if (mRouteInVolumeSliderTouched != null) {
+ mVolumeSlider.removeCallbacks(mStopTrackingTouch);
+ }
+ mRouteInVolumeSliderTouched = (MediaRouter.RouteInfo) seekBar.getTag();
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ // Defer resetting mVolumeSliderTouched to allow the media route provider
+ // a little time to settle into its new state and publish the final
+ // volume update.
+ mVolumeSlider.postDelayed(mStopTrackingTouch, VOLUME_UPDATE_DELAY_MILLIS);
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (fromUser) {
+ MediaRouter.RouteInfo route = (MediaRouter.RouteInfo) seekBar.getTag();
+ if (route.getVolume() != progress) {
+ route.requestSetVolume(progress);
+ }
+ }
+ }
+ }
+
+ private class VolumeGroupAdapter extends ArrayAdapter<MediaRouter.RouteInfo> {
+ final float mDisabledAlpha;
+
+ public VolumeGroupAdapter(Context context, List<MediaRouter.RouteInfo> objects) {
+ super(context, 0, objects);
+ mDisabledAlpha = MediaRouterThemeHelper.getDisabledAlpha(context);
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ View v = convertView;
+ if (v == null) {
+ v = LayoutInflater.from(mContext).inflate(
+ R.layout.mr_controller_volume_item, parent, false);
+ } else {
+ updateVolumeGroupItemHeight(v);
+ }
+
+ MediaRouter.RouteInfo route = getItem(position);
+ if (route != null) {
+ boolean isEnabled = route.isEnabled();
+
+ TextView routeName = (TextView) v.findViewById(R.id.mr_name);
+ routeName.setEnabled(isEnabled);
+ routeName.setText(route.getName());
+
+ MediaRouteVolumeSlider volumeSlider =
+ (MediaRouteVolumeSlider) v.findViewById(R.id.mr_volume_slider);
+ MediaRouterThemeHelper.setVolumeSliderColor(
+ mContext, volumeSlider, mVolumeGroupList);
+ volumeSlider.setTag(route);
+ mVolumeSliderMap.put(route, volumeSlider);
+ volumeSlider.setHideThumb(!isEnabled);
+ volumeSlider.setEnabled(isEnabled);
+ if (isEnabled) {
+ if (isVolumeControlAvailable(route)) {
+ volumeSlider.setMax(route.getVolumeMax());
+ volumeSlider.setProgress(route.getVolume());
+ volumeSlider.setOnSeekBarChangeListener(mVolumeChangeListener);
+ } else {
+ volumeSlider.setMax(100);
+ volumeSlider.setProgress(100);
+ volumeSlider.setEnabled(false);
+ }
+ }
+
+ ImageView volumeItemIcon =
+ (ImageView) v.findViewById(R.id.mr_volume_item_icon);
+ volumeItemIcon.setAlpha(isEnabled ? 0xFF : (int) (0xFF * mDisabledAlpha));
+ }
+ return v;
+ }
+ }
+
+ private class FetchArtTask extends AsyncTask<Void, Void, Bitmap> {
+ final Bitmap mIconBitmap;
+ final Uri mIconUri;
+ int mBackgroundColor;
+
+ FetchArtTask() {
+ mIconBitmap = mDescription == null ? null : mDescription.getIconBitmap();
+ mIconUri = mDescription == null ? null : mDescription.getIconUri();
+ }
+
+ @Override
+ protected void onPreExecute() {
+ if (mArtIconBitmap == mIconBitmap && mArtIconUri == mIconUri) {
+ // Already handled the current art.
+ cancel(true);
+ }
+ }
+
+ @Override
+ protected Bitmap doInBackground(Void... arg) {
+ Bitmap art = null;
+ if (mIconBitmap != null) {
+ art = mIconBitmap;
+ } else if (mIconUri != null) {
+ String scheme = mIconUri.getScheme();
+ if (!(ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
+ || ContentResolver.SCHEME_CONTENT.equals(scheme)
+ || ContentResolver.SCHEME_FILE.equals(scheme))) {
+ Log.w(TAG, "Icon Uri should point to local resources.");
+ return null;
+ }
+ BufferedInputStream stream = null;
+ try {
+ stream = new BufferedInputStream(
+ mContext.getContentResolver().openInputStream(mIconUri));
+
+ // Query art size.
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(stream, null, options);
+ if (options.outWidth == 0 || options.outHeight == 0) {
+ return null;
+ }
+ // Rewind the stream in order to restart art decoding.
+ try {
+ stream.reset();
+ } catch (IOException e) {
+ // Failed to rewind the stream, try to reopen it.
+ stream.close();
+ stream = new BufferedInputStream(mContext.getContentResolver()
+ .openInputStream(mIconUri));
+ }
+ // Calculate required size to decode the art and possibly resize it.
+ options.inJustDecodeBounds = false;
+ int reqHeight = getDesiredArtHeight(options.outWidth, options.outHeight);
+ int ratio = options.outHeight / reqHeight;
+ options.inSampleSize = Math.max(1, Integer.highestOneBit(ratio));
+ if (isCancelled()) {
+ return null;
+ }
+ art = BitmapFactory.decodeStream(stream, null, options);
+ } catch (IOException e){
+ Log.w(TAG, "Unable to open: " + mIconUri, e);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ if (art != null && art.getWidth() < art.getHeight()) {
+ // Portrait art requires dominant color as background color.
+ Palette palette = new Palette.Builder(art).maximumColorCount(1).generate();
+ mBackgroundColor = palette.getSwatches().isEmpty()
+ ? 0 : palette.getSwatches().get(0).getRgb();
+ }
+ return art;
+ }
+
+ @Override
+ protected void onCancelled() {
+ mFetchArtTask = null;
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap art) {
+ mFetchArtTask = null;
+ if (mArtIconBitmap != mIconBitmap || mArtIconUri != mIconUri) {
+ mArtIconBitmap = mIconBitmap;
+ mArtIconUri = mIconUri;
+
+ mArtView.setImageBitmap(art);
+ mArtView.setBackgroundColor(mBackgroundColor);
+ updateLayoutHeight();
}
}
}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java
index beb9832..6cadb9a 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java
@@ -18,6 +18,7 @@
import android.app.Dialog;
import android.content.Context;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
@@ -29,6 +30,7 @@
* </p>
*/
public class MediaRouteControllerDialogFragment extends DialogFragment {
+ private MediaRouteControllerDialog mDialog;
/**
* Creates a media route controller dialog fragment.
* <p>
@@ -52,6 +54,15 @@
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- return onCreateControllerDialog(getActivity(), savedInstanceState);
+ mDialog = onCreateControllerDialog(getActivity(), savedInstanceState);
+ return mDialog;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mDialog != null) {
+ mDialog.updateLayout();
+ }
}
}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteDialogHelper.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteDialogHelper.java
new file mode 100644
index 0000000..99d414f
--- /dev/null
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteDialogHelper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.app;
+
+import android.content.Context;
+import android.support.v7.mediarouter.R;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ViewGroup;
+
+final class MediaRouteDialogHelper {
+ /**
+ * The framework should set the dialog width properly, but somehow it doesn't work, hence
+ * duplicating a similar logic here to determine the appropriate dialog width.
+ */
+ public static int getDialogWidth(Context context) {
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
+
+ TypedValue value = new TypedValue();
+ context.getResources().getValue(isPortrait ? R.dimen.mr_dialog_fixed_width_minor
+ : R.dimen.mr_dialog_fixed_width_major, value, true);
+ if (value.type == TypedValue.TYPE_DIMENSION) {
+ return (int) value.getDimension(metrics);
+ } else if (value.type == TypedValue.TYPE_FRACTION) {
+ return (int) value.getFraction(metrics.widthPixels, metrics.widthPixels);
+ }
+ return ViewGroup.LayoutParams.WRAP_CONTENT;
+ }
+}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteExpandCollapseButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteExpandCollapseButton.java
new file mode 100644
index 0000000..6ccfaa8
--- /dev/null
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteExpandCollapseButton.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.app;
+
+import android.content.Context;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.AnimationDrawable;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.mediarouter.R;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+
+/**
+ * Chevron/Caret button to expand/collapse group volume list with animation.
+ */
+class MediaRouteExpandCollapseButton extends ImageButton {
+ private final AnimationDrawable mExpandAnimationDrawable;
+ private final AnimationDrawable mCollapseAnimationDrawable;
+ private final String mExpandGroupDescription;
+ private final String mCollapseGroupDescription;
+ private boolean mIsGroupExpanded;
+ private OnClickListener mListener;
+
+ public MediaRouteExpandCollapseButton(Context context) {
+ this(context, null);
+ }
+
+ public MediaRouteExpandCollapseButton(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public MediaRouteExpandCollapseButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mExpandAnimationDrawable = (AnimationDrawable) ContextCompat.getDrawable(
+ context, R.drawable.ic_expand);
+ mCollapseAnimationDrawable = (AnimationDrawable) ContextCompat.getDrawable(
+ context, R.drawable.ic_collapse);
+
+ ColorFilter filter = new PorterDuffColorFilter(
+ MediaRouterThemeHelper.getControllerColor(context, defStyleAttr),
+ PorterDuff.Mode.SRC_IN);
+ mExpandAnimationDrawable.setColorFilter(filter);
+ mCollapseAnimationDrawable.setColorFilter(filter);
+
+ mExpandGroupDescription = context.getString(R.string.mr_controller_expand_group);
+ mCollapseGroupDescription = context.getString(R.string.mr_controller_collapse_group);
+
+ setImageDrawable(mExpandAnimationDrawable.getFrame(0));
+ setContentDescription(mExpandGroupDescription);
+
+ super.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mIsGroupExpanded = !mIsGroupExpanded;
+ if (mIsGroupExpanded) {
+ setImageDrawable(mExpandAnimationDrawable);
+ mExpandAnimationDrawable.start();
+ setContentDescription(mCollapseGroupDescription);
+ } else {
+ setImageDrawable(mCollapseAnimationDrawable);
+ mCollapseAnimationDrawable.start();
+ setContentDescription(mExpandGroupDescription);
+ }
+ if (mListener != null) {
+ mListener.onClick(view);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener listener) {
+ mListener = listener;
+ }
+}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
new file mode 100644
index 0000000..a7aafd2
--- /dev/null
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.app;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.v7.mediarouter.R;
+import android.support.v7.widget.AppCompatSeekBar;
+import android.util.AttributeSet;
+import android.util.Log;
+
+/**
+ * Volume slider with showing, hiding, and applying alpha supports to the thumb.
+ */
+class MediaRouteVolumeSlider extends AppCompatSeekBar {
+ private static final String TAG = "MediaRouteVolumeSlider";
+
+ private final float mDisabledAlpha;
+
+ private boolean mHideThumb;
+ private Drawable mThumb;
+ private int mColor;
+
+ public MediaRouteVolumeSlider(Context context) {
+ this(context, null);
+ }
+
+ public MediaRouteVolumeSlider(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.seekBarStyle);
+ }
+
+ public MediaRouteVolumeSlider(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mDisabledAlpha = MediaRouterThemeHelper.getDisabledAlpha(context);
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ int alpha = isEnabled() ? 0xFF : (int) (0xFF * mDisabledAlpha);
+
+ // The thumb drawable is a collection of drawables and its current drawables are changed per
+ // state. Apply the color filter and alpha on every state change.
+ mThumb.setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
+ mThumb.setAlpha(alpha);
+
+ getProgressDrawable().setColorFilter(mColor, PorterDuff.Mode.SRC_IN);
+ getProgressDrawable().setAlpha(alpha);
+ }
+
+ @Override
+ public void setThumb(Drawable thumb) {
+ mThumb = thumb;
+ super.setThumb(mHideThumb ? null : mThumb);
+ }
+
+ /**
+ * Sets whether to show or hide thumb.
+ */
+ public void setHideThumb(boolean hideThumb) {
+ if (mHideThumb == hideThumb) {
+ return;
+ }
+ mHideThumb = hideThumb;
+ super.setThumb(mHideThumb ? null : mThumb);
+ }
+
+ /**
+ * Sets the volume slider color. The change takes effect next time drawable state is changed.
+ * <p>
+ * The color cannot be translucent, otherwise the underlying progress bar will be seen through
+ * the thumb.
+ * </p>
+ */
+ public void setColor(int color) {
+ if (mColor == color) {
+ return;
+ }
+ if (Color.alpha(color) != 0xFF) {
+ Log.e(TAG, "Volume slider color cannot be translucent: #" + Integer.toHexString(color));
+ }
+ mColor = color;
+ }
+}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java b/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
index 09999a1..33ab7bc 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
@@ -17,19 +17,59 @@
package android.support.v7.app;
import android.content.Context;
-import android.graphics.drawable.Drawable;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.support.annotation.IntDef;
+import android.support.v4.graphics.ColorUtils;
import android.support.v7.mediarouter.R;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
+import android.view.View;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
final class MediaRouterThemeHelper {
+ private static final float MIN_CONTRAST = 3.0f;
+
+ @IntDef({COLOR_DARK_ON_LIGHT_BACKGROUND, COLOR_WHITE_ON_DARK_BACKGROUND})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface ControllerColorType {}
+
+ private static final int COLOR_DARK_ON_LIGHT_BACKGROUND = 0xDE000000; /* Opacity of 87% */
+ private static final int COLOR_WHITE_ON_DARK_BACKGROUND = Color.WHITE;
+
private MediaRouterThemeHelper() {
}
- public static Context createThemedContext(Context context) {
- boolean isLightTheme = isLightTheme(context);
- return new ContextThemeWrapper(context, isLightTheme ?
- R.style.Theme_MediaRouter_Light : R.style.Theme_MediaRouter);
+ /**
+ * Creates a themed context based on the explicit style resource or the parent context's default
+ * theme.
+ * <p>
+ * The theme which will be applied on top of the parent {@code context}'s theme is determined
+ * by the primary color defined in the given {@code style}, or in the parent {@code context}.
+ *
+ * @param context the parent context
+ * @param style the resource ID of the style against which to inflate this context, or
+ * {@code 0} to use the parent {@code context}'s default theme.
+ * @return The themed context.
+ */
+ public static Context createThemedContext(Context context, int style) {
+ int theme;
+ if (isLightTheme(context)) {
+ if (getControllerColor(context, style) == COLOR_DARK_ON_LIGHT_BACKGROUND) {
+ theme = R.style.Theme_MediaRouter_Light;
+ } else {
+ theme = R.style.Theme_MediaRouter_Light_DarkControlPanel;
+ }
+ } else {
+ if (getControllerColor(context, style) == COLOR_DARK_ON_LIGHT_BACKGROUND) {
+ theme = R.style.Theme_MediaRouter_LightControlPanel;
+ } else {
+ theme = R.style.Theme_MediaRouter;
+ }
+ }
+ return new ContextThemeWrapper(context, theme);
}
public static int getThemeResource(Context context, int attr) {
@@ -37,9 +77,62 @@
return context.getTheme().resolveAttribute(attr, value, true) ? value.resourceId : 0;
}
- public static Drawable getThemeDrawable(Context context, int attr) {
- int res = getThemeResource(context, attr);
- return res != 0 ? context.getResources().getDrawable(res) : null;
+ public static float getDisabledAlpha(Context context) {
+ TypedValue value = new TypedValue();
+ return context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, value, true)
+ ? value.getFloat() : 0.5f;
+ }
+
+ public static @ControllerColorType int getControllerColor(Context context, int style) {
+ int primaryColor = getThemeColor(context, style, R.attr.colorPrimary);
+ if (ColorUtils.calculateContrast(COLOR_WHITE_ON_DARK_BACKGROUND, primaryColor)
+ >= MIN_CONTRAST) {
+ return COLOR_WHITE_ON_DARK_BACKGROUND;
+ }
+ return COLOR_DARK_ON_LIGHT_BACKGROUND;
+ }
+
+ public static int getButtonTextColor(Context context) {
+ int primaryColor = getThemeColor(context, 0, R.attr.colorPrimary);
+ int backgroundColor = getThemeColor(context, 0, android.R.attr.colorBackground);
+
+ if (ColorUtils.calculateContrast(primaryColor, backgroundColor) < MIN_CONTRAST) {
+ // Default to colorAccent if the contrast ratio is low.
+ return getThemeColor(context, 0, R.attr.colorAccent);
+ }
+ return primaryColor;
+ }
+
+ public static void setMediaControlsBackgroundColor(
+ Context context, View mainControls, View groupControls, boolean hasGroup) {
+ int primaryColor = getThemeColor(context, 0, R.attr.colorPrimary);
+ int primaryDarkColor = getThemeColor(context, 0, R.attr.colorPrimaryDark);
+ int controllerColor = getControllerColor(context, 0);
+ if (hasGroup && controllerColor == COLOR_DARK_ON_LIGHT_BACKGROUND
+ && ColorUtils.calculateContrast(controllerColor, primaryDarkColor) < MIN_CONTRAST) {
+ // Instead of showing dark controls in a possibly dark (i.e. the primary dark), model
+ // the white dialog and use the primary color for the group controls.
+ primaryDarkColor = primaryColor;
+ primaryColor = Color.WHITE;
+ }
+ mainControls.setBackgroundColor(primaryColor);
+ groupControls.setBackgroundColor(primaryDarkColor);
+ // Also store the background colors to the view tags. They are used in
+ // setVolumeSliderColor() below.
+ mainControls.setTag(primaryColor);
+ groupControls.setTag(primaryDarkColor);
+ }
+
+ public static void setVolumeSliderColor(
+ Context context, MediaRouteVolumeSlider volumeSlider, View backgroundView) {
+ int controllerColor = getControllerColor(context, 0);
+ if (Color.alpha(controllerColor) != 0xFF) {
+ // Composite with the background in order not to show the underlying progress bar
+ // through the thumb.
+ int backgroundColor = (int) backgroundView.getTag();
+ controllerColor = ColorUtils.compositeColors(controllerColor, backgroundColor);
+ }
+ volumeSlider.setColor(controllerColor);
}
private static boolean isLightTheme(Context context) {
@@ -47,4 +140,22 @@
return context.getTheme().resolveAttribute(R.attr.isLightTheme, value, true)
&& value.data != 0;
}
+
+ private static int getThemeColor(Context context, int style, int attr) {
+ if (style != 0) {
+ int[] attrs = { attr };
+ TypedArray ta = context.obtainStyledAttributes(style, attrs);
+ int color = ta.getColor(0, 0);
+ ta.recycle();
+ if (color != 0) {
+ return color;
+ }
+ }
+ TypedValue value = new TypedValue();
+ context.getTheme().resolveAttribute(attr, value, true);
+ if (value.resourceId != 0) {
+ return context.getResources().getColor(value.resourceId);
+ }
+ return value.data;
+ }
}
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java b/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java
index d83ad2f..97a2cd7 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java
@@ -17,6 +17,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
@@ -37,13 +38,17 @@
*/
public final class MediaRouteDescriptor {
private static final String KEY_ID = "id";
+ private static final String KEY_GROUP_MEMBER_IDS = "groupMemberIds";
private static final String KEY_NAME = "name";
private static final String KEY_DESCRIPTION = "status";
+ private static final String KEY_ICON_URI = "iconUri";
private static final String KEY_ENABLED = "enabled";
private static final String KEY_CONNECTING = "connecting";
+ private static final String KEY_CONNECTION_STATE = "connectionState";
private static final String KEY_CONTROL_FILTERS = "controlFilters";
private static final String KEY_PLAYBACK_TYPE = "playbackType";
private static final String KEY_PLAYBACK_STREAM = "playbackStream";
+ private static final String KEY_DEVICE_TYPE = "deviceType";
private static final String KEY_VOLUME = "volume";
private static final String KEY_VOLUME_MAX = "volumeMax";
private static final String KEY_VOLUME_HANDLING = "volumeHandling";
@@ -73,6 +78,18 @@
}
/**
+ * Gets the group member ids of the route.
+ * <p>
+ * A route descriptor that has one or more group member route ids
+ * represents a route group. A member route may belong to another group.
+ * </p>
+ * @hide
+ */
+ public List<String> getGroupMemberIds() {
+ return mBundle.getStringArrayList(KEY_GROUP_MEMBER_IDS);
+ }
+
+ /**
* Gets the user-visible name of the route.
* <p>
* The route name identifies the destination represented by the route.
@@ -95,6 +112,17 @@
}
/**
+ * Gets the URI of the icon representing this route.
+ * <p>
+ * This icon will be used in picker UIs if available.
+ * </p>
+ */
+ public Uri getIconUri() {
+ String iconUri = mBundle.getString(KEY_ICON_URI);
+ return iconUri == null ? null : Uri.parse(iconUri);
+ }
+
+ /**
* Gets whether the route is enabled.
*/
public boolean isEnabled() {
@@ -103,16 +131,37 @@
/**
* Gets whether the route is connecting.
+ * @deprecated Use {@link #getConnectionState} instead
*/
public boolean isConnecting() {
return mBundle.getBoolean(KEY_CONNECTING, false);
}
/**
- * Gets whether the route can be disconnected without stopping playback. To
- * specify that the route should disconnect without stopping use
+ * Gets the connection state of the route.
+ *
+ * @return The connection state of this route:
+ * {@link MediaRouter.RouteInfo#CONNECTION_STATE_DISCONNECTED},
+ * {@link MediaRouter.RouteInfo#CONNECTION_STATE_CONNECTING}, or
+ * {@link MediaRouter.RouteInfo#CONNECTION_STATE_CONNECTED}.
+ */
+ public int getConnectionState() {
+ return mBundle.getInt(KEY_CONNECTION_STATE,
+ MediaRouter.RouteInfo.CONNECTION_STATE_DISCONNECTED);
+ }
+
+ /**
+ * Gets whether the route can be disconnected without stopping playback.
+ * <p>
+ * The route can normally be disconnected without stopping playback when
+ * the destination device on the route is connected to two or more source
+ * devices. The route provider should update the route immediately when the
+ * number of connected devices changes.
+ * </p><p>
+ * To specify that the route should disconnect without stopping use
* {@link MediaRouter#unselect(int)} with
* {@link MediaRouter#UNSELECT_REASON_DISCONNECTED}.
+ * </p>
*/
public boolean canDisconnectAndKeepPlaying() {
return mBundle.getBoolean(KEY_CAN_DISCONNECT, false);
@@ -147,7 +196,11 @@
}
/**
- * Gets the route's playback type.
+ * Gets the type of playback associated with this route.
+ *
+ * @return The type of playback associated with this route:
+ * {@link MediaRouter.RouteInfo#PLAYBACK_TYPE_LOCAL} or
+ * {@link MediaRouter.RouteInfo#PLAYBACK_TYPE_REMOTE}.
*/
public int getPlaybackType() {
return mBundle.getInt(KEY_PLAYBACK_TYPE, MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE);
@@ -161,6 +214,17 @@
}
/**
+ * Gets the type of the receiver device associated with this route.
+ *
+ * @return The type of the receiver device associated with this route:
+ * {@link MediaRouter.RouteInfo#DEVICE_TYPE_TV} or
+ * {@link MediaRouter.RouteInfo#DEVICE_TYPE_SPEAKER}.
+ */
+ public int getDeviceType() {
+ return mBundle.getInt(KEY_DEVICE_TYPE);
+ }
+
+ /**
* Gets the route's current volume, or 0 if unknown.
*/
public int getVolume() {
@@ -175,7 +239,11 @@
}
/**
- * Gets the route's volume handling.
+ * Gets information about how volume is handled on the route.
+ *
+ * @return How volume is handled on the route:
+ * {@link MediaRouter.RouteInfo#PLAYBACK_VOLUME_FIXED} or
+ * {@link MediaRouter.RouteInfo#PLAYBACK_VOLUME_VARIABLE}.
*/
public int getVolumeHandling() {
return mBundle.getInt(KEY_VOLUME_HANDLING,
@@ -186,7 +254,8 @@
* Gets the route's presentation display id, or -1 if none.
*/
public int getPresentationDisplayId() {
- return mBundle.getInt(KEY_PRESENTATION_DISPLAY_ID, -1);
+ return mBundle.getInt(
+ KEY_PRESENTATION_DISPLAY_ID, MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE);
}
/**
@@ -216,13 +285,17 @@
StringBuilder result = new StringBuilder();
result.append("MediaRouteDescriptor{ ");
result.append("id=").append(getId());
+ result.append(", groupMemberIds=").append(getGroupMemberIds());
result.append(", name=").append(getName());
result.append(", description=").append(getDescription());
+ result.append(", iconUri=").append(getIconUri());
result.append(", isEnabled=").append(isEnabled());
result.append(", isConnecting=").append(isConnecting());
+ result.append(", connectionState=").append(getConnectionState());
result.append(", controlFilters=").append(Arrays.toString(getControlFilters().toArray()));
result.append(", playbackType=").append(getPlaybackType());
result.append(", playbackStream=").append(getPlaybackStream());
+ result.append(", deviceType=").append(getDeviceType());
result.append(", volume=").append(getVolume());
result.append(", volumeMax=").append(getVolumeMax());
result.append(", volumeHandling=").append(getVolumeHandling());
@@ -257,6 +330,7 @@
*/
public static final class Builder {
private final Bundle mBundle;
+ private ArrayList<String> mGroupMemberIds;
private ArrayList<IntentFilter> mControlFilters;
/**
@@ -302,6 +376,49 @@
}
/**
+ * Adds a group member id of the route.
+ * <p>
+ * A route descriptor that has one or more group member route ids
+ * represents a route group. A member route may belong to another group.
+ * </p>
+ * @hide
+ */
+ public Builder addGroupMemberId(String groupMemberId) {
+ if (TextUtils.isEmpty(groupMemberId)) {
+ throw new IllegalArgumentException("groupMemberId must not be empty");
+ }
+
+ if (mGroupMemberIds == null) {
+ mGroupMemberIds = new ArrayList<>();
+ }
+ if (!mGroupMemberIds.contains(groupMemberId)) {
+ mGroupMemberIds.add(groupMemberId);
+ }
+ return this;
+ }
+
+ /**
+ * Adds a list of group member ids of the route.
+ * <p>
+ * A route descriptor that has one or more group member route ids
+ * represents a route group. A member route may belong to another group.
+ * </p>
+ * @hide
+ */
+ public Builder addGroupMemberIds(Collection<String> groupMemberIds) {
+ if (groupMemberIds == null) {
+ throw new IllegalArgumentException("groupMemberIds must not be null");
+ }
+
+ if (!groupMemberIds.isEmpty()) {
+ for (String groupMemberId : groupMemberIds) {
+ addGroupMemberId(groupMemberId);
+ }
+ }
+ return this;
+ }
+
+ /**
* Sets the user-visible name of the route.
* <p>
* The route name identifies the destination represented by the route.
@@ -326,6 +443,28 @@
}
/**
+ * Sets the URI of the icon representing this route.
+ * <p>
+ * This icon will be used in picker UIs if available.
+ * </p><p>
+ * The URI must be one of the following formats:
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ * </p>
+ */
+ public Builder setIconUri(Uri iconUri) {
+ if (iconUri == null) {
+ throw new IllegalArgumentException("iconUri must not be null");
+ }
+ mBundle.putString(KEY_ICON_URI, iconUri.toString());
+ return this;
+ }
+
+ /**
* Sets whether the route is enabled.
* <p>
* Disabled routes represent routes that a route provider knows about, such as paired
@@ -340,6 +479,7 @@
/**
* Sets whether the route is in the process of connecting and is not yet
* ready for use.
+ * @deprecated Use {@link #setConnectionState} instead.
*/
public Builder setConnecting(boolean connecting) {
mBundle.putBoolean(KEY_CONNECTING, connecting);
@@ -347,6 +487,19 @@
}
/**
+ * Sets the route's connection state.
+ *
+ * @param connectionState The connection state of the route:
+ * {@link MediaRouter.RouteInfo#CONNECTION_STATE_DISCONNECTED},
+ * {@link MediaRouter.RouteInfo#CONNECTION_STATE_CONNECTING}, or
+ * {@link MediaRouter.RouteInfo#CONNECTION_STATE_CONNECTED}.
+ */
+ public Builder setConnectionState(int connectionState) {
+ mBundle.putInt(KEY_CONNECTION_STATE, connectionState);
+ return this;
+ }
+
+ /**
* Sets whether the route can be disconnected without stopping playback.
*/
public Builder setCanDisconnect(boolean canDisconnect) {
@@ -398,6 +551,10 @@
/**
* Sets the route's playback type.
+ *
+ * @param playbackType The playback type of the route:
+ * {@link MediaRouter.RouteInfo#PLAYBACK_TYPE_LOCAL} or
+ * {@link MediaRouter.RouteInfo#PLAYBACK_TYPE_REMOTE}.
*/
public Builder setPlaybackType(int playbackType) {
mBundle.putInt(KEY_PLAYBACK_TYPE, playbackType);
@@ -413,6 +570,18 @@
}
/**
+ * Sets the route's receiver device type.
+ *
+ * @param deviceType The receive device type of the route:
+ * {@link MediaRouter.RouteInfo#DEVICE_TYPE_TV} or
+ * {@link MediaRouter.RouteInfo#DEVICE_TYPE_SPEAKER}.
+ */
+ public Builder setDeviceType(int deviceType) {
+ mBundle.putInt(KEY_DEVICE_TYPE, deviceType);
+ return this;
+ }
+
+ /**
* Sets the route's current volume, or 0 if unknown.
*/
public Builder setVolume(int volume) {
@@ -430,6 +599,10 @@
/**
* Sets the route's volume handling.
+ *
+ * @param volumeHandling how volume is handled on the route:
+ * {@link MediaRouter.RouteInfo#PLAYBACK_VOLUME_FIXED} or
+ * {@link MediaRouter.RouteInfo#PLAYBACK_VOLUME_VARIABLE}.
*/
public Builder setVolumeHandling(int volumeHandling) {
mBundle.putInt(KEY_VOLUME_HANDLING, volumeHandling);
@@ -461,6 +634,9 @@
if (mControlFilters != null) {
mBundle.putParcelableArrayList(KEY_CONTROL_FILTERS, mControlFilters);
}
+ if (mGroupMemberIds != null) {
+ mBundle.putStringArrayList(KEY_GROUP_MEMBER_IDS, mGroupMemberIds);
+ }
return new MediaRouteDescriptor(mBundle, mControlFilters);
}
}
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index d37ed95..b2e74e4 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -17,7 +17,6 @@
package android.support.v7.media;
import android.app.ActivityManager;
-import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -26,6 +25,7 @@
import android.content.IntentSender;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -37,7 +37,10 @@
import android.support.v4.hardware.display.DisplayManagerCompat;
import android.support.v4.media.VolumeProviderCompat;
import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.util.Pair;
import android.support.v7.media.MediaRouteProvider.ProviderMetadata;
+import android.support.v7.media.MediaRouteProvider.RouteController;
+import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
@@ -46,8 +49,10 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
/**
* MediaRouter allows applications to control the routing of media channels
@@ -762,26 +767,57 @@
* route and the manner in which it is used and controlled.
* </p>
*/
- public static final class RouteInfo {
+ public static class RouteInfo {
private final ProviderInfo mProvider;
private final String mDescriptorId;
private final String mUniqueId;
private String mName;
private String mDescription;
+ private Uri mIconUri;
private boolean mEnabled;
private boolean mConnecting;
+ private int mConnectionState;
private boolean mCanDisconnect;
- private final ArrayList<IntentFilter> mControlFilters = new ArrayList<IntentFilter>();
+ private final ArrayList<IntentFilter> mControlFilters = new ArrayList<>();
private int mPlaybackType;
private int mPlaybackStream;
+ private int mDeviceType;
private int mVolumeHandling;
private int mVolume;
private int mVolumeMax;
private Display mPresentationDisplay;
- private int mPresentationDisplayId = -1;
+ private int mPresentationDisplayId = PRESENTATION_DISPLAY_ID_NONE;
private Bundle mExtras;
private IntentSender mSettingsIntent;
- private MediaRouteDescriptor mDescriptor;
+ MediaRouteDescriptor mDescriptor;
+
+ /** @hide */
+ @IntDef({CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING,
+ CONNECTION_STATE_CONNECTED})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface ConnectionState {}
+
+ /**
+ * The default connection state indicating the route is disconnected.
+ *
+ * @see #getConnectionState
+ */
+ public static final int CONNECTION_STATE_DISCONNECTED = 0;
+
+ /**
+ * A connection state indicating the route is in the process of connecting and is not yet
+ * ready for use.
+ *
+ * @see #getConnectionState
+ */
+ public static final int CONNECTION_STATE_CONNECTING = 1;
+
+ /**
+ * A connection state indicating the route is connected.
+ *
+ * @see #getConnectionState
+ */
+ public static final int CONNECTION_STATE_CONNECTED = 2;
/** @hide */
@IntDef({PLAYBACK_TYPE_LOCAL,PLAYBACK_TYPE_REMOTE})
@@ -806,6 +842,45 @@
public static final int PLAYBACK_TYPE_REMOTE = 1;
/** @hide */
+ @IntDef({DEVICE_TYPE_UNKNOWN, DEVICE_TYPE_TV, DEVICE_TYPE_SPEAKER, DEVICE_TYPE_BLUETOOTH})
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface DeviceType {}
+
+ /**
+ * The default receiver device type of the route indicating the type is unknown.
+ *
+ * @see #getDeviceType
+ * @hide
+ */
+ public static final int DEVICE_TYPE_UNKNOWN = 0;
+
+
+ /**
+ * A receiver device type of the route indicating the presentation of the media is happening
+ * on a bluetooth device such as a bluetooth speaker.
+ *
+ * @see #getDeviceType
+ * @hide
+ */
+ public static final int DEVICE_TYPE_BLUETOOTH = -1;
+
+ /**
+ * A receiver device type of the route indicating the presentation of the media is happening
+ * on a TV.
+ *
+ * @see #getDeviceType
+ */
+ public static final int DEVICE_TYPE_TV = 1;
+
+ /**
+ * A receiver device type of the route indicating the presentation of the media is happening
+ * on a speaker.
+ *
+ * @see #getDeviceType
+ */
+ public static final int DEVICE_TYPE_SPEAKER = 2;
+
+ /** @hide */
@IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
private @interface PlaybackVolume {}
@@ -828,10 +903,20 @@
*/
public static final int PLAYBACK_VOLUME_VARIABLE = 1;
+ /**
+ * The default presentation display id indicating no presentation display is associated
+ * with the route.
+ * @hide
+ */
+ public static final int PRESENTATION_DISPLAY_ID_NONE = -1;
+
static final int CHANGE_GENERAL = 1 << 0;
static final int CHANGE_VOLUME = 1 << 1;
static final int CHANGE_PRESENTATION_DISPLAY = 1 << 2;
+ // Should match to SystemMediaRouteProvider.PACKAGE_NAME.
+ static final String SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME = "android";
+
RouteInfo(ProviderInfo provider, String descriptorId, String uniqueId) {
mProvider = provider;
mDescriptorId = descriptorId;
@@ -889,6 +974,18 @@
}
/**
+ * Gets the URI of the icon representing this route.
+ * <p>
+ * This icon will be used in picker UIs if available.
+ * </p>
+ *
+ * @return The URI of the icon representing this route, or null if none.
+ */
+ public Uri getIconUri() {
+ return mIconUri;
+ }
+
+ /**
* Returns true if this route is enabled and may be selected.
*
* @return True if this route is enabled.
@@ -908,6 +1005,17 @@
}
/**
+ * Gets the connection state of the route.
+ *
+ * @return The connection state of this route: {@link #CONNECTION_STATE_DISCONNECTED},
+ * {@link #CONNECTION_STATE_CONNECTING}, or {@link #CONNECTION_STATE_CONNECTED}.
+ */
+ @ConnectionState
+ public int getConnectionState() {
+ return mConnectionState;
+ }
+
+ /**
* Returns true if this route is currently selected.
*
* @return True if this route is currently selected.
@@ -1113,6 +1221,43 @@
}
/**
+ * Gets the type of the receiver device associated with this route.
+ *
+ * @return The type of the receiver device associated with this route:
+ * {@link #DEVICE_TYPE_TV} or {@link #DEVICE_TYPE_SPEAKER}.
+ */
+ public int getDeviceType() {
+ return mDeviceType;
+ }
+
+
+ /**
+ * Gets whether the type of the receiver device associated with this route is
+ * {@link #DEVICE_TYPE_BLUETOOTH}.
+ * <p>
+ * This is a workaround for platform version 23 or below where the system route provider
+ * doesn't specify device type for bluetooth media routes.
+ * </p>
+ *
+ * @return True if the receiver device type can be assumed to be
+ * {@link #DEVICE_TYPE_BLUETOOTH}, false otherwise.
+ * @hide
+ */
+ public boolean isDeviceTypeBluetooth() {
+ if (mDeviceType == DEVICE_TYPE_BLUETOOTH) {
+ return true;
+ }
+ return isSystemMediaRouteProvider(this)
+ && supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
+ && !supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO);
+ }
+
+ private static boolean isSystemMediaRouteProvider(MediaRouter.RouteInfo route) {
+ return TextUtils.equals(route.getProviderInstance().getMetadata().getPackageName(),
+ SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME);
+ }
+
+ /**
* Gets information about how volume is handled on the route.
*
* @return How volume is handled on the route: {@link #PLAYBACK_VOLUME_FIXED}
@@ -1223,6 +1368,14 @@
}
/**
+ * Gets the route's presentation display id, or -1 if none.
+ * @hide
+ */
+ public int getPresentationDisplayId() {
+ return mPresentationDisplayId;
+ }
+
+ /**
* Gets a collection of extra properties about this route that were supplied
* by its media route provider, or null if none.
*/
@@ -1253,11 +1406,14 @@
return "MediaRouter.RouteInfo{ uniqueId=" + mUniqueId
+ ", name=" + mName
+ ", description=" + mDescription
+ + ", iconUri=" + mIconUri
+ ", enabled=" + mEnabled
+ ", connecting=" + mConnecting
+ + ", connectionState=" + mConnectionState
+ ", canDisconnect=" + mCanDisconnect
+ ", playbackType=" + mPlaybackType
+ ", playbackStream=" + mPlaybackStream
+ + ", deviceType=" + mDeviceType
+ ", volumeHandling=" + mVolumeHandling
+ ", volume=" + mVolume
+ ", volumeMax=" + mVolumeMax
@@ -1268,69 +1424,87 @@
+ " }";
}
- int updateDescriptor(MediaRouteDescriptor descriptor) {
+ int maybeUpdateDescriptor(MediaRouteDescriptor descriptor) {
int changes = 0;
if (mDescriptor != descriptor) {
- mDescriptor = descriptor;
- if (descriptor != null) {
- if (!equal(mName, descriptor.getName())) {
- mName = descriptor.getName();
- changes |= CHANGE_GENERAL;
- }
- if (!equal(mDescription, descriptor.getDescription())) {
- mDescription = descriptor.getDescription();
- changes |= CHANGE_GENERAL;
- }
- if (mEnabled != descriptor.isEnabled()) {
- mEnabled = descriptor.isEnabled();
- changes |= CHANGE_GENERAL;
- }
- if (mConnecting != descriptor.isConnecting()) {
- mConnecting = descriptor.isConnecting();
- changes |= CHANGE_GENERAL;
- }
- if (!mControlFilters.equals(descriptor.getControlFilters())) {
- mControlFilters.clear();
- mControlFilters.addAll(descriptor.getControlFilters());
- changes |= CHANGE_GENERAL;
- }
- if (mPlaybackType != descriptor.getPlaybackType()) {
- mPlaybackType = descriptor.getPlaybackType();
- changes |= CHANGE_GENERAL;
- }
- if (mPlaybackStream != descriptor.getPlaybackStream()) {
- mPlaybackStream = descriptor.getPlaybackStream();
- changes |= CHANGE_GENERAL;
- }
- if (mVolumeHandling != descriptor.getVolumeHandling()) {
- mVolumeHandling = descriptor.getVolumeHandling();
- changes |= CHANGE_GENERAL | CHANGE_VOLUME;
- }
- if (mVolume != descriptor.getVolume()) {
- mVolume = descriptor.getVolume();
- changes |= CHANGE_GENERAL | CHANGE_VOLUME;
- }
- if (mVolumeMax != descriptor.getVolumeMax()) {
- mVolumeMax = descriptor.getVolumeMax();
- changes |= CHANGE_GENERAL | CHANGE_VOLUME;
- }
- if (mPresentationDisplayId != descriptor.getPresentationDisplayId()) {
- mPresentationDisplayId = descriptor.getPresentationDisplayId();
- mPresentationDisplay = null;
- changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
- }
- if (!equal(mExtras, descriptor.getExtras())) {
- mExtras = descriptor.getExtras();
- changes |= CHANGE_GENERAL;
- }
- if (!equal(mSettingsIntent, descriptor.getSettingsActivity())) {
- mSettingsIntent = descriptor.getSettingsActivity();
- changes |= CHANGE_GENERAL;
- }
- if (mCanDisconnect != descriptor.canDisconnectAndKeepPlaying()) {
- mCanDisconnect = descriptor.canDisconnectAndKeepPlaying();
- changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
- }
+ changes = updateDescriptor(descriptor);
+ }
+ return changes;
+ }
+
+ int updateDescriptor(MediaRouteDescriptor descriptor) {
+ int changes = 0;
+ mDescriptor = descriptor;
+ if (descriptor != null) {
+ if (!equal(mName, descriptor.getName())) {
+ mName = descriptor.getName();
+ changes |= CHANGE_GENERAL;
+ }
+ if (!equal(mDescription, descriptor.getDescription())) {
+ mDescription = descriptor.getDescription();
+ changes |= CHANGE_GENERAL;
+ }
+ if (!equal(mIconUri, descriptor.getIconUri())) {
+ mIconUri = descriptor.getIconUri();
+ changes |= CHANGE_GENERAL;
+ }
+ if (mEnabled != descriptor.isEnabled()) {
+ mEnabled = descriptor.isEnabled();
+ changes |= CHANGE_GENERAL;
+ }
+ if (mConnecting != descriptor.isConnecting()) {
+ mConnecting = descriptor.isConnecting();
+ changes |= CHANGE_GENERAL;
+ }
+ if (mConnectionState != descriptor.getConnectionState()) {
+ mConnectionState = descriptor.getConnectionState();
+ changes |= CHANGE_GENERAL;
+ }
+ if (!mControlFilters.equals(descriptor.getControlFilters())) {
+ mControlFilters.clear();
+ mControlFilters.addAll(descriptor.getControlFilters());
+ changes |= CHANGE_GENERAL;
+ }
+ if (mPlaybackType != descriptor.getPlaybackType()) {
+ mPlaybackType = descriptor.getPlaybackType();
+ changes |= CHANGE_GENERAL;
+ }
+ if (mPlaybackStream != descriptor.getPlaybackStream()) {
+ mPlaybackStream = descriptor.getPlaybackStream();
+ changes |= CHANGE_GENERAL;
+ }
+ if (mDeviceType != descriptor.getDeviceType()) {
+ mDeviceType = descriptor.getDeviceType();
+ changes |= CHANGE_GENERAL;
+ }
+ if (mVolumeHandling != descriptor.getVolumeHandling()) {
+ mVolumeHandling = descriptor.getVolumeHandling();
+ changes |= CHANGE_GENERAL | CHANGE_VOLUME;
+ }
+ if (mVolume != descriptor.getVolume()) {
+ mVolume = descriptor.getVolume();
+ changes |= CHANGE_GENERAL | CHANGE_VOLUME;
+ }
+ if (mVolumeMax != descriptor.getVolumeMax()) {
+ mVolumeMax = descriptor.getVolumeMax();
+ changes |= CHANGE_GENERAL | CHANGE_VOLUME;
+ }
+ if (mPresentationDisplayId != descriptor.getPresentationDisplayId()) {
+ mPresentationDisplayId = descriptor.getPresentationDisplayId();
+ mPresentationDisplay = null;
+ changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
+ }
+ if (!equal(mExtras, descriptor.getExtras())) {
+ mExtras = descriptor.getExtras();
+ changes |= CHANGE_GENERAL;
+ }
+ if (!equal(mSettingsIntent, descriptor.getSettingsActivity())) {
+ mSettingsIntent = descriptor.getSettingsActivity();
+ changes |= CHANGE_GENERAL;
+ }
+ if (mCanDisconnect != descriptor.canDisconnectAndKeepPlaying()) {
+ mCanDisconnect = descriptor.canDisconnectAndKeepPlaying();
+ changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
}
}
return changes;
@@ -1340,12 +1514,91 @@
return mDescriptorId;
}
- MediaRouteProvider getProviderInstance() {
+ /** @hide */
+ public MediaRouteProvider getProviderInstance() {
return mProvider.getProviderInstance();
}
}
/**
+ * Information about a route that consists of multiple other routes in a group.
+ * @hide
+ */
+ public static class RouteGroup extends RouteInfo {
+ private List<RouteInfo> mRoutes = new ArrayList<>();
+
+ RouteGroup(ProviderInfo provider, String descriptorId, String uniqueId) {
+ super(provider, descriptorId, uniqueId);
+ }
+
+ /**
+ * @return The number of routes in this group
+ */
+ public int getRouteCount() {
+ return mRoutes.size();
+ }
+
+ /**
+ * Returns the route in this group at the specified index
+ *
+ * @param index Index to fetch
+ * @return The route at index
+ */
+ public RouteInfo getRouteAt(int index) {
+ return mRoutes.get(index);
+ }
+
+ /**
+ * Returns the routes in this group
+ *
+ * @return The list of the routes in this group
+ */
+ public List<RouteInfo> getRoutes() {
+ return mRoutes;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(super.toString());
+ sb.append('[');
+ final int count = mRoutes.size();
+ for (int i = 0; i < count; i++) {
+ if (i > 0) sb.append(", ");
+ sb.append(mRoutes.get(i));
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ @Override
+ int maybeUpdateDescriptor(MediaRouteDescriptor descriptor) {
+ boolean changed = false;
+ if (mDescriptor != descriptor) {
+ mDescriptor = descriptor;
+ if (descriptor != null) {
+ List<String> groupMemberIds = descriptor.getGroupMemberIds();
+ List<RouteInfo> routes = new ArrayList<>();
+ changed = groupMemberIds.size() != mRoutes.size();
+ for (String groupMemberId : groupMemberIds) {
+ String uniqueId = sGlobal.getUniqueId(getProvider(), groupMemberId);
+ RouteInfo groupMember = sGlobal.getRoute(uniqueId);
+ if (groupMember != null) {
+ routes.add(groupMember);
+ if (!changed && !mRoutes.contains(groupMember)) {
+ changed = true;
+ }
+ }
+ }
+ if (changed) {
+ mRoutes = routes;
+ }
+ }
+ }
+ return (changed ? CHANGE_GENERAL : 0) | super.updateDescriptor(descriptor);
+ }
+ }
+
+ /**
* Provides information about a media route provider.
* <p>
* This object may be used to determine which media route provider has
@@ -1354,7 +1607,7 @@
*/
public static final class ProviderInfo {
private final MediaRouteProvider mProviderInstance;
- private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+ private final List<RouteInfo> mRoutes = new ArrayList<>();
private final ProviderMetadata mMetadata;
private MediaRouteProviderDescriptor mDescriptor;
@@ -1602,13 +1855,12 @@
implements SystemMediaRouteProvider.SyncCallback,
RegisteredMediaRouteProviderWatcher.Callback {
private final Context mApplicationContext;
- private final ArrayList<WeakReference<MediaRouter>> mRouters =
- new ArrayList<WeakReference<MediaRouter>>();
- private final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
- private final ArrayList<ProviderInfo> mProviders =
- new ArrayList<ProviderInfo>();
+ private final ArrayList<WeakReference<MediaRouter>> mRouters = new ArrayList<>();
+ private final ArrayList<RouteInfo> mRoutes = new ArrayList<>();
+ private final Map<Pair<String, String>, String> mUniqueIdMap = new HashMap<>();
+ private final ArrayList<ProviderInfo> mProviders = new ArrayList<>();
private final ArrayList<RemoteControlClientRecord> mRemoteControlClients =
- new ArrayList<RemoteControlClientRecord>();
+ new ArrayList<>();
private final RemoteControlClientCompat.PlaybackInfo mPlaybackInfo =
new RemoteControlClientCompat.PlaybackInfo();
private final ProviderCallback mProviderCallback = new ProviderCallback();
@@ -1620,7 +1872,8 @@
private RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher;
private RouteInfo mDefaultRoute;
private RouteInfo mSelectedRoute;
- private MediaRouteProvider.RouteController mSelectedRouteController;
+ private RouteController mSelectedRouteController;
+ private Map<String, RouteController> mGroupMemberControllers;
private MediaRouteDiscoveryRequest mDiscoveryRequest;
private MediaSessionRecord mMediaSession;
private MediaSessionCompat mRccMediaSession;
@@ -1711,6 +1964,11 @@
public void requestSetVolume(RouteInfo route, int volume) {
if (route == mSelectedRoute && mSelectedRouteController != null) {
mSelectedRouteController.onSetVolume(volume);
+ } else if (mGroupMemberControllers != null) {
+ RouteController controller = mGroupMemberControllers.get(route.mDescriptorId);
+ if (controller != null) {
+ controller.onSetVolume(volume);
+ }
}
}
@@ -1720,6 +1978,15 @@
}
}
+ public RouteInfo getRoute(String uniqueId) {
+ for (RouteInfo info : mRoutes) {
+ if (info.mUniqueId.equals(uniqueId)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
public List<RouteInfo> getRoutes() {
return mRoutes;
}
@@ -1930,6 +2197,11 @@
final List<MediaRouteDescriptor> routeDescriptors =
providerDescriptor.getRoutes();
final int routeCount = routeDescriptors.size();
+ // Updating route group's contents requires all member routes' information.
+ // Add the groups to the lists and update them later.
+ List<Pair<RouteInfo, MediaRouteDescriptor>> addedGroups = new ArrayList<>();
+ List<Pair<RouteInfo, MediaRouteDescriptor>> updatedGroups =
+ new ArrayList<>();
for (int i = 0; i < routeCount; i++) {
final MediaRouteDescriptor routeDescriptor = routeDescriptors.get(i);
final String id = routeDescriptor.getId();
@@ -1937,16 +2209,23 @@
if (sourceIndex < 0) {
// 1. Add the route to the list.
String uniqueId = assignRouteUniqueId(provider, id);
- RouteInfo route = new RouteInfo(provider, id, uniqueId);
+ boolean isGroup = routeDescriptor.getGroupMemberIds() != null;
+ RouteInfo route = isGroup ? new RouteGroup(provider, id, uniqueId) :
+ new RouteInfo(provider, id, uniqueId);
provider.mRoutes.add(targetIndex++, route);
mRoutes.add(route);
// 2. Create the route's contents.
- route.updateDescriptor(routeDescriptor);
- // 3. Notify clients about addition.
- if (DEBUG) {
- Log.d(TAG, "Route added: " + route);
+ if (isGroup) {
+ addedGroups.add(new Pair(route, routeDescriptor));
+ } else {
+ route.maybeUpdateDescriptor(routeDescriptor);
+ // 3. Notify clients about addition.
+ if (DEBUG) {
+ Log.d(TAG, "Route added: " + route);
+ }
+ mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route);
}
- mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route);
+
} else if (sourceIndex < targetIndex) {
Log.w(TAG, "Ignoring route descriptor with duplicate id: "
+ routeDescriptor);
@@ -1956,34 +2235,33 @@
Collections.swap(provider.mRoutes,
sourceIndex, targetIndex++);
// 2. Update the route's contents.
- int changes = route.updateDescriptor(routeDescriptor);
- // 3. Notify clients about changes.
- if (changes != 0) {
- if ((changes & RouteInfo.CHANGE_GENERAL) != 0) {
- if (DEBUG) {
- Log.d(TAG, "Route changed: " + route);
+ if (route instanceof RouteGroup) {
+ updatedGroups.add(new Pair(route, routeDescriptor));
+ } else {
+ // 3. Notify clients about changes.
+ if (updateRouteDescriptorAndNotify(route, routeDescriptor)
+ != 0) {
+ if (route == mSelectedRoute) {
+ selectedRouteDescriptorChanged = true;
}
- mCallbackHandler.post(
- CallbackHandler.MSG_ROUTE_CHANGED, route);
}
- if ((changes & RouteInfo.CHANGE_VOLUME) != 0) {
- if (DEBUG) {
- Log.d(TAG, "Route volume changed: " + route);
- }
- mCallbackHandler.post(
- CallbackHandler.MSG_ROUTE_VOLUME_CHANGED, route);
- }
- if ((changes & RouteInfo.CHANGE_PRESENTATION_DISPLAY) != 0) {
- if (DEBUG) {
- Log.d(TAG, "Route presentation display changed: "
- + route);
- }
- mCallbackHandler.post(CallbackHandler.
- MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED, route);
- }
- if (route == mSelectedRoute) {
- selectedRouteDescriptorChanged = true;
- }
+ }
+ }
+ }
+ // Update the new and/or existing groups.
+ for (Pair<RouteInfo, MediaRouteDescriptor> pair : addedGroups) {
+ RouteInfo route = pair.first;
+ route.maybeUpdateDescriptor(pair.second);
+ if (DEBUG) {
+ Log.d(TAG, "Route added: " + route);
+ }
+ mCallbackHandler.post(CallbackHandler.MSG_ROUTE_ADDED, route);
+ }
+ for (Pair<RouteInfo, MediaRouteDescriptor> pair : updatedGroups) {
+ RouteInfo route = pair.first;
+ if (updateRouteDescriptorAndNotify(route, pair.second) != 0) {
+ if (route == mSelectedRoute) {
+ selectedRouteDescriptorChanged = true;
}
}
}
@@ -1996,7 +2274,7 @@
for (int i = provider.mRoutes.size() - 1; i >= targetIndex; i--) {
// 1. Delete the route's contents.
RouteInfo route = provider.mRoutes.get(i);
- route.updateDescriptor(null);
+ route.maybeUpdateDescriptor(null);
// 2. Remove the route from the list.
mRoutes.remove(route);
}
@@ -2025,18 +2303,52 @@
}
}
+ private int updateRouteDescriptorAndNotify(RouteInfo route,
+ MediaRouteDescriptor routeDescriptor) {
+ int changes = route.maybeUpdateDescriptor(routeDescriptor);
+ if (changes != 0) {
+ if ((changes & RouteInfo.CHANGE_GENERAL) != 0) {
+ if (DEBUG) {
+ Log.d(TAG, "Route changed: " + route);
+ }
+ mCallbackHandler.post(
+ CallbackHandler.MSG_ROUTE_CHANGED, route);
+ }
+ if ((changes & RouteInfo.CHANGE_VOLUME) != 0) {
+ if (DEBUG) {
+ Log.d(TAG, "Route volume changed: " + route);
+ }
+ mCallbackHandler.post(
+ CallbackHandler.MSG_ROUTE_VOLUME_CHANGED, route);
+ }
+ if ((changes & RouteInfo.CHANGE_PRESENTATION_DISPLAY) != 0) {
+ if (DEBUG) {
+ Log.d(TAG, "Route presentation display changed: "
+ + route);
+ }
+ mCallbackHandler.post(CallbackHandler.
+ MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED, route);
+ }
+ }
+ return changes;
+ }
+
private String assignRouteUniqueId(ProviderInfo provider, String routeDescriptorId) {
// Although route descriptor ids are unique within a provider, it's
// possible for there to be two providers with the same package name.
// Therefore we must dedupe the composite id.
- String uniqueId = provider.getComponentName().flattenToShortString()
- + ":" + routeDescriptorId;
+ String componentName = provider.getComponentName().flattenToShortString();
+ String uniqueId = componentName + ":" + routeDescriptorId;
if (findRouteByUniqueId(uniqueId) < 0) {
+ mUniqueIdMap.put(new Pair(componentName, routeDescriptorId), uniqueId);
return uniqueId;
}
+ Log.w(TAG, "Either " + routeDescriptorId + " isn't unique in " + componentName
+ + " or we're trying to assign a unique ID for an already added route");
for (int i = 2; ; i++) {
String newUniqueId = String.format(Locale.US, "%s_%d", uniqueId, i);
if (findRouteByUniqueId(newUniqueId) < 0) {
+ mUniqueIdMap.put(new Pair(componentName, routeDescriptorId), newUniqueId);
return newUniqueId;
}
}
@@ -2052,6 +2364,11 @@
return -1;
}
+ private String getUniqueId(ProviderInfo provider, String routeDescriptorId) {
+ String componentName = provider.getComponentName().flattenToShortString();
+ return mUniqueIdMap.get(new Pair(componentName, routeDescriptorId));
+ }
+
private void updateSelectedRouteIfNeeded(boolean selectedRouteDescriptorChanged) {
// Update default route.
if (mDefaultRoute != null && !isRouteSelectable(mDefaultRoute)) {
@@ -2134,6 +2451,13 @@
mSelectedRouteController.onRelease();
mSelectedRouteController = null;
}
+ if (mGroupMemberControllers != null) {
+ for (RouteController controller : mGroupMemberControllers.values()) {
+ controller.onUnselect();
+ controller.onRelease();
+ }
+ mGroupMemberControllers = null;
+ }
}
mSelectedRoute = route;
@@ -2148,6 +2472,17 @@
Log.d(TAG, "Route selected: " + mSelectedRoute);
}
mCallbackHandler.post(CallbackHandler.MSG_ROUTE_SELECTED, mSelectedRoute);
+
+ if (mSelectedRoute instanceof RouteGroup) {
+ mGroupMemberControllers = new HashMap<>();
+ RouteGroup group = (RouteGroup) mSelectedRoute;
+ for (RouteInfo groupMember : group.getRoutes()) {
+ RouteController controller = groupMember.getProviderInstance()
+ .onCreateRouteController(groupMember.mDescriptorId);
+ controller.onSelect();
+ mGroupMemberControllers.put(groupMember.mDescriptorId, controller);
+ }
+ }
}
updatePlaybackInfoFromSelectedRoute();
diff --git a/v7/palette/api/23.txt b/v7/palette/api/23.0.0.txt
similarity index 100%
rename from v7/palette/api/23.txt
rename to v7/palette/api/23.0.0.txt
diff --git a/v7/palette/api/23.1.0.txt b/v7/palette/api/23.1.0.txt
new file mode 100644
index 0000000..fac6a55
--- /dev/null
+++ b/v7/palette/api/23.1.0.txt
@@ -0,0 +1,56 @@
+package android.support.v7.graphics {
+
+ public final class Palette {
+ method public static android.support.v7.graphics.Palette.Builder from(android.graphics.Bitmap);
+ method public static android.support.v7.graphics.Palette from(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+ method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap);
+ method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap, int);
+ method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, android.support.v7.graphics.Palette.PaletteAsyncListener);
+ method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, int, android.support.v7.graphics.Palette.PaletteAsyncListener);
+ method public int getDarkMutedColor(int);
+ method public android.support.v7.graphics.Palette.Swatch getDarkMutedSwatch();
+ method public int getDarkVibrantColor(int);
+ method public android.support.v7.graphics.Palette.Swatch getDarkVibrantSwatch();
+ method public int getLightMutedColor(int);
+ method public android.support.v7.graphics.Palette.Swatch getLightMutedSwatch();
+ method public int getLightVibrantColor(int);
+ method public android.support.v7.graphics.Palette.Swatch getLightVibrantSwatch();
+ method public int getMutedColor(int);
+ method public android.support.v7.graphics.Palette.Swatch getMutedSwatch();
+ method public java.util.List<android.support.v7.graphics.Palette.Swatch> getSwatches();
+ method public int getVibrantColor(int);
+ method public android.support.v7.graphics.Palette.Swatch getVibrantSwatch();
+ }
+
+ public static final class Palette.Builder {
+ ctor public Palette.Builder(android.graphics.Bitmap);
+ ctor public Palette.Builder(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+ method public android.support.v7.graphics.Palette.Builder addFilter(android.support.v7.graphics.Palette.Filter);
+ method public android.support.v7.graphics.Palette.Builder clearFilters();
+ method public android.support.v7.graphics.Palette.Builder clearRegion();
+ method public android.support.v7.graphics.Palette generate();
+ method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generate(android.support.v7.graphics.Palette.PaletteAsyncListener);
+ method public android.support.v7.graphics.Palette.Builder maximumColorCount(int);
+ method public android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+ method public android.support.v7.graphics.Palette.Builder setRegion(int, int, int, int);
+ }
+
+ public static abstract interface Palette.Filter {
+ method public abstract boolean isAllowed(int, float[]);
+ }
+
+ public static abstract interface Palette.PaletteAsyncListener {
+ method public abstract void onGenerated(android.support.v7.graphics.Palette);
+ }
+
+ public static final class Palette.Swatch {
+ ctor public Palette.Swatch(int, int);
+ method public int getBodyTextColor();
+ method public float[] getHsl();
+ method public int getPopulation();
+ method public int getRgb();
+ method public int getTitleTextColor();
+ }
+
+}
+
diff --git a/v7/palette/api/current.txt b/v7/palette/api/current.txt
index 1b6c745..3b24b77 100644
--- a/v7/palette/api/current.txt
+++ b/v7/palette/api/current.txt
@@ -7,6 +7,7 @@
method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap, int);
method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, android.support.v7.graphics.Palette.PaletteAsyncListener);
method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, int, android.support.v7.graphics.Palette.PaletteAsyncListener);
+ method public int getColorForTarget(android.support.v7.graphics.Target, int);
method public int getDarkMutedColor(int);
method public android.support.v7.graphics.Palette.Swatch getDarkMutedSwatch();
method public int getDarkVibrantColor(int);
@@ -17,7 +18,9 @@
method public android.support.v7.graphics.Palette.Swatch getLightVibrantSwatch();
method public int getMutedColor(int);
method public android.support.v7.graphics.Palette.Swatch getMutedSwatch();
+ method public android.support.v7.graphics.Palette.Swatch getSwatchForTarget(android.support.v7.graphics.Target);
method public java.util.List<android.support.v7.graphics.Palette.Swatch> getSwatches();
+ method public java.util.List<android.support.v7.graphics.Target> getTargets();
method public int getVibrantColor(int);
method public android.support.v7.graphics.Palette.Swatch getVibrantSwatch();
}
@@ -26,11 +29,16 @@
ctor public Palette.Builder(android.graphics.Bitmap);
ctor public Palette.Builder(java.util.List<android.support.v7.graphics.Palette.Swatch>);
method public android.support.v7.graphics.Palette.Builder addFilter(android.support.v7.graphics.Palette.Filter);
+ method public android.support.v7.graphics.Palette.Builder addTarget(android.support.v7.graphics.Target);
method public android.support.v7.graphics.Palette.Builder clearFilters();
+ method public android.support.v7.graphics.Palette.Builder clearRegion();
+ method public android.support.v7.graphics.Palette.Builder clearTargets();
method public android.support.v7.graphics.Palette generate();
method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generate(android.support.v7.graphics.Palette.PaletteAsyncListener);
method public android.support.v7.graphics.Palette.Builder maximumColorCount(int);
- method public android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+ method public android.support.v7.graphics.Palette.Builder resizeBitmapArea(int);
+ method public deprecated android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+ method public android.support.v7.graphics.Palette.Builder setRegion(int, int, int, int);
}
public static abstract interface Palette.Filter {
@@ -50,5 +58,40 @@
method public int getTitleTextColor();
}
+ public final class Target {
+ method public float getLightnessWeight();
+ method public float getMaximumLightness();
+ method public float getMaximumSaturation();
+ method public float getMinimumLightness();
+ method public float getMinimumSaturation();
+ method public float getPopulationWeight();
+ method public float getSaturationWeight();
+ method public float getTargetLightness();
+ method public float getTargetSaturation();
+ method public boolean isExclusive();
+ field public static final android.support.v7.graphics.Target DARK_MUTED;
+ field public static final android.support.v7.graphics.Target DARK_VIBRANT;
+ field public static final android.support.v7.graphics.Target LIGHT_MUTED;
+ field public static final android.support.v7.graphics.Target LIGHT_VIBRANT;
+ field public static final android.support.v7.graphics.Target MUTED;
+ field public static final android.support.v7.graphics.Target VIBRANT;
+ }
+
+ public static final class Target.Builder {
+ ctor public Target.Builder();
+ ctor public Target.Builder(android.support.v7.graphics.Target);
+ method public android.support.v7.graphics.Target build();
+ method public android.support.v7.graphics.Target.Builder setExclusive(boolean);
+ method public android.support.v7.graphics.Target.Builder setLightnessWeight(float);
+ method public android.support.v7.graphics.Target.Builder setMaximumLightness(float);
+ method public android.support.v7.graphics.Target.Builder setMaximumSaturation(float);
+ method public android.support.v7.graphics.Target.Builder setMinimumLightness(float);
+ method public android.support.v7.graphics.Target.Builder setMinimumSaturation(float);
+ method public android.support.v7.graphics.Target.Builder setPopulationWeight(float);
+ method public android.support.v7.graphics.Target.Builder setSaturationWeight(float);
+ method public android.support.v7.graphics.Target.Builder setTargetLightness(float);
+ method public android.support.v7.graphics.Target.Builder setTargetSaturation(float);
+ }
+
}
diff --git a/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java b/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java
index dc0ec1d..3635c3e 100644
--- a/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java
+++ b/v7/palette/src/androidTest/java/android/support/v7/graphics/BucketTests.java
@@ -66,4 +66,72 @@
assertEquals(swatches, p.getSwatches());
}
+
+ public void testRegionWhole() {
+ Palette.Builder b = new Palette.Builder(mSource);
+ b.setRegion(0, 0, mSource.getWidth(), mSource.getHeight());
+
+ Throwable thrown = null;
+ try {
+ b.generate();
+ } catch (Exception e) {
+ thrown = e;
+ }
+ assertNull(thrown);
+ }
+
+ public void testRegionUpperLeft() {
+ Palette.Builder b = new Palette.Builder(mSource);
+ b.setRegion(0, 0, mSource.getWidth() / 2, mSource.getHeight() / 2);
+
+ Throwable thrown = null;
+ try {
+ b.generate();
+ } catch (Exception e) {
+ thrown = e;
+ }
+ assertNull(thrown);
+ }
+
+ public void testRegionBottomRight() {
+ Palette.Builder b = new Palette.Builder(mSource);
+ b.setRegion(mSource.getWidth() / 2, mSource.getHeight() / 2,
+ mSource.getWidth(), mSource.getHeight());
+
+ Throwable thrown = null;
+ try {
+ b.generate();
+ } catch (Exception e) {
+ thrown = e;
+ }
+ assertNull(thrown);
+ }
+
+ public void testOnePixelTallBitmap() {
+ Bitmap bitmap = Bitmap.createBitmap(1000, 1, Bitmap.Config.ARGB_8888);
+
+ Palette.Builder b = new Palette.Builder(bitmap);
+
+ Throwable thrown = null;
+ try {
+ b.generate();
+ } catch (Exception e) {
+ thrown = e;
+ }
+ assertNull(thrown);
+ }
+
+ public void testOnePixelWideBitmap() {
+ Bitmap bitmap = Bitmap.createBitmap(1, 1000, Bitmap.Config.ARGB_8888);
+
+ Palette.Builder b = new Palette.Builder(bitmap);
+
+ Throwable thrown = null;
+ try {
+ b.generate();
+ } catch (Exception e) {
+ thrown = e;
+ }
+ assertNull(thrown);
+ }
}
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java b/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java
deleted file mode 100644
index 3ee2bfa..0000000
--- a/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package android.support.v7.graphics;
-
-import android.support.v4.graphics.ColorUtils;
-import android.support.v7.graphics.Palette.Swatch;
-
-import java.util.List;
-
-class DefaultGenerator extends Palette.Generator {
-
- private static final float TARGET_DARK_LUMA = 0.26f;
- private static final float MAX_DARK_LUMA = 0.45f;
-
- private static final float MIN_LIGHT_LUMA = 0.55f;
- private static final float TARGET_LIGHT_LUMA = 0.74f;
-
- private static final float MIN_NORMAL_LUMA = 0.3f;
- private static final float TARGET_NORMAL_LUMA = 0.5f;
- private static final float MAX_NORMAL_LUMA = 0.7f;
-
- private static final float TARGET_MUTED_SATURATION = 0.3f;
- private static final float MAX_MUTED_SATURATION = 0.4f;
-
- private static final float TARGET_VIBRANT_SATURATION = 1f;
- private static final float MIN_VIBRANT_SATURATION = 0.35f;
-
- private static final float WEIGHT_SATURATION = 3f;
- private static final float WEIGHT_LUMA = 6f;
- private static final float WEIGHT_POPULATION = 1f;
-
- private List<Swatch> mSwatches;
-
- private int mHighestPopulation;
-
- private Swatch mVibrantSwatch;
- private Swatch mMutedSwatch;
- private Swatch mDarkVibrantSwatch;
- private Swatch mDarkMutedSwatch;
- private Swatch mLightVibrantSwatch;
- private Swatch mLightMutedSwatch;
-
- @Override
- public void generate(final List<Swatch> swatches) {
- mSwatches = swatches;
-
- mHighestPopulation = findMaxPopulation();
-
- generateVariationColors();
-
- // Now try and generate any missing colors
- generateEmptySwatches();
- }
-
- @Override
- public Swatch getVibrantSwatch() {
- return mVibrantSwatch;
- }
-
- @Override
- public Swatch getLightVibrantSwatch() {
- return mLightVibrantSwatch;
- }
-
- @Override
- public Swatch getDarkVibrantSwatch() {
- return mDarkVibrantSwatch;
- }
-
- @Override
- public Swatch getMutedSwatch() {
- return mMutedSwatch;
- }
-
- @Override
- public Swatch getLightMutedSwatch() {
- return mLightMutedSwatch;
- }
-
- @Override
- public Swatch getDarkMutedSwatch() {
- return mDarkMutedSwatch;
- }
-
- private void generateVariationColors() {
- mVibrantSwatch = findColorVariation(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
- TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
- mLightVibrantSwatch = findColorVariation(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
- TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
- mDarkVibrantSwatch = findColorVariation(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
- TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
- mMutedSwatch = findColorVariation(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
- TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
-
- mLightMutedSwatch = findColorVariation(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
- TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
-
- mDarkMutedSwatch = findColorVariation(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
- TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
- }
-
- /**
- * Try and generate any missing swatches from the swatches we did find.
- */
- private void generateEmptySwatches() {
- if (mVibrantSwatch == null) {
- // If we do not have a vibrant color...
- if (mDarkVibrantSwatch != null) {
- // ...but we do have a dark vibrant, generate the value by modifying the luma
- final float[] newHsl = copyHslValues(mDarkVibrantSwatch);
- newHsl[2] = TARGET_NORMAL_LUMA;
- mVibrantSwatch = new Swatch(ColorUtils.HSLToColor(newHsl), 0);
- }
- }
-
- if (mDarkVibrantSwatch == null) {
- // If we do not have a dark vibrant color...
- if (mVibrantSwatch != null) {
- // ...but we do have a vibrant, generate the value by modifying the luma
- final float[] newHsl = copyHslValues(mVibrantSwatch);
- newHsl[2] = TARGET_DARK_LUMA;
- mDarkVibrantSwatch = new Swatch(ColorUtils.HSLToColor(newHsl), 0);
- }
- }
- }
-
- /**
- * Find the {@link Palette.Swatch} with the highest population value and return the population.
- */
- private int findMaxPopulation() {
- int population = 0;
- for (Swatch swatch : mSwatches) {
- population = Math.max(population, swatch.getPopulation());
- }
- return population;
- }
-
- private Swatch findColorVariation(float targetLuma, float minLuma, float maxLuma,
- float targetSaturation, float minSaturation, float maxSaturation) {
- Swatch max = null;
- float maxValue = 0f;
-
- for (Swatch swatch : mSwatches) {
- final float sat = swatch.getHsl()[1];
- final float luma = swatch.getHsl()[2];
-
- if (sat >= minSaturation && sat <= maxSaturation &&
- luma >= minLuma && luma <= maxLuma &&
- !isAlreadySelected(swatch)) {
- float value = createComparisonValue(sat, targetSaturation, luma, targetLuma,
- swatch.getPopulation(), mHighestPopulation);
- if (max == null || value > maxValue) {
- max = swatch;
- maxValue = value;
- }
- }
- }
-
- return max;
- }
-
- /**
- * @return true if we have already selected {@code swatch}
- */
- private boolean isAlreadySelected(Swatch swatch) {
- return mVibrantSwatch == swatch || mDarkVibrantSwatch == swatch ||
- mLightVibrantSwatch == swatch || mMutedSwatch == swatch ||
- mDarkMutedSwatch == swatch || mLightMutedSwatch == swatch;
- }
-
- private static float createComparisonValue(float saturation, float targetSaturation,
- float luma, float targetLuma,
- int population, int maxPopulation) {
- return createComparisonValue(saturation, targetSaturation, WEIGHT_SATURATION,
- luma, targetLuma, WEIGHT_LUMA,
- population, maxPopulation, WEIGHT_POPULATION);
- }
-
- private static float createComparisonValue(
- float saturation, float targetSaturation, float saturationWeight,
- float luma, float targetLuma, float lumaWeight,
- int population, int maxPopulation, float populationWeight) {
- return weightedMean(
- invertDiff(saturation, targetSaturation), saturationWeight,
- invertDiff(luma, targetLuma), lumaWeight,
- population / (float) maxPopulation, populationWeight
- );
- }
-
- /**
- * Copy a {@link Swatch}'s HSL values into a new float[].
- */
- private static float[] copyHslValues(Swatch color) {
- final float[] newHsl = new float[3];
- System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
- return newHsl;
- }
-
- /**
- * Returns a value in the range 0-1. 1 is returned when {@code value} equals the
- * {@code targetValue} and then decreases as the absolute difference between {@code value} and
- * {@code targetValue} increases.
- *
- * @param value the item's value
- * @param targetValue the value which we desire
- */
- private static float invertDiff(float value, float targetValue) {
- return 1f - Math.abs(value - targetValue);
- }
-
- private static float weightedMean(float... values) {
- float sum = 0f;
- float sumWeight = 0f;
-
- for (int i = 0; i < values.length; i += 2) {
- float value = values[i];
- float weight = values[i + 1];
-
- sum += (value * weight);
- sumWeight += weight;
- }
-
- return sum / sumWeight;
- }
-}
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 1ffb7a1..d0dff30 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
@@ -18,17 +18,23 @@
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Rect;
import android.os.AsyncTask;
import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.graphics.ColorUtils;
import android.support.v4.os.AsyncTaskCompat;
+import android.support.v4.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseBooleanArray;
import android.util.TimingLogger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
/**
* A helper class to extract prominent colors from an image.
@@ -78,7 +84,7 @@
void onGenerated(Palette palette);
}
- private static final int DEFAULT_RESIZE_BITMAP_MAX_DIMENSION = 192;
+ private static final int DEFAULT_RESIZE_BITMAP_AREA = 160 * 160;
private static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
private static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
@@ -138,151 +144,266 @@
}
private final List<Swatch> mSwatches;
- private final Generator mGenerator;
+ private final List<Target> mTargets;
- private Palette(List<Swatch> swatches, Generator generator) {
+ private final Map<Target, Swatch> mSelectedSwatches;
+ private final SparseBooleanArray mUsedColors;
+
+ private final int mMaxPopulation;
+
+ private Palette(List<Swatch> swatches, List<Target> targets) {
mSwatches = swatches;
- mGenerator = generator;
+ mTargets = targets;
+
+ mUsedColors = new SparseBooleanArray();
+ mSelectedSwatches = new ArrayMap<>();
+
+ mMaxPopulation = findMaxPopulation();
}
/**
* Returns all of the swatches which make up the palette.
*/
+ @NonNull
public List<Swatch> getSwatches() {
return Collections.unmodifiableList(mSwatches);
}
/**
+ * Returns the targets used to generate this palette.
+ */
+ @NonNull
+ public List<Target> getTargets() {
+ return Collections.unmodifiableList(mTargets);
+ }
+
+ /**
* Returns the most vibrant swatch in the palette. Might be null.
+ *
+ * @see Target#VIBRANT
*/
@Nullable
public Swatch getVibrantSwatch() {
- return mGenerator.getVibrantSwatch();
+ return getSwatchForTarget(Target.VIBRANT);
}
/**
* Returns a light and vibrant swatch from the palette. Might be null.
+ *
+ * @see Target#LIGHT_VIBRANT
*/
@Nullable
public Swatch getLightVibrantSwatch() {
- return mGenerator.getLightVibrantSwatch();
+ return getSwatchForTarget(Target.LIGHT_VIBRANT);
}
/**
* Returns a dark and vibrant swatch from the palette. Might be null.
+ *
+ * @see Target#DARK_VIBRANT
*/
@Nullable
public Swatch getDarkVibrantSwatch() {
- return mGenerator.getDarkVibrantSwatch();
+ return getSwatchForTarget(Target.DARK_VIBRANT);
}
/**
* Returns a muted swatch from the palette. Might be null.
+ *
+ * @see Target#MUTED
*/
@Nullable
public Swatch getMutedSwatch() {
- return mGenerator.getMutedSwatch();
+ return getSwatchForTarget(Target.MUTED);
}
/**
* Returns a muted and light swatch from the palette. Might be null.
+ *
+ * @see Target#LIGHT_MUTED
*/
@Nullable
public Swatch getLightMutedSwatch() {
- return mGenerator.getLightMutedSwatch();
+ return getSwatchForTarget(Target.LIGHT_MUTED);
}
/**
* Returns a muted and dark swatch from the palette. Might be null.
+ *
+ * @see Target#DARK_MUTED
*/
@Nullable
public Swatch getDarkMutedSwatch() {
- return mGenerator.getDarkMutedSwatch();
+ return getSwatchForTarget(Target.DARK_MUTED);
}
/**
* Returns the most vibrant color in the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getVibrantSwatch()
*/
@ColorInt
- public int getVibrantColor(@ColorInt int defaultColor) {
- Swatch swatch = getVibrantSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.VIBRANT, defaultColor);
}
/**
* Returns a light and vibrant color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getLightVibrantSwatch()
*/
@ColorInt
- public int getLightVibrantColor(@ColorInt int defaultColor) {
- Swatch swatch = getLightVibrantSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getLightVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.LIGHT_VIBRANT, defaultColor);
}
/**
* Returns a dark and vibrant color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getDarkVibrantSwatch()
*/
@ColorInt
- public int getDarkVibrantColor(@ColorInt int defaultColor) {
- Swatch swatch = getDarkVibrantSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getDarkVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.DARK_VIBRANT, defaultColor);
}
/**
* Returns a muted color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getMutedSwatch()
*/
@ColorInt
- public int getMutedColor(@ColorInt int defaultColor) {
- Swatch swatch = getMutedSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.MUTED, defaultColor);
}
/**
* Returns a muted and light color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getLightMutedSwatch()
*/
@ColorInt
- public int getLightMutedColor(@ColorInt int defaultColor) {
- Swatch swatch = getLightMutedSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getLightMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.LIGHT_MUTED, defaultColor);
}
/**
* Returns a muted and dark color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getDarkMutedSwatch()
*/
@ColorInt
- public int getDarkMutedColor(@ColorInt int defaultColor) {
- Swatch swatch = getDarkMutedSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getDarkMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.DARK_MUTED, defaultColor);
}
/**
- * Scale the bitmap down so that it's largest dimension is {@code targetMaxDimension}.
- * If {@code bitmap} is smaller than this, then it is returned.
+ * Returns the selected swatch for the given target from the palette, or {@code null} if one
+ * could not be found.
*/
- private static Bitmap scaleBitmapDown(Bitmap bitmap, final int targetMaxDimension) {
- final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+ @Nullable
+ public Swatch getSwatchForTarget(@NonNull final Target target) {
+ return mSelectedSwatches.get(target);
+ }
- if (maxDimension <= targetMaxDimension) {
- // If the bitmap is small enough already, just return it
- return bitmap;
+ /**
+ * Returns the selected color for the given target from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getColorForTarget(@NonNull final Target target, @ColorInt final int defaultColor) {
+ Swatch swatch = getSwatchForTarget(target);
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ private 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++) {
+ final Target target = mTargets.get(i);
+ target.normalizeWeights();
+ mSelectedSwatches.put(target, generateScoredTarget(target));
+ }
+ // We now clear out the used colors
+ mUsedColors.clear();
+ }
+
+ private Swatch generateScoredTarget(final Target target) {
+ final Swatch maxScoreSwatch = getMaxScoredSwatchForTarget(target);
+ if (maxScoreSwatch != null && target.isExclusive()) {
+ // If we have a swatch, and the target is exclusive, add the color to the used list
+ mUsedColors.append(maxScoreSwatch.getRgb(), true);
+ }
+ return maxScoreSwatch;
+ }
+
+ private Swatch getMaxScoredSwatchForTarget(final Target target) {
+ float maxScore = 0;
+ Swatch maxScoreSwatch = null;
+ for (int i = 0, count = mSwatches.size(); i < count; i++) {
+ final Swatch swatch = mSwatches.get(i);
+ if (shouldBeScoredForTarget(swatch, target)) {
+ final float score = generateScore(swatch, target);
+ if (maxScoreSwatch == null || score > maxScore) {
+ maxScoreSwatch = swatch;
+ maxScore = score;
+ }
+ }
+ }
+ return maxScoreSwatch;
+ }
+
+ private boolean shouldBeScoredForTarget(final Swatch swatch, final Target target) {
+ // Check whether the HSL values are within the correct ranges, and this color hasn't
+ // been used yet.
+ final float hsl[] = swatch.getHsl();
+ return hsl[1] >= target.getMinimumSaturation() && hsl[1] <= target.getMaximumSaturation()
+ && hsl[2] >= target.getMinimumLightness() && hsl[2] <= target.getMaximumLightness()
+ && !mUsedColors.get(swatch.getRgb());
+ }
+
+ private float generateScore(Swatch swatch, Target target) {
+ final float[] hsl = swatch.getHsl();
+
+ float saturationScore = 0;
+ float luminanceScore = 0;
+ float populationScore = 0;
+
+ if (target.getSaturationWeight() > 0) {
+ saturationScore = target.getSaturationWeight()
+ * (1f - Math.abs(hsl[1] - target.getTargetSaturation()));
+ }
+ if (target.getLightnessWeight() > 0) {
+ luminanceScore = target.getLightnessWeight()
+ * (1f - Math.abs(hsl[2] - target.getTargetLightness()));
+ }
+ if (target.getPopulationWeight() > 0) {
+ populationScore = target.getPopulationWeight()
+ * (swatch.getPopulation() / (float) mMaxPopulation);
}
- final float scaleRatio = targetMaxDimension / (float) maxDimension;
- return Bitmap.createScaledBitmap(bitmap,
- Math.round(bitmap.getWidth() * scaleRatio),
- Math.round(bitmap.getHeight() * scaleRatio),
- false);
+ return saturationScore + luminanceScore + populationScore;
+ }
+
+ private int findMaxPopulation() {
+ int max = 0;
+ for (int i = 0, count = mSwatches.size(); i < count; i++) {
+ max = Math.max(mSwatches.get(i).getPopulation(), max);
+ }
+ return max;
+ }
+
+ private static float[] copyHslValues(Swatch color) {
+ final float[] newHsl = new float[3];
+ System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
+ return newHsl;
}
/**
@@ -316,6 +437,11 @@
mPopulation = population;
}
+ Swatch(float[] hsl, int population) {
+ this(ColorUtils.HSLToColor(hsl), population);
+ mHsl = hsl;
+ }
+
/**
* @return this swatch's RGB color value
*/
@@ -333,8 +459,8 @@
public float[] getHsl() {
if (mHsl == null) {
mHsl = new float[3];
- ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
}
+ ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
return mHsl;
}
@@ -441,23 +567,36 @@
* Builder class for generating {@link Palette} instances.
*/
public static final class Builder {
- private List<Swatch> mSwatches;
- private Bitmap mBitmap;
- private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
- private int mResizeMaxDimension = DEFAULT_RESIZE_BITMAP_MAX_DIMENSION;
- private final List<Filter> mFilters = new ArrayList<>();
+ private final List<Swatch> mSwatches;
+ private final Bitmap mBitmap;
- private Generator mGenerator;
+ private final List<Target> mTargets = new ArrayList<>();
+
+ private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
+ private int mResizeArea = DEFAULT_RESIZE_BITMAP_AREA;
+ private int mResizeMaxDimension = -1;
+
+ private final List<Filter> mFilters = new ArrayList<>();
+ private Rect mRegion;
/**
* Construct a new {@link Builder} using a source {@link Bitmap}
*/
public Builder(Bitmap bitmap) {
- this();
if (bitmap == null || bitmap.isRecycled()) {
throw new IllegalArgumentException("Bitmap is not valid");
}
+ mFilters.add(DEFAULT_FILTER);
mBitmap = bitmap;
+ mSwatches = null;
+
+ // Add the default targets
+ mTargets.add(Target.LIGHT_VIBRANT);
+ mTargets.add(Target.VIBRANT);
+ mTargets.add(Target.DARK_VIBRANT);
+ mTargets.add(Target.LIGHT_MUTED);
+ mTargets.add(Target.MUTED);
+ mTargets.add(Target.DARK_MUTED);
}
/**
@@ -465,24 +604,12 @@
* Typically only used for testing.
*/
public Builder(List<Swatch> swatches) {
- this();
if (swatches == null || swatches.isEmpty()) {
throw new IllegalArgumentException("List of Swatches is not valid");
}
- mSwatches = swatches;
- }
-
- private Builder() {
mFilters.add(DEFAULT_FILTER);
- }
-
- /**
- * Set the {@link Generator} to use when generating the {@link Palette}. If this is called
- * with {@code null} then the default generator will be used.
- */
- Builder generator(Generator generator) {
- mGenerator = generator;
- return this;
+ mSwatches = swatches;
+ mBitmap = null;
}
/**
@@ -493,6 +620,7 @@
* the range 10-16. For images which are largely made up of people's faces then this
* value should be increased to ~24.
*/
+ @NonNull
public Builder maximumColorCount(int colors) {
mMaxColors = colors;
return this;
@@ -503,13 +631,38 @@
* If the bitmap's largest dimension is greater than the value specified, then the bitmap
* will be resized so that it's largest dimension matches {@code maxDimension}. If the
* bitmap is smaller or equal, the original is used as-is.
+ *
+ * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
+ * abnormal aspect ratios more gracefully.
+ *
+ * @param maxDimension the number of pixels that the max dimension should be scaled down to,
+ * or any value <= 0 to disable resizing.
+ */
+ @NonNull
+ @Deprecated
+ public Builder resizeBitmapSize(final int maxDimension) {
+ mResizeMaxDimension = maxDimension;
+ mResizeArea = -1;
+ return this;
+ }
+
+ /**
+ * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
+ * If the bitmap's area is greater than the value specified, then the bitmap
+ * will be resized so that it's area matches {@code area}. If the
+ * bitmap is smaller or equal, the original is used as-is.
* <p>
* This value has a large effect on the processing time. The larger the resized image is,
* the greater time it will take to generate the palette. The smaller the image is, the
* more detail is lost in the resulting image and thus less precision for color selection.
+ *
+ * @param area the number of pixels that the intemediary scaled down Bitmap should cover,
+ * or any value <= 0 to disable resizing.
*/
- public Builder resizeBitmapSize(int maxDimension) {
- mResizeMaxDimension = maxDimension;
+ @NonNull
+ public Builder resizeBitmapArea(final int area) {
+ mResizeArea = area;
+ mResizeMaxDimension = -1;
return this;
}
@@ -517,17 +670,19 @@
* Clear all added filters. This includes any default filters added automatically by
* {@link Palette}.
*/
+ @NonNull
public Builder clearFilters() {
mFilters.clear();
return this;
}
/**
- * Add a filter to be able to have fine grained controlled over the colors which are
+ * Add a filter to be able to have fine grained control over which colors are
* allowed in the resulting palette.
*
* @param filter filter to add.
*/
+ @NonNull
public Builder addFilter(Filter filter) {
if (filter != null) {
mFilters.add(filter);
@@ -536,8 +691,67 @@
}
/**
+ * Set a region of the bitmap to be used exclusively when calculating the palette.
+ * <p>This only works when the original input is a {@link Bitmap}.</p>
+ *
+ * @param left The left side of the rectangle used for the region.
+ * @param top The top of the rectangle used for the region.
+ * @param right The right side of the rectangle used for the region.
+ * @param bottom The bottom of the rectangle used for the region.
+ */
+ @NonNull
+ public Builder setRegion(int left, int top, int right, int bottom) {
+ if (mBitmap != null) {
+ if (mRegion == null) mRegion = new Rect();
+ // Set the Rect to be initially the whole Bitmap
+ mRegion.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+ // Now just get the intersection with the region
+ if (!mRegion.intersect(left, top, right, bottom)) {
+ throw new IllegalArgumentException("The given region must intersect with "
+ + "the Bitmap's dimensions.");
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Clear any previously region set via {@link #setRegion(int, int, int, int)}.
+ */
+ @NonNull
+ public Builder clearRegion() {
+ mRegion = null;
+ return this;
+ }
+
+ /**
+ * Add a target profile to be generated in the palette.
+ *
+ * <p>You can retrieve the result via {@link Palette#getSwatchForTarget(Target)}.</p>
+ */
+ @NonNull
+ public Builder addTarget(@NonNull final Target target) {
+ if (!mTargets.contains(target)) {
+ mTargets.add(target);
+ }
+ return this;
+ }
+
+ /**
+ * Clear all added targets. This includes any default targets added automatically by
+ * {@link Palette}.
+ */
+ @NonNull
+ public Builder clearTargets() {
+ if (mTargets != null) {
+ mTargets.clear();
+ }
+ return this;
+ }
+
+ /**
* Generate and return the {@link Palette} synchronously.
*/
+ @NonNull
public Palette generate() {
final TimingLogger logger = LOG_TIMINGS
? new TimingLogger(LOG_TAG, "Generation")
@@ -546,33 +760,37 @@
List<Swatch> swatches;
if (mBitmap != null) {
- // We have a Bitmap so we need to quantization to reduce the number of colors
+ // We have a Bitmap so we need to use quantization to reduce the number of colors
- if (mResizeMaxDimension <= 0) {
- throw new IllegalArgumentException(
- "Minimum dimension size for resizing should should be >= 1");
- }
-
- // First we'll scale down the bitmap so it's largest dimension is as specified
- final Bitmap scaledBitmap = scaleBitmapDown(mBitmap, mResizeMaxDimension);
+ // First we'll scale down the bitmap if needed
+ final Bitmap bitmap = scaleBitmapDown(mBitmap);
if (logger != null) {
logger.addSplit("Processed Bitmap");
}
- // Now generate a quantizer from the Bitmap
- final int width = scaledBitmap.getWidth();
- final int height = scaledBitmap.getHeight();
- final int[] pixels = new int[width * height];
- scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
+ final Rect region = mRegion;
+ if (bitmap != mBitmap && region != null) {
+ // If we have a scaled bitmap and a selected region, we need to scale down the
+ // region to match the new scale
+ final float scale = bitmap.getWidth() / (float) mBitmap.getWidth();
+ region.left = (int) Math.floor(region.left * scale);
+ region.top = (int) Math.floor(region.top * scale);
+ region.right = (int) Math.ceil(region.right * scale);
+ region.bottom = (int) Math.ceil(region.bottom * scale);
+ }
- final ColorCutQuantizer quantizer = new ColorCutQuantizer(pixels, mMaxColors,
+ // Now generate a quantizer from the Bitmap
+ final ColorCutQuantizer quantizer = new ColorCutQuantizer(
+ getPixelsFromBitmap(bitmap),
+ mMaxColors,
mFilters.isEmpty() ? null : mFilters.toArray(new Filter[mFilters.size()]));
// If created a new bitmap, recycle it
- if (scaledBitmap != mBitmap) {
- scaledBitmap.recycle();
+ if (bitmap != mBitmap) {
+ bitmap.recycle();
}
+
swatches = quantizer.getQuantizedColors();
if (logger != null) {
@@ -583,20 +801,10 @@
swatches = mSwatches;
}
- // If we haven't been provided with a generator, use the default
- if (mGenerator == null) {
- mGenerator = new DefaultGenerator();
- }
-
- // Now call let the Generator do it's thing
- mGenerator.generate(swatches);
-
- if (logger != null) {
- logger.addSplit("Generator.generate() completed");
- }
-
// Now create a Palette instance
- Palette p = new Palette(swatches, mGenerator);
+ final Palette p = new Palette(swatches, mTargets);
+ // And make it generate itself
+ p.generate();
if (logger != null) {
logger.addSplit("Created Palette");
@@ -611,6 +819,7 @@
* {@link PaletteAsyncListener#onGenerated} method will be called with the palette when
* generated.
*/
+ @NonNull
public AsyncTask<Bitmap, Void, Palette> generate(final PaletteAsyncListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener can not be null");
@@ -620,7 +829,12 @@
new AsyncTask<Bitmap, Void, Palette>() {
@Override
protected Palette doInBackground(Bitmap... params) {
- return generate();
+ try {
+ return generate();
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Exception thrown during async generate", e);
+ return null;
+ }
}
@Override
@@ -629,59 +843,62 @@
}
}, mBitmap);
}
- }
- static abstract class Generator {
+ private int[] getPixelsFromBitmap(Bitmap bitmap) {
+ final int bitmapWidth = bitmap.getWidth();
+ final int bitmapHeight = bitmap.getHeight();
+ final int[] pixels = new int[bitmapWidth * bitmapHeight];
- /**
- * This method will be called with the {@link Palette.Swatch} that represent an image.
- * You should process this list so that you have appropriate values when the other methods in
- * class are called.
- * <p>
- * This method will probably be called on a background thread.
- */
- public abstract void generate(List<Palette.Swatch> swatches);
-
- /**
- * Return the most vibrant {@link Palette.Swatch}
- */
- public Palette.Swatch getVibrantSwatch() {
- return null;
+ if (mRegion == null) {
+ // If we don't have a region, return all of the pixels
+ bitmap.getPixels(pixels, 0, bitmapWidth, 0, 0, bitmapWidth, bitmapHeight);
+ return pixels;
+ } else {
+ // If we do have a region, lets create a subset array containing only the region's
+ // pixels
+ final int regionWidth = mRegion.width();
+ final int regionHeight = mRegion.height();
+ // First read the pixels within the region
+ bitmap.getPixels(pixels, 0, bitmapWidth, mRegion.left, mRegion.top,
+ regionWidth, regionHeight);
+ // pixels now contains all of the pixels, but not packed together. We need to
+ // iterate through each row and copy them into a new smaller array
+ final int[] subsetPixels = new int[regionWidth * regionHeight];
+ for (int row = 0; row < regionHeight; row++) {
+ System.arraycopy(pixels, ((row + mRegion.top) * bitmapWidth) + mRegion.left,
+ subsetPixels, row * regionWidth, regionWidth);
+ }
+ return subsetPixels;
+ }
}
/**
- * Return a light and vibrant {@link Palette.Swatch}
+ * Scale the bitmap down as needed.
*/
- public Palette.Swatch getLightVibrantSwatch() {
- return null;
- }
+ private Bitmap scaleBitmapDown(final Bitmap bitmap) {
+ double scaleRatio = -1;
- /**
- * Return a dark and vibrant {@link Palette.Swatch}
- */
- public Palette.Swatch getDarkVibrantSwatch() {
- return null;
- }
+ if (mResizeArea > 0) {
+ final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
+ if (bitmapArea > mResizeArea) {
+ scaleRatio = mResizeArea / (double) bitmapArea;
+ }
+ } else if (mResizeMaxDimension > 0) {
+ final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+ if (maxDimension > mResizeMaxDimension) {
+ scaleRatio = mResizeMaxDimension / (double) maxDimension;
+ }
+ }
- /**
- * Return a muted {@link Palette.Swatch}
- */
- public Palette.Swatch getMutedSwatch() {
- return null;
- }
+ if (scaleRatio <= 0) {
+ // Scaling has been disabled or not needed so just return the Bitmap
+ return bitmap;
+ }
- /**
- * Return a muted and light {@link Palette.Swatch}
- */
- public Palette.Swatch getLightMutedSwatch() {
- return null;
- }
-
- /**
- * Return a muted and dark {@link Palette.Swatch}
- */
- public Palette.Swatch getDarkMutedSwatch() {
- return null;
+ return Bitmap.createScaledBitmap(bitmap,
+ (int) Math.ceil(bitmap.getWidth() * scaleRatio),
+ (int) Math.ceil(bitmap.getHeight() * scaleRatio),
+ false);
}
}
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
new file mode 100644
index 0000000..8ac8205
--- /dev/null
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright 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.
+ */
+
+package android.support.v7.graphics;
+
+import android.support.annotation.FloatRange;
+
+/**
+ * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
+ * can be created via the {@link Builder} class.
+ *
+ * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a
+ * Palette.</p>
+ */
+public final class Target {
+
+ private static final float TARGET_DARK_LUMA = 0.26f;
+ private static final float MAX_DARK_LUMA = 0.45f;
+
+ private static final float MIN_LIGHT_LUMA = 0.55f;
+ private static final float TARGET_LIGHT_LUMA = 0.74f;
+
+ private static final float MIN_NORMAL_LUMA = 0.3f;
+ private static final float TARGET_NORMAL_LUMA = 0.5f;
+ private static final float MAX_NORMAL_LUMA = 0.7f;
+
+ private static final float TARGET_MUTED_SATURATION = 0.3f;
+ private static final float MAX_MUTED_SATURATION = 0.4f;
+
+ private static final float TARGET_VIBRANT_SATURATION = 1f;
+ private static final float MIN_VIBRANT_SATURATION = 0.35f;
+
+ private static final float WEIGHT_SATURATION = 0.24f;
+ 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;
+
+ private static final int INDEX_WEIGHT_SAT = 0;
+ private static final int INDEX_WEIGHT_LUMA = 1;
+ private static final int INDEX_WEIGHT_POP = 2;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is light in luminance.
+ */
+ public static final Target LIGHT_VIBRANT;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is neither light or dark.
+ */
+ public static final Target VIBRANT;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is dark in luminance.
+ */
+ public static final Target DARK_VIBRANT;
+
+ /**
+ * A target which has the characteristics of a muted color which is light in luminance.
+ */
+ public static final Target LIGHT_MUTED;
+
+ /**
+ * A target which has the characteristics of a muted color which is neither light or dark.
+ */
+ public static final Target MUTED;
+
+ /**
+ * A target which has the characteristics of a muted color which is dark in luminance.
+ */
+ public static final Target DARK_MUTED;
+
+ static {
+ LIGHT_VIBRANT = new Target();
+ setDefaultLightLightnessValues(LIGHT_VIBRANT);
+ setDefaultVibrantSaturationValues(LIGHT_VIBRANT);
+
+ VIBRANT = new Target();
+ setDefaultNormalLightnessValues(VIBRANT);
+ setDefaultVibrantSaturationValues(VIBRANT);
+
+ DARK_VIBRANT = new Target();
+ setDefaultDarkLightnessValues(DARK_VIBRANT);
+ setDefaultVibrantSaturationValues(DARK_VIBRANT);
+
+ LIGHT_MUTED = new Target();
+ setDefaultLightLightnessValues(LIGHT_MUTED);
+ setDefaultMutedSaturationValues(LIGHT_MUTED);
+
+ MUTED = new Target();
+ setDefaultNormalLightnessValues(MUTED);
+ setDefaultMutedSaturationValues(MUTED);
+
+ DARK_MUTED = new Target();
+ setDefaultDarkLightnessValues(DARK_MUTED);
+ 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
+
+ private Target() {
+ setTargetDefaultValues(mSaturationTargets);
+ setTargetDefaultValues(mLightnessTargets);
+ setDefaultWeights();
+ }
+
+ private Target(Target from) {
+ System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
+ mSaturationTargets.length);
+ System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
+ mLightnessTargets.length);
+ System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length);
+ }
+
+ /**
+ * The minimum saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMinimumSaturation() {
+ return mSaturationTargets[INDEX_MIN];
+ }
+
+ /**
+ * The target saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getTargetSaturation() {
+ return mSaturationTargets[INDEX_TARGET];
+ }
+
+ /**
+ * The maximum saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMaximumSaturation() {
+ return mSaturationTargets[INDEX_MAX];
+ }
+
+ /**
+ * The minimum lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMinimumLightness() {
+ return mLightnessTargets[INDEX_MIN];
+ }
+
+ /**
+ * The target lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getTargetLightness() {
+ return mLightnessTargets[INDEX_TARGET];
+ }
+
+ /**
+ * The maximum lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMaximumLightness() {
+ return mLightnessTargets[INDEX_MAX];
+ }
+
+ /**
+ * The weight of important that a color's saturation value has on selection.
+ */
+ public float getSaturationWeight() {
+ return mWeights[INDEX_WEIGHT_SAT];
+ }
+
+ /**
+ * The weight of important that a color's lightness value has on selection.
+ */
+ public float getLightnessWeight() {
+ return mWeights[INDEX_WEIGHT_LUMA];
+ }
+
+ /**
+ * The weight of important that a color's population value has on selection.
+ */
+ public float getPopulationWeight() {
+ return mWeights[INDEX_WEIGHT_POP];
+ }
+
+ /**
+ * Returns whether any color selected for this target is exclusive for this target only.
+ *
+ * <p>If false, then the color can be selected for other targets.</p>
+ */
+ public boolean isExclusive() {
+ return mIsExclusive;
+ }
+
+ private static void setTargetDefaultValues(final float[] values) {
+ values[INDEX_MIN] = 0f;
+ values[INDEX_TARGET] = 0.5f;
+ values[INDEX_MAX] = 1f;
+ }
+
+ private void setDefaultWeights() {
+ mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION;
+ mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA;
+ mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION;
+ }
+
+ void normalizeWeights() {
+ float sum = 0;
+ for (int i = 0, z = mWeights.length; i < z; i++) {
+ float weight = mWeights[i];
+ if (weight > 0) {
+ sum += weight;
+ }
+ }
+ if (sum != 0) {
+ for (int i = 0, z = mWeights.length; i < z; i++) {
+ if (mWeights[i] > 0) {
+ mWeights[i] /= sum;
+ }
+ }
+ }
+ }
+
+ private static void setDefaultDarkLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA;
+ target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA;
+ }
+
+ private static void setDefaultNormalLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA;
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA;
+ target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA;
+ }
+
+ private static void setDefaultLightLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA;
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA;
+ }
+
+ private static void setDefaultVibrantSaturationValues(Target target) {
+ target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION;
+ target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION;
+ }
+
+ private static void setDefaultMutedSaturationValues(Target target) {
+ target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION;
+ target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION;
+ }
+
+ /**
+ * Builder class for generating custom {@link Target} instances.
+ */
+ public final static class Builder {
+ private final Target mTarget;
+
+ /**
+ * Create a new {@link Target} builder from scratch.
+ */
+ public Builder() {
+ mTarget = new Target();
+ }
+
+ /**
+ * Create a new builder based on an existing {@link Target}.
+ */
+ public Builder(Target target) {
+ mTarget = new Target(target);
+ }
+
+ /**
+ * Set the minimum saturation value for this target.
+ */
+ public Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_MIN] = value;
+ return this;
+ }
+
+ /**
+ * Set the target/ideal saturation value for this target.
+ */
+ public Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_TARGET] = value;
+ return this;
+ }
+
+ /**
+ * Set the maximum saturation value for this target.
+ */
+ public Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_MAX] = value;
+ return this;
+ }
+
+ /**
+ * Set the minimum lightness value for this target.
+ */
+ public Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_MIN] = value;
+ return this;
+ }
+
+ /**
+ * Set the target/ideal lightness value for this target.
+ */
+ public Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_TARGET] = value;
+ return this;
+ }
+
+ /**
+ * Set the maximum lightness value for this target.
+ */
+ public Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_MAX] = value;
+ return this;
+ }
+
+ /**
+ * Set the weight of important that a color's saturation value has on selection. A weight
+ * of <= 0 means that it has no weight and is ignored.
+ */
+ public Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
+ return this;
+ }
+
+ /**
+ * Set the weight of important that a color's lightness value has on selection. A weight
+ * of <= 0 means that it has no weight and is ignored.
+ */
+ public Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
+ return this;
+ }
+
+ /**
+ * Set the weight of important that a color's population value has on selection. A weight
+ * of <= 0 means that it has no weight and is ignored.
+ */
+ public Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
+ return this;
+ }
+
+ /**
+ * Set whether any color selected for this target is exclusive to this target only.
+ * Defaults to true.
+ *
+ * @param exclusive true if any the color is exclusive to this target, or false is the
+ * color can be selected for other targets.
+ */
+ public Builder setExclusive(boolean exclusive) {
+ mTarget.mIsExclusive = exclusive;
+ return this;
+ }
+
+ /**
+ * Builds and returns the resulting {@link Target}.
+ */
+ public Target build() {
+ return mTarget;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/v7/preference/NOTICES.md b/v7/preference/NOTICES.md
new file mode 100644
index 0000000..4fe92cc
--- /dev/null
+++ b/v7/preference/NOTICES.md
@@ -0,0 +1,11 @@
+# Change Log
+
+## [23.1.0](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/v14/preference) (2015-09-28)
+
+**Breakage and deprecation notices:**
+
+- EditTextPreferenceDialogFragmentCompat
+ - onAddEditTextToDialogView has been removed. Any code depending on overriding this method should
+ be moved to onBindDialogView.
+ - The EditText view is now expected to be present in the dialog layout file with the id
+ @android:id/edit, and is no longer created in code.
diff --git a/v7/preference/api/23.txt b/v7/preference/api/23.0.0.txt
similarity index 100%
rename from v7/preference/api/23.txt
rename to v7/preference/api/23.0.0.txt
diff --git a/v7/preference/api/23.1.0.txt b/v7/preference/api/23.1.0.txt
new file mode 100644
index 0000000..7d7aeb1
--- /dev/null
+++ b/v7/preference/api/23.1.0.txt
@@ -0,0 +1,318 @@
+package android.support.v7.preference {
+
+ public class CheckBoxPreference extends android.support.v7.preference.TwoStatePreference {
+ ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet);
+ ctor public CheckBoxPreference(android.content.Context);
+ }
+
+ public abstract class DialogPreference extends android.support.v7.preference.Preference {
+ ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public DialogPreference(android.content.Context, android.util.AttributeSet);
+ ctor public DialogPreference(android.content.Context);
+ method public android.graphics.drawable.Drawable getDialogIcon();
+ method public int getDialogLayoutResource();
+ method public java.lang.CharSequence getDialogMessage();
+ method public java.lang.CharSequence getDialogTitle();
+ method public java.lang.CharSequence getNegativeButtonText();
+ method public java.lang.CharSequence getPositiveButtonText();
+ method public void setDialogIcon(android.graphics.drawable.Drawable);
+ method public void setDialogIcon(int);
+ method public void setDialogLayoutResource(int);
+ method public void setDialogMessage(java.lang.CharSequence);
+ method public void setDialogMessage(int);
+ method public void setDialogTitle(java.lang.CharSequence);
+ method public void setDialogTitle(int);
+ method public void setNegativeButtonText(java.lang.CharSequence);
+ method public void setNegativeButtonText(int);
+ method public void setPositiveButtonText(java.lang.CharSequence);
+ method public void setPositiveButtonText(int);
+ }
+
+ public static abstract interface DialogPreference.TargetFragment {
+ method public abstract android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ }
+
+ public class EditTextPreference extends android.support.v7.preference.DialogPreference {
+ ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public EditTextPreference(android.content.Context, android.util.AttributeSet);
+ ctor public EditTextPreference(android.content.Context);
+ method public java.lang.String getText();
+ method public void setText(java.lang.String);
+ }
+
+ public class EditTextPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+ ctor public EditTextPreferenceDialogFragmentCompat();
+ method public static android.support.v7.preference.EditTextPreferenceDialogFragmentCompat newInstance(java.lang.String);
+ method public void onDialogClosed(boolean);
+ }
+
+ public class ListPreference extends android.support.v7.preference.DialogPreference {
+ ctor public ListPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public ListPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public ListPreference(android.content.Context, android.util.AttributeSet);
+ ctor public ListPreference(android.content.Context);
+ method public int findIndexOfValue(java.lang.String);
+ method public java.lang.CharSequence[] getEntries();
+ method public java.lang.CharSequence getEntry();
+ method public java.lang.CharSequence[] getEntryValues();
+ method public java.lang.String getValue();
+ method public void setEntries(java.lang.CharSequence[]);
+ method public void setEntries(int);
+ method public void setEntryValues(java.lang.CharSequence[]);
+ method public void setEntryValues(int);
+ method public void setValue(java.lang.String);
+ method public void setValueIndex(int);
+ }
+
+ public class ListPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+ ctor public ListPreferenceDialogFragmentCompat();
+ method public static android.support.v7.preference.ListPreferenceDialogFragmentCompat newInstance(java.lang.String);
+ method public void onDialogClosed(boolean);
+ }
+
+ public class Preference {
+ ctor public Preference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public Preference(android.content.Context, android.util.AttributeSet, int);
+ ctor public Preference(android.content.Context, android.util.AttributeSet);
+ ctor public Preference(android.content.Context);
+ method public boolean callChangeListener(java.lang.Object);
+ method public int compareTo(android.support.v7.preference.Preference);
+ method protected android.support.v7.preference.Preference findPreferenceInHierarchy(java.lang.String);
+ method public android.content.Context getContext();
+ method public java.lang.String getDependency();
+ method public android.os.Bundle getExtras();
+ method public java.lang.String getFragment();
+ method public android.graphics.drawable.Drawable getIcon();
+ method public android.content.Intent getIntent();
+ method public java.lang.String getKey();
+ method public final int getLayoutResource();
+ method public android.support.v7.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
+ method public android.support.v7.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
+ method public int getOrder();
+ method protected boolean getPersistedBoolean(boolean);
+ method protected float getPersistedFloat(float);
+ method protected int getPersistedInt(int);
+ method protected long getPersistedLong(long);
+ method protected java.lang.String getPersistedString(java.lang.String);
+ method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+ method public android.content.SharedPreferences getSharedPreferences();
+ method public boolean getShouldDisableView();
+ method public java.lang.CharSequence getSummary();
+ method public java.lang.CharSequence getTitle();
+ method public final int getWidgetLayoutResource();
+ method public boolean hasKey();
+ method public boolean isEnabled();
+ method public boolean isPersistent();
+ method public boolean isSelectable();
+ method public final boolean isVisible();
+ method protected void notifyChanged();
+ method public void notifyDependencyChange(boolean);
+ method protected void notifyHierarchyChanged();
+ method public void onAttached();
+ method protected void onAttachedToHierarchy(android.support.v7.preference.PreferenceManager);
+ method public void onBindViewHolder(android.support.v7.preference.PreferenceViewHolder);
+ method protected void onClick();
+ method public void onDependencyChanged(android.support.v7.preference.Preference, boolean);
+ method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
+ method public void onParentChanged(android.support.v7.preference.Preference, boolean);
+ method protected void onPrepareForRemoval();
+ method protected void onRestoreInstanceState(android.os.Parcelable);
+ method protected android.os.Parcelable onSaveInstanceState();
+ method protected void onSetInitialValue(boolean, java.lang.Object);
+ method public android.os.Bundle peekExtras();
+ method protected boolean persistBoolean(boolean);
+ method protected boolean persistFloat(float);
+ method protected boolean persistInt(int);
+ method protected boolean persistLong(long);
+ method protected boolean persistString(java.lang.String);
+ method public void restoreHierarchyState(android.os.Bundle);
+ method public void saveHierarchyState(android.os.Bundle);
+ method public void setDefaultValue(java.lang.Object);
+ method public void setDependency(java.lang.String);
+ method public void setEnabled(boolean);
+ method public void setFragment(java.lang.String);
+ method public void setIcon(android.graphics.drawable.Drawable);
+ method public void setIcon(int);
+ method public void setIntent(android.content.Intent);
+ method public void setKey(java.lang.String);
+ method public void setLayoutResource(int);
+ method public void setOnPreferenceChangeListener(android.support.v7.preference.Preference.OnPreferenceChangeListener);
+ method public void setOnPreferenceClickListener(android.support.v7.preference.Preference.OnPreferenceClickListener);
+ method public void setOrder(int);
+ method public void setPersistent(boolean);
+ method public void setSelectable(boolean);
+ method public void setShouldDisableView(boolean);
+ method public void setSummary(java.lang.CharSequence);
+ method public void setSummary(int);
+ method public void setTitle(java.lang.CharSequence);
+ method public void setTitle(int);
+ method public final void setVisible(boolean);
+ method public void setWidgetLayoutResource(int);
+ method public boolean shouldDisableDependents();
+ method protected boolean shouldPersist();
+ field public static final int DEFAULT_ORDER = 2147483647; // 0x7fffffff
+ }
+
+ public static class Preference.BaseSavedState extends android.view.AbsSavedState {
+ ctor public Preference.BaseSavedState(android.os.Parcel);
+ ctor public Preference.BaseSavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.v7.preference.Preference.BaseSavedState> CREATOR;
+ }
+
+ public static abstract interface Preference.OnPreferenceChangeListener {
+ method public abstract boolean onPreferenceChange(android.support.v7.preference.Preference, java.lang.Object);
+ }
+
+ public static abstract interface Preference.OnPreferenceClickListener {
+ method public abstract boolean onPreferenceClick(android.support.v7.preference.Preference);
+ }
+
+ public class PreferenceCategory extends android.support.v7.preference.PreferenceGroup {
+ ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int);
+ ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet);
+ ctor public PreferenceCategory(android.content.Context);
+ }
+
+ public abstract class PreferenceDialogFragmentCompat extends android.support.v4.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+ ctor public PreferenceDialogFragmentCompat();
+ method public android.support.v7.preference.DialogPreference getPreference();
+ method protected void onBindDialogView(android.view.View);
+ method public void onClick(android.content.DialogInterface, int);
+ method protected android.view.View onCreateDialogView(android.content.Context);
+ method public abstract void onDialogClosed(boolean);
+ method protected void onPrepareDialogBuilder(android.support.v7.app.AlertDialog.Builder);
+ field protected static final java.lang.String ARG_KEY = "key";
+ }
+
+ public abstract class PreferenceFragmentCompat extends android.support.v4.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+ ctor public PreferenceFragmentCompat();
+ method public void addPreferencesFromResource(int);
+ method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ method public final android.support.v7.widget.RecyclerView getListView();
+ method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+ method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+ method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+ method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+ method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+ method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+ method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+ method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+ method public void setPreferencesFromResource(int, java.lang.String);
+ field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+ }
+
+ public static abstract interface PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
+ method public abstract boolean onPreferenceDisplayDialog(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
+ method public abstract boolean onPreferenceStartFragment(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
+ method public abstract boolean onPreferenceStartScreen(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.PreferenceScreen);
+ }
+
+ public abstract class PreferenceGroup extends android.support.v7.preference.Preference {
+ ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int);
+ ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet);
+ method public void addItemFromInflater(android.support.v7.preference.Preference);
+ method public boolean addPreference(android.support.v7.preference.Preference);
+ method protected void dispatchRestoreInstanceState(android.os.Bundle);
+ method protected void dispatchSaveInstanceState(android.os.Bundle);
+ method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ method public android.support.v7.preference.Preference getPreference(int);
+ method public int getPreferenceCount();
+ method protected boolean isOnSameScreenAsChildren();
+ method public boolean isOrderingAsAdded();
+ method protected boolean onPrepareAddPreference(android.support.v7.preference.Preference);
+ method public void removeAll();
+ method public boolean removePreference(android.support.v7.preference.Preference);
+ method public void setOrderingAsAdded(boolean);
+ }
+
+ public class PreferenceManager {
+ method public android.support.v7.preference.PreferenceScreen createPreferenceScreen(android.content.Context);
+ method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ method public android.content.Context getContext();
+ method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
+ method public android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener();
+ method public android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener getOnNavigateToScreenListener();
+ method public android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener getOnPreferenceTreeClickListener();
+ method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+ method public android.content.SharedPreferences getSharedPreferences();
+ method public int getSharedPreferencesMode();
+ method public java.lang.String getSharedPreferencesName();
+ method public static void setDefaultValues(android.content.Context, int, boolean);
+ method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+ method public void setOnDisplayPreferenceDialogListener(android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener);
+ method public void setOnNavigateToScreenListener(android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener);
+ method public void setOnPreferenceTreeClickListener(android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener);
+ method public boolean setPreferences(android.support.v7.preference.PreferenceScreen);
+ method public void setSharedPreferencesMode(int);
+ method public void setSharedPreferencesName(java.lang.String);
+ method public void showDialog(android.support.v7.preference.Preference);
+ field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
+ }
+
+ public static abstract interface PreferenceManager.OnDisplayPreferenceDialogListener {
+ method public abstract void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceManager.OnNavigateToScreenListener {
+ method public abstract void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+ }
+
+ public static abstract interface PreferenceManager.OnPreferenceTreeClickListener {
+ method public abstract boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ }
+
+ public final class PreferenceScreen extends android.support.v7.preference.PreferenceGroup {
+ }
+
+ public class PreferenceViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
+ method public android.view.View findViewById(int);
+ }
+
+ public class SwitchPreferenceCompat extends android.support.v7.preference.TwoStatePreference {
+ ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int);
+ ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet);
+ ctor public SwitchPreferenceCompat(android.content.Context);
+ method public java.lang.CharSequence getSwitchTextOff();
+ method public java.lang.CharSequence getSwitchTextOn();
+ method public void setSwitchTextOff(java.lang.CharSequence);
+ method public void setSwitchTextOff(int);
+ method public void setSwitchTextOn(java.lang.CharSequence);
+ method public void setSwitchTextOn(int);
+ }
+
+ public abstract class TwoStatePreference extends android.support.v7.preference.Preference {
+ ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet);
+ ctor public TwoStatePreference(android.content.Context);
+ method public boolean getDisableDependentsState();
+ method public java.lang.CharSequence getSummaryOff();
+ method public java.lang.CharSequence getSummaryOn();
+ method public boolean isChecked();
+ method public void setChecked(boolean);
+ method public void setDisableDependentsState(boolean);
+ method public void setSummaryOff(java.lang.CharSequence);
+ method public void setSummaryOff(int);
+ method public void setSummaryOn(java.lang.CharSequence);
+ method public void setSummaryOn(int);
+ method protected void syncSummaryView(android.support.v7.preference.PreferenceViewHolder);
+ field protected boolean mChecked;
+ }
+
+}
+
diff --git a/v7/preference/api/current.txt b/v7/preference/api/current.txt
index 6ab53c5..9034fd4 100644
--- a/v7/preference/api/current.txt
+++ b/v7/preference/api/current.txt
@@ -47,7 +47,6 @@
public class EditTextPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
ctor public EditTextPreferenceDialogFragmentCompat();
method public static android.support.v7.preference.EditTextPreferenceDialogFragmentCompat newInstance(java.lang.String);
- method protected void onAddEditTextToDialogView(android.view.View, android.widget.EditText);
method public void onDialogClosed(boolean);
}
@@ -204,6 +203,8 @@
method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ method public void setDivider(android.graphics.drawable.Drawable);
+ method public void setDividerHeight(int);
method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
method public void setPreferencesFromResource(int, java.lang.String);
field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
@@ -281,6 +282,10 @@
public class PreferenceViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
method public android.view.View findViewById(int);
+ method public boolean isDividerAllowedAbove();
+ method public boolean isDividerAllowedBelow();
+ method public void setDividerAllowedAbove(boolean);
+ method public void setDividerAllowedBelow(boolean);
}
public class SwitchPreferenceCompat extends android.support.v7.preference.TwoStatePreference {
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index d93a93d..a0681ed 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -55,3 +55,37 @@
consumerProguardFiles 'proguard-rules.pro'
}
}
+
+uploadArchives {
+ repositories {
+ mavenDeployer {
+ repository(url: uri(rootProject.ext.supportRepoOut)) {
+ }
+
+ pom.project {
+ name 'Android Support Preference v7'
+ description "Android Support Preference v7"
+ url 'http://developer.android.com/tools/extras/support-library.html'
+ inceptionYear '2015'
+
+ licenses {
+ license {
+ name 'The Apache Software License, Version 2.0'
+ url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ distribution 'repo'
+ }
+ }
+
+ scm {
+ url "http://source.android.com"
+ connection "scm:git:https://android.googlesource.com/platform/frameworks/support"
+ }
+ developers {
+ developer {
+ name 'The Android Open Source Project'
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/v7/preference/proguard-rules.pro b/v7/preference/proguard-rules.pro
index 07c2b2b..bdcc466 100644
--- a/v7/preference/proguard-rules.pro
+++ b/v7/preference/proguard-rules.pro
@@ -13,5 +13,9 @@
# limitations under the License.
# Preference objects are inflated via reflection
--keep public class * extends android.support.v7.preference.Preference
-
+-keep public class android.support.v7.preference.Preference {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+-keep public class * extends android.support.v7.preference.Preference {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
diff --git a/v7/preference/res/layout/preference_dialog_edittext.xml b/v7/preference/res/layout/preference_dialog_edittext.xml
index 527a7de..9fbf2b7 100644
--- a/v7/preference/res/layout/preference_dialog_edittext.xml
+++ b/v7/preference/res/layout/preference_dialog_edittext.xml
@@ -23,7 +23,6 @@
android:overScrollMode="ifContentScrolls">
<LinearLayout
- android:id="@+id/edittext_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dip"
@@ -36,6 +35,11 @@
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorSecondary" />
+ <EditText
+ android:id="@android:id/edit"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
</LinearLayout>
</ScrollView>
diff --git a/v7/preference/res/layout/preference_information.xml b/v7/preference/res/layout/preference_information.xml
index e3be3820..5815c46 100644
--- a/v7/preference/res/layout/preference_information.xml
+++ b/v7/preference/res/layout/preference_information.xml
@@ -33,14 +33,14 @@
android:layout_marginBottom="6sp"
android:layout_weight="1">
- <TextView android:id="@+android:id/title"
+ <TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorSecondary" />
- <TextView android:id="@+android:id/summary"
+ <TextView android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
@@ -52,7 +52,7 @@
</RelativeLayout>
<!-- Preference should place its actual preference widget here. -->
- <LinearLayout android:id="@+android:id/widget_frame"
+ <LinearLayout android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
diff --git a/v7/preference/res/values-v17/styles.xml b/v7/preference/res/values-v17/styles.xml
index 20168b2..2184354 100644
--- a/v7/preference/res/values-v17/styles.xml
+++ b/v7/preference/res/values-v17/styles.xml
@@ -19,6 +19,7 @@
<style name="PreferenceFragment">
<item name="android:paddingStart">0dp</item>
<item name="android:paddingEnd">0dp</item>
+ <item name="android:divider">?android:attr/listDivider</item>
</style>
<style name="PreferenceFragmentList">
diff --git a/v7/preference/res/values/attrs.xml b/v7/preference/res/values/attrs.xml
index b93c1e6..5d39b63 100644
--- a/v7/preference/res/values/attrs.xml
+++ b/v7/preference/res/values/attrs.xml
@@ -1,243 +1,248 @@
<?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
- -->
+ 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
+ -->
<resources>
- <declare-styleable name="Theme">
+ <declare-styleable name="Theme">
- <!-- =================== -->
- <!-- Preference styles -->
- <!-- =================== -->
- <eat-comment />
+ <!-- =================== -->
+ <!-- Preference styles -->
+ <!-- =================== -->
+ <eat-comment />
- <!-- Theme for inflating Preference objects -->
- <attr name="preferenceTheme" format="reference" />
+ <!-- Theme for inflating Preference objects -->
+ <attr name="preferenceTheme" format="reference" />
- <!-- Default style for PreferenceScreen. -->
- <attr name="preferenceScreenStyle" format="reference" />
- <!-- Default style for the PreferenceActivity. -->
- <attr name="preferenceActivityStyle" format="reference" />
- <!-- Default style for Headers pane in PreferenceActivity. -->
- <attr name="preferenceFragmentStyle" format="reference" />
- <!-- Default style for PreferenceCategory. -->
- <attr name="preferenceCategoryStyle" format="reference" />
- <!-- Default style for Preference. -->
- <attr name="preferenceStyle" format="reference" />
- <!-- Default style for informational Preference. -->
- <attr name="preferenceInformationStyle" format="reference" />
- <!-- Default style for CheckBoxPreference. -->
- <attr name="checkBoxPreferenceStyle" format="reference" />
- <!-- Default style for YesNoPreference. -->
- <attr name="yesNoPreferenceStyle" format="reference" />
- <!-- Default style for DialogPreference. -->
- <attr name="dialogPreferenceStyle" format="reference" />
- <!-- Default style for EditTextPreference. -->
- <attr name="editTextPreferenceStyle" format="reference" />
- <!-- Default style for RingtonePreference. -->
- <attr name="ringtonePreferenceStyle" format="reference" />
- <!-- The preference layout that has the child/tabbed effect. -->
- <attr name="preferenceLayoutChild" format="reference" />
- <!-- Preference panel style -->
- <attr name="preferencePanelStyle" format="reference" />
- <!-- Preference headers panel style -->
- <attr name="preferenceHeaderPanelStyle" format="reference" />
- <!-- Preference list style -->
- <attr name="preferenceListStyle" format="reference" />
- <!-- Preference fragment list style -->
- <attr name="preferenceFragmentListStyle" format="reference" />
- <!-- Preference fragment padding side -->
- <attr name="preferenceFragmentPaddingSide" format="dimension" />
- <!-- Default style for switch preferences. -->
- <attr name="switchPreferenceStyle" format="reference" />
- <!-- Default style for switch compat preferences. -->
- <attr name="switchPreferenceCompatStyle" format="reference" />
- <!-- Default style for seekbar preferences. -->
- <attr name="seekBarPreferenceStyle" format="reference" />
- </declare-styleable>
+ <!-- Default style for PreferenceScreen. -->
+ <attr name="preferenceScreenStyle" format="reference" />
+ <!-- Default style for the PreferenceActivity. -->
+ <attr name="preferenceActivityStyle" format="reference" />
+ <!-- Default style for Headers pane in PreferenceActivity. -->
+ <attr name="preferenceFragmentStyle" format="reference" />
+ <!-- Default style for Headers pane in PreferenceActivity. -->
+ <attr name="preferenceFragmentCompatStyle" format="reference" />
+ <!-- Default style for PreferenceCategory. -->
+ <attr name="preferenceCategoryStyle" format="reference" />
+ <!-- Default style for Preference. -->
+ <attr name="preferenceStyle" format="reference" />
+ <!-- Default style for informational Preference. -->
+ <attr name="preferenceInformationStyle" format="reference" />
+ <!-- Default style for CheckBoxPreference. -->
+ <attr name="checkBoxPreferenceStyle" format="reference" />
+ <!-- Default style for YesNoPreference. -->
+ <attr name="yesNoPreferenceStyle" format="reference" />
+ <!-- Default style for DialogPreference. -->
+ <attr name="dialogPreferenceStyle" format="reference" />
+ <!-- Default style for EditTextPreference. -->
+ <attr name="editTextPreferenceStyle" format="reference" />
+ <!-- Default style for RingtonePreference. -->
+ <attr name="ringtonePreferenceStyle" format="reference" />
+ <!-- The preference layout that has the child/tabbed effect. -->
+ <attr name="preferenceLayoutChild" format="reference" />
+ <!-- Preference panel style -->
+ <attr name="preferencePanelStyle" format="reference" />
+ <!-- Preference headers panel style -->
+ <attr name="preferenceHeaderPanelStyle" format="reference" />
+ <!-- Preference list style -->
+ <attr name="preferenceListStyle" format="reference" />
+ <!-- Preference fragment list style -->
+ <attr name="preferenceFragmentListStyle" format="reference" />
+ <!-- Preference fragment padding side -->
+ <attr name="preferenceFragmentPaddingSide" format="dimension" />
+ <!-- Default style for switch preferences. -->
+ <attr name="switchPreferenceStyle" format="reference" />
+ <!-- Default style for switch compat preferences. -->
+ <attr name="switchPreferenceCompatStyle" format="reference" />
+ <!-- Default style for seekbar preferences. -->
+ <attr name="seekBarPreferenceStyle" format="reference" />
+ </declare-styleable>
- <!-- Base attributes available to PreferenceFragment. -->
- <declare-styleable name="PreferenceFragmentCompat">
- <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
- <attr name="layout" />
- <attr name="android:layout" />
- </declare-styleable>
+ <!-- Base attributes available to PreferenceFragment. -->
+ <declare-styleable name="PreferenceFragmentCompat">
+ <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
+ <attr name="android:layout" />
+ <!-- List separator to draw between preference views -->
+ <attr name="android:divider" />
+ <!-- List separator height -->
+ <attr name="android:dividerHeight" />
+ </declare-styleable>
- <!-- Base attributes available to PreferenceGroup. -->
- <declare-styleable name="PreferenceGroup">
- <!-- Whether to order the Preference under this group as they appear in the XML file.
- If this is false, the ordering will follow the Preference order attribute and
- default to alphabetic for those without the order attribute. -->
- <attr name="orderingFromXml" format="boolean" />
- <attr name="android:orderingFromXml" />
- </declare-styleable>
+ <!-- Base attributes available to PreferenceGroup. -->
+ <declare-styleable name="PreferenceGroup">
+ <!-- Whether to order the Preference under this group as they appear in the XML file.
+ If this is false, the ordering will follow the Preference order attribute and
+ default to alphabetic for those without the order attribute. -->
+ <attr name="orderingFromXml" format="boolean" />
+ <attr name="android:orderingFromXml" />
+ </declare-styleable>
- <!-- Base attributes available to Preference. -->
- <declare-styleable name="Preference">
- <!-- The optional icon for the preference -->
- <attr name="icon" />
- <attr name="android:icon" />
- <!-- The key to store the Preference value. -->
- <attr name="key" format="string" />
- <attr name="android:key" />
- <!-- The title for the Preference in a PreferenceActivity screen. -->
- <attr name="title" />
- <attr name="android:title" />
- <!-- The summary for the Preference in a PreferenceActivity screen. -->
- <attr name="summary" format="string" />
- <attr name="android:summary" />
- <!-- The order for the Preference (lower values are to be ordered first). If this is not
- specified, the default ordering will be alphabetic. -->
- <attr name="order" format="integer" />
- <attr name="android:order" />
- <!-- When used inside of a modern PreferenceActivity, this declares
- a new PreferenceFragment to be shown when the user selects this item. -->
- <attr name="fragment" format="string" />
- <attr name="android:fragment" />
- <!-- The layout for the Preference in a PreferenceActivity screen. This should
- rarely need to be changed, look at widgetLayout instead. -->
- <attr name="layout" />
- <attr name="android:layout" />
- <!-- The layout for the controllable widget portion of a Preference. This is inflated
- into the layout for a Preference and should be used more frequently than
- the layout attribute. For example, a checkbox preference would specify
- a custom layout (consisting of just the CheckBox) here. -->
- <attr name="widgetLayout" format="reference" />
- <attr name="android:widgetLayout" />
- <!-- Whether the Preference is enabled. -->
- <attr name="enabled" format="boolean" />
- <attr name="android:enabled" />
- <!-- Whether the Preference is selectable. -->
- <attr name="selectable" format="boolean" />
- <attr name="android:selectable" />
- <!-- The key of another Preference that this Preference will depend on. If the other
- Preference is not set or is off, this Preference will be disabled. -->
- <attr name="dependency" format="string" />
- <attr name="android:dependency" />
- <!-- Whether the Preference stores its value to the shared preferences. -->
- <attr name="persistent" format="boolean" />
- <attr name="android:persistent" />
- <!-- The default value for the preference, which will be set either if persistence
- is off or persistence is on and the preference is not found in the persistent
- storage. -->
- <attr name="defaultValue" format="string|boolean|integer|reference|float" />
- <attr name="android:defaultValue" />
- <!-- Whether the view of this Preference should be disabled when
- this Preference is disabled. -->
- <attr name="shouldDisableView" format="boolean" />
- <attr name="android:shouldDisableView" />
- </declare-styleable>
+ <!-- Base attributes available to Preference. -->
+ <declare-styleable name="Preference">
+ <!-- The optional icon for the preference -->
+ <attr name="icon" />
+ <attr name="android:icon" />
+ <!-- The key to store the Preference value. -->
+ <attr name="key" format="string" />
+ <attr name="android:key" />
+ <!-- The title for the Preference in a PreferenceActivity screen. -->
+ <attr name="title" />
+ <attr name="android:title" />
+ <!-- The summary for the Preference in a PreferenceActivity screen. -->
+ <attr name="summary" format="string" />
+ <attr name="android:summary" />
+ <!-- The order for the Preference (lower values are to be ordered first). If this is not
+ specified, the default ordering will be alphabetic. -->
+ <attr name="order" format="integer" />
+ <attr name="android:order" />
+ <!-- When used inside of a modern PreferenceActivity, this declares
+ a new PreferenceFragment to be shown when the user selects this item. -->
+ <attr name="fragment" format="string" />
+ <attr name="android:fragment" />
+ <!-- The layout for the Preference in a PreferenceActivity screen. This should
+ rarely need to be changed, look at widgetLayout instead. -->
+ <attr name="layout" />
+ <attr name="android:layout" />
+ <!-- The layout for the controllable widget portion of a Preference. This is inflated
+ into the layout for a Preference and should be used more frequently than
+ the layout attribute. For example, a checkbox preference would specify
+ a custom layout (consisting of just the CheckBox) here. -->
+ <attr name="widgetLayout" format="reference" />
+ <attr name="android:widgetLayout" />
+ <!-- Whether the Preference is enabled. -->
+ <attr name="enabled" format="boolean" />
+ <attr name="android:enabled" />
+ <!-- Whether the Preference is selectable. -->
+ <attr name="selectable" format="boolean" />
+ <attr name="android:selectable" />
+ <!-- The key of another Preference that this Preference will depend on. If the other
+ Preference is not set or is off, this Preference will be disabled. -->
+ <attr name="dependency" format="string" />
+ <attr name="android:dependency" />
+ <!-- Whether the Preference stores its value to the shared preferences. -->
+ <attr name="persistent" format="boolean" />
+ <attr name="android:persistent" />
+ <!-- The default value for the preference, which will be set either if persistence
+ is off or persistence is on and the preference is not found in the persistent
+ storage. -->
+ <attr name="defaultValue" format="string|boolean|integer|reference|float" />
+ <attr name="android:defaultValue" />
+ <!-- Whether the view of this Preference should be disabled when
+ this Preference is disabled. -->
+ <attr name="shouldDisableView" format="boolean" />
+ <attr name="android:shouldDisableView" />
+ </declare-styleable>
- <!-- Base attributes available to CheckBoxPreference. -->
- <declare-styleable name="CheckBoxPreference">
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- CheckBoxPreference is checked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="summaryOn" format="string" />
- <attr name="android:summaryOn" />
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- CheckBoxPreference is unchecked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="summaryOff" format="string" />
- <attr name="android:summaryOff" />
- <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
- dependents will be disabled when this is unchecked, so the value of this preference is false. -->
- <attr name="disableDependentsState" format="boolean" />
- <attr name="android:disableDependentsState" />
- </declare-styleable>
+ <!-- Base attributes available to CheckBoxPreference. -->
+ <declare-styleable name="CheckBoxPreference">
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ CheckBoxPreference is checked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOn" format="string" />
+ <attr name="android:summaryOn" />
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ CheckBoxPreference is unchecked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOff" format="string" />
+ <attr name="android:summaryOff" />
+ <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+ dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+ <attr name="disableDependentsState" format="boolean" />
+ <attr name="android:disableDependentsState" />
+ </declare-styleable>
- <!-- Base attributes available to DialogPreference. -->
- <declare-styleable name="DialogPreference">
- <!-- The title in the dialog. -->
- <attr name="dialogTitle" format="string" />
- <attr name="android:dialogTitle" />
- <!-- The message in the dialog. If a dialogLayout is provided and contains
- a TextView with ID android:id/message, this message will be placed in there. -->
- <attr name="dialogMessage" format="string" />
- <attr name="android:dialogMessage" />
- <!-- The icon for the dialog. -->
- <attr name="dialogIcon" format="reference" />
- <attr name="android:dialogIcon" />
- <!-- The positive button text for the dialog. Set to @null to hide the positive button. -->
- <attr name="positiveButtonText" format="string" />
- <attr name="android:positiveButtonText" />
- <!-- The negative button text for the dialog. Set to @null to hide the negative button. -->
- <attr name="negativeButtonText" format="string" />
- <attr name="android:negativeButtonText" />
- <!-- A layout to be used as the content View for the dialog. By default, this shouldn't
- be needed. If a custom DialogPreference is required, this should be set. For example,
- the EditTextPreference uses a layout with an EditText as this attribute. -->
- <attr name="dialogLayout" format="reference" />
- <attr name="android:dialogLayout" />
- </declare-styleable>
+ <!-- Base attributes available to DialogPreference. -->
+ <declare-styleable name="DialogPreference">
+ <!-- The title in the dialog. -->
+ <attr name="dialogTitle" format="string" />
+ <attr name="android:dialogTitle" />
+ <!-- The message in the dialog. If a dialogLayout is provided and contains
+ a TextView with ID android:id/message, this message will be placed in there. -->
+ <attr name="dialogMessage" format="string" />
+ <attr name="android:dialogMessage" />
+ <!-- The icon for the dialog. -->
+ <attr name="dialogIcon" format="reference" />
+ <attr name="android:dialogIcon" />
+ <!-- The positive button text for the dialog. Set to @null to hide the positive button. -->
+ <attr name="positiveButtonText" format="string" />
+ <attr name="android:positiveButtonText" />
+ <!-- The negative button text for the dialog. Set to @null to hide the negative button. -->
+ <attr name="negativeButtonText" format="string" />
+ <attr name="android:negativeButtonText" />
+ <!-- A layout to be used as the content View for the dialog. By default, this shouldn't
+ be needed. If a custom DialogPreference is required, this should be set. For example,
+ the EditTextPreference uses a layout with an EditText as this attribute. -->
+ <attr name="dialogLayout" format="reference" />
+ <attr name="android:dialogLayout" />
+ </declare-styleable>
- <!-- Base attributes available to ListPreference. -->
- <declare-styleable name="ListPreference">
- <!-- The human-readable array to present as a list. Each entry must have a corresponding
- index in entryValues. -->
- <attr name="entries" format="reference" />
- <attr name="android:entries" />
- <!-- The array to find the value to save for a preference when an entry from
- entries is selected. If a user clicks on the second item in entries, the
- second item in this array will be saved to the preference. -->
- <attr name="entryValues" format="reference" />
- <attr name="android:entryValues" />
- </declare-styleable>
+ <!-- Base attributes available to ListPreference. -->
+ <declare-styleable name="ListPreference">
+ <!-- The human-readable array to present as a list. Each entry must have a corresponding
+ index in entryValues. -->
+ <attr name="entries" format="reference" />
+ <attr name="android:entries" />
+ <!-- The array to find the value to save for a preference when an entry from
+ entries is selected. If a user clicks on the second item in entries, the
+ second item in this array will be saved to the preference. -->
+ <attr name="entryValues" format="reference" />
+ <attr name="android:entryValues" />
+ </declare-styleable>
- <declare-styleable name="MultiSelectListPreference">
- <!-- The human-readable array to present as a list. Each entry must have a corresponding
- index in entryValues. -->
- <attr name="entries" />
- <attr name="android:entries" />
- <!-- The array to find the value to save for a preference when an entry from
- entries is selected. If a user clicks the second item in entries, the
- second item in this array will be saved to the preference. -->
- <attr name="entryValues" />
- <attr name="android:entryValues" />
- </declare-styleable>
+ <declare-styleable name="MultiSelectListPreference">
+ <!-- The human-readable array to present as a list. Each entry must have a corresponding
+ index in entryValues. -->
+ <attr name="entries" />
+ <attr name="android:entries" />
+ <!-- The array to find the value to save for a preference when an entry from
+ entries is selected. If a user clicks the second item in entries, the
+ second item in this array will be saved to the preference. -->
+ <attr name="entryValues" />
+ <attr name="android:entryValues" />
+ </declare-styleable>
- <declare-styleable name="SwitchPreferenceCompat">
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- SwitchPreference is checked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="summaryOn" />
- <attr name="android:summaryOn" />
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- SwitchPreference is unchecked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="summaryOff" />
- <attr name="android:summaryOff" />
- <!-- The text used on the switch itself when in the "on" state.
- This should be a very SHORT string, as it appears in a small space. -->
- <attr name="switchTextOn" format="string" />
- <attr name="android:switchTextOn" />
- <!-- The text used on the switch itself when in the "off" state.
- This should be a very SHORT string, as it appears in a small space. -->
- <attr name="switchTextOff" format="string" />
- <attr name="android:switchTextOff" />
- <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
- dependents will be disabled when this is unchecked, so the value of this preference is false. -->
- <attr name="disableDependentsState" />
- <attr name="android:disableDependentsState" />
- </declare-styleable>
+ <declare-styleable name="SwitchPreferenceCompat">
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ SwitchPreference is checked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOn" />
+ <attr name="android:summaryOn" />
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ SwitchPreference is unchecked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOff" />
+ <attr name="android:summaryOff" />
+ <!-- The text used on the switch itself when in the "on" state.
+ This should be a very SHORT string, as it appears in a small space. -->
+ <attr name="switchTextOn" format="string" />
+ <attr name="android:switchTextOn" />
+ <!-- The text used on the switch itself when in the "off" state.
+ This should be a very SHORT string, as it appears in a small space. -->
+ <attr name="switchTextOff" format="string" />
+ <attr name="android:switchTextOff" />
+ <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+ dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+ <attr name="disableDependentsState" />
+ <attr name="android:disableDependentsState" />
+ </declare-styleable>
- <declare-styleable name="PreferenceImageView">
- <attr name="maxWidth" format="dimension" />
- <attr name="android:maxWidth" />
- <attr name="maxHeight" format="dimension" />
- <attr name="android:maxHeight" />
- </declare-styleable>
+ <declare-styleable name="PreferenceImageView">
+ <attr name="maxWidth" format="dimension" />
+ <attr name="android:maxWidth" />
+ <attr name="maxHeight" format="dimension" />
+ <attr name="android:maxHeight" />
+ </declare-styleable>
</resources>
diff --git a/v7/preference/res/values/styles.xml b/v7/preference/res/values/styles.xml
index 3af31a42..774c0c9 100644
--- a/v7/preference/res/values/styles.xml
+++ b/v7/preference/res/values/styles.xml
@@ -17,47 +17,48 @@
<resources>
<style name="Preference">
- <item name="layout">@layout/preference</item>
+ <item name="android:layout">@layout/preference</item>
</style>
<style name="PreferenceFragment">
<item name="android:paddingLeft">0dp</item>
<item name="android:paddingRight">0dp</item>
+ <item name="android:divider">?android:attr/listDivider</item>
</style>
<style name="Preference.Information">
- <item name="layout">@layout/preference_information</item>
- <item name="enabled">false</item>
- <item name="shouldDisableView">false</item>
+ <item name="android:layout">@layout/preference_information</item>
+ <item name="android:enabled">false</item>
+ <item name="android:shouldDisableView">false</item>
</style>
<style name="Preference.Category">
- <item name="layout">@layout/preference_category</item>
+ <item name="android:layout">@layout/preference_category</item>
<!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
- <item name="shouldDisableView">false</item>
- <item name="selectable">false</item>
+ <item name="android:shouldDisableView">false</item>
+ <item name="android:selectable">false</item>
</style>
<style name="Preference.CheckBoxPreference">
- <item name="widgetLayout">@layout/preference_widget_checkbox</item>
+ <item name="android:widgetLayout">@layout/preference_widget_checkbox</item>
</style>
<style name="Preference.SwitchPreferenceCompat">
- <item name="widgetLayout">@layout/preference_widget_switch_compat</item>
- <item name="switchTextOn">@string/v7_preference_on</item>
- <item name="switchTextOff">@string/v7_preference_off</item>
+ <item name="android:widgetLayout">@layout/preference_widget_switch_compat</item>
+ <item name="android:switchTextOn">@string/v7_preference_on</item>
+ <item name="android:switchTextOff">@string/v7_preference_off</item>
</style>
<style name="Preference.PreferenceScreen">
</style>
<style name="Preference.DialogPreference">
- <item name="positiveButtonText">@android:string/ok</item>
- <item name="negativeButtonText">@android:string/cancel</item>
+ <item name="android:positiveButtonText">@android:string/ok</item>
+ <item name="android:negativeButtonText">@android:string/cancel</item>
</style>
<style name="Preference.DialogPreference.EditTextPreference">
- <item name="dialogLayout">@layout/preference_dialog_edittext</item>
+ <item name="android:dialogLayout">@layout/preference_dialog_edittext</item>
</style>
<style name="PreferenceFragmentList">
diff --git a/v7/preference/res/values/themes.xml b/v7/preference/res/values/themes.xml
index c2c2c3c..8a7eaa3 100644
--- a/v7/preference/res/values/themes.xml
+++ b/v7/preference/res/values/themes.xml
@@ -18,7 +18,7 @@
<resources>
<style name="PreferenceThemeOverlay">
<item name="preferenceScreenStyle">@style/Preference.PreferenceScreen</item>
- <item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
+ <item name="preferenceFragmentCompatStyle">@style/PreferenceFragment</item>
<item name="preferenceCategoryStyle">@style/Preference.Category</item>
<item name="preferenceStyle">@style/Preference</item>
<item name="preferenceInformationStyle">@style/Preference.Information</item>
diff --git a/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
index 182cf28..6e7663c 100644
--- a/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
@@ -18,8 +18,6 @@
import android.os.Bundle;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
import android.widget.EditText;
public class EditTextPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
@@ -39,19 +37,14 @@
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
- mEditText = new EditText(view.getContext());
- // Give it an ID so it can be saved/restored
- mEditText.setId(android.R.id.edit);
+ mEditText = (EditText) view.findViewById(android.R.id.edit);
+
+ if (mEditText == null) {
+ throw new IllegalStateException("Dialog view must contain an EditText with id" +
+ " @android:id/edit");
+ }
mEditText.setText(getEditTextPreference().getText());
-
- ViewParent oldParent = mEditText.getParent();
- if (oldParent != view) {
- if (oldParent != null) {
- ((ViewGroup) oldParent).removeView(mEditText);
- }
- onAddEditTextToDialogView(view, mEditText);
- }
}
private EditTextPreference getEditTextPreference() {
@@ -65,20 +58,6 @@
return true;
}
- /**
- * Adds the EditText widget of this preference to the dialog's view.
- *
- * @param dialogView The dialog view.
- */
- protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
- ViewGroup container = (ViewGroup) dialogView
- .findViewById(R.id.edittext_container);
- if (container != null) {
- container.addView(editText, ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- }
- }
-
@Override
public void onDialogClosed(boolean positiveResult) {
diff --git a/v7/preference/src/android/support/v7/preference/Preference.java b/v7/preference/src/android/support/v7/preference/Preference.java
index 4f210ae..f386592 100644
--- a/v7/preference/src/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/android/support/v7/preference/Preference.java
@@ -516,6 +516,12 @@
} else {
setEnabledStateOnViews(holder.itemView, true);
}
+
+ final boolean selectable = isSelectable();
+ holder.itemView.setFocusable(selectable);
+
+ holder.setDividerAllowedAbove(selectable);
+ holder.setDividerAllowedBelow(selectable);
}
/**
@@ -749,9 +755,11 @@
* @param visible Set false if this preference should be hidden from the list.
*/
public final void setVisible(boolean visible) {
- mVisible = visible;
- if (mListener != null) {
- mListener.onPreferenceVisibilityChange(this);
+ if (mVisible != visible) {
+ mVisible = visible;
+ if (mListener != null) {
+ mListener.onPreferenceVisibilityChange(this);
+ }
}
}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
index 8231d89..221d3ea 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
@@ -18,6 +18,9 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -25,6 +28,7 @@
import android.support.annotation.XmlRes;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
+import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
@@ -51,7 +55,7 @@
* hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
* denote a screen break--that is the preferences contained within subsequent
* {@link PreferenceScreen} should be shown on another screen. The preference
- * framework handles showing these other screens from the preference hierarchy.
+ * framework handles this by calling {@link #onNavigateToScreen(PreferenceScreen)}.
* <p>
* The preference hierarchy can be formed in multiple ways:
* <li> From an XML file specifying the hierarchy
@@ -123,10 +127,7 @@
private int mLayoutResId = R.layout.preference_list_fragment;
- /**
- * The starting request code given out to preference framework.
- */
- private static final int FIRST_REQUEST_CODE = 100;
+ private final DividerDecoration mDividerDecoration = new DividerDecoration();
private static final int MSG_BIND_PREFERENCES = 1;
private Handler mHandler = new Handler() {
@@ -233,15 +234,28 @@
TypedArray a = mStyledContext.obtainStyledAttributes(null,
R.styleable.PreferenceFragmentCompat,
- R.attr.preferenceFragmentStyle,
+ R.attr.preferenceFragmentCompatStyle,
0);
- mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_layout,
+ mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_android_layout,
mLayoutResId);
+ final Drawable divider = a.getDrawable(
+ R.styleable.PreferenceFragmentCompat_android_divider);
+ final int dividerHeight = a.getInt(
+ R.styleable.PreferenceFragmentCompat_android_dividerHeight, -1);
+
a.recycle();
- final View view = inflater.inflate(mLayoutResId, container, false);
+ // Need to theme the inflater to pick up the preferenceFragmentListStyle
+ final TypedValue tv = new TypedValue();
+ getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
+ final int theme = tv.resourceId;
+
+ final Context themedContext = new ContextThemeWrapper(inflater.getContext(), theme);
+ final LayoutInflater themedInflater = inflater.cloneInContext(themedContext);
+
+ final View view = themedInflater.inflate(mLayoutResId, container, false);
final View rawListContainer = view.findViewById(R.id.list_container);
if (!(rawListContainer instanceof ViewGroup)) {
@@ -251,18 +265,49 @@
final ViewGroup listContainer = (ViewGroup) rawListContainer;
- final RecyclerView listView = onCreateRecyclerView(inflater, listContainer,
+ final RecyclerView listView = onCreateRecyclerView(themedInflater, listContainer,
savedInstanceState);
if (listView == null) {
throw new RuntimeException("Could not create RecyclerView");
}
mList = listView;
+
+ listView.addItemDecoration(mDividerDecoration);
+ setDivider(divider);
+ if (dividerHeight != -1) {
+ setDividerHeight(dividerHeight);
+ }
+
listContainer.addView(mList);
mHandler.post(mRequestFocus);
return view;
}
+ /**
+ * Sets the drawable that will be drawn between each item in the list.
+ * <p>
+ * <strong>Note:</strong> If the drawable does not have an intrinsic
+ * height, you should also call {@link #setDividerHeight(int)}.
+ *
+ * @param divider the drawable to use
+ * @attr ref R.styleable#PreferenceFragmentCompat_android_divider
+ */
+ public void setDivider(Drawable divider) {
+ mDividerDecoration.setDivider(divider);
+ }
+
+ /**
+ * Sets the height of the divider that will be drawn between each item in the list. Calling
+ * this will override the intrinsic height as set by {@link #setDivider(Drawable)}
+ *
+ * @param height The new height of the divider in pixels.
+ * @attr ref R.styleable#PreferenceFragmentCompat_android_dividerHeight
+ */
+ public void setDividerHeight(int height) {
+ mDividerDecoration.setDividerHeight(height);
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -574,4 +619,78 @@
public Fragment getCallbackFragment() {
return null;
}
+
+ private class DividerDecoration extends RecyclerView.ItemDecoration {
+
+ private Drawable mDivider;
+ private int mDividerHeight;
+
+ @Override
+ public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ if (mDivider == null) {
+ return;
+ }
+ final int childCount = parent.getChildCount();
+ final int width = parent.getWidth();
+ for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
+ final View view = parent.getChildAt(childViewIndex);
+ if (shouldDrawDividerAbove(view, parent)) {
+ int top = (int) ViewCompat.getY(view);
+ mDivider.setBounds(0, top, width, top + mDividerHeight);
+ mDivider.draw(c);
+ }
+ if (shouldDrawDividerBelow(view, parent)) {
+ int top = (int) ViewCompat.getY(view) + view.getHeight();
+ mDivider.setBounds(0, top, width, top + mDividerHeight);
+ mDivider.draw(c);
+ }
+ }
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+ RecyclerView.State state) {
+ if (shouldDrawDividerAbove(view, parent)) {
+ outRect.top = mDividerHeight;
+ }
+ if (shouldDrawDividerBelow(view, parent)) {
+ outRect.bottom = mDividerHeight;
+ }
+ }
+
+ private boolean shouldDrawDividerAbove(View view, RecyclerView parent) {
+ final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
+ return holder.getAdapterPosition() == 0 &&
+ ((PreferenceViewHolder) holder).isDividerAllowedAbove();
+ }
+
+ private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
+ final PreferenceViewHolder holder =
+ (PreferenceViewHolder) parent.getChildViewHolder(view);
+ boolean nextAllowed = true;
+ int index = parent.indexOfChild(view);
+ if (index < parent.getChildCount() - 1) {
+ final View nextView = parent.getChildAt(index + 1);
+ final PreferenceViewHolder nextHolder =
+ (PreferenceViewHolder) parent.getChildViewHolder(nextView);
+ nextAllowed = nextHolder.isDividerAllowedAbove();
+ }
+ return nextAllowed && holder.isDividerAllowedBelow();
+ }
+
+ public void setDivider(Drawable divider) {
+ if (divider != null) {
+ mDividerHeight = divider.getIntrinsicHeight();
+ } else {
+ mDividerHeight = 0;
+ }
+ mDivider = divider;
+ mList.invalidateItemDecorations();
+ }
+
+ public void setDividerHeight(int dividerHeight) {
+ mDividerHeight = dividerHeight;
+ mList.invalidateItemDecorations();
+ }
+ }
}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
index 9943087..c4ccc66 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
@@ -79,6 +79,14 @@
private int widgetResId;
private String name;
+ public PreferenceLayout() {}
+
+ public PreferenceLayout(PreferenceLayout other) {
+ resId = other.resId;
+ widgetResId = other.widgetResId;
+ name = other.name;
+ }
+
@Override
public boolean equals(Object o) {
if (!(o instanceof PreferenceLayout)) {
@@ -249,7 +257,14 @@
mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout);
- return mPreferenceLayouts.indexOf(mTempPreferenceLayout);
+ int viewType = mPreferenceLayouts.indexOf(mTempPreferenceLayout);
+ if (viewType != -1) {
+ return viewType;
+ } else {
+ viewType = mPreferenceLayouts.size();
+ mPreferenceLayouts.add(new PreferenceLayout(mTempPreferenceLayout));
+ return viewType;
+ }
}
@Override
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
index c7e247c..f9eaf22 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
@@ -28,6 +28,8 @@
*/
public class PreferenceViewHolder extends RecyclerView.ViewHolder {
private final SparseArray<View> mCachedViews = new SparseArray<>(4);
+ private boolean mDividerAllowedAbove;
+ private boolean mDividerAllowedBelow;
/* package */ PreferenceViewHolder(View itemView) {
super(itemView);
@@ -58,4 +60,44 @@
return v;
}
}
+
+ /**
+ * Dividers are only drawn between items if both items allow it, or above the first and below
+ * the last item if that item allows it.
+ *
+ * @return true if dividers are allowed above this item
+ */
+ public boolean isDividerAllowedAbove() {
+ return mDividerAllowedAbove;
+ }
+
+ /**
+ * Dividers are only drawn between items if both items allow it, or above the first and below
+ * the last item if that item allows it.
+ *
+ * @param allowed false to prevent dividers being drawn above this item
+ */
+ public void setDividerAllowedAbove(boolean allowed) {
+ mDividerAllowedAbove = allowed;
+ }
+
+ /**
+ * Dividers are only drawn between items if both items allow it, or above the first and below
+ * the last item if that item allows it.
+ *
+ * @return true if dividers are allowed below this item
+ */
+ public boolean isDividerAllowedBelow() {
+ return mDividerAllowedBelow;
+ }
+
+ /**
+ * Dividers are only drawn between items if both items allow it, or above the first and below
+ * the last item if that item allows it.
+ *
+ * @param allowed false to prevent dividers being drawn below this item
+ */
+ public void setDividerAllowedBelow(boolean allowed) {
+ mDividerAllowedBelow = allowed;
+ }
}
diff --git a/v7/recyclerview/api/23.txt b/v7/recyclerview/api/23.0.0.txt
similarity index 100%
rename from v7/recyclerview/api/23.txt
rename to v7/recyclerview/api/23.0.0.txt
diff --git a/v7/recyclerview/api/23.1.0.txt b/v7/recyclerview/api/23.1.0.txt
new file mode 100644
index 0000000..1f91036
--- /dev/null
+++ b/v7/recyclerview/api/23.1.0.txt
@@ -0,0 +1,864 @@
+package android.support.v7.recyclerview {
+
+ public final class R {
+ ctor public R();
+ }
+
+ public static final class R.attr {
+ ctor public R.attr();
+ field public static int layoutManager;
+ field public static int reverseLayout;
+ field public static int spanCount;
+ field public static int stackFromEnd;
+ }
+
+ public static final class R.dimen {
+ ctor public R.dimen();
+ field public static int item_touch_helper_max_drag_scroll_per_frame;
+ }
+
+ public static final class R.id {
+ ctor public R.id();
+ field public static int item_touch_helper_previous_elevation;
+ }
+
+ public static final class R.styleable {
+ ctor public R.styleable();
+ field public static final int[] RecyclerView;
+ field public static int RecyclerView_android_orientation;
+ field public static int RecyclerView_layoutManager;
+ field public static int RecyclerView_reverseLayout;
+ field public static int RecyclerView_spanCount;
+ field public static int RecyclerView_stackFromEnd;
+ }
+
+}
+
+package android.support.v7.util {
+
+ public class AsyncListUtil {
+ ctor public AsyncListUtil(java.lang.Class<T>, int, android.support.v7.util.AsyncListUtil.DataCallback<T>, android.support.v7.util.AsyncListUtil.ViewCallback);
+ method public T getItem(int);
+ method public int getItemCount();
+ method public void onRangeChanged();
+ method public void refresh();
+ }
+
+ public static abstract class AsyncListUtil.DataCallback {
+ ctor public AsyncListUtil.DataCallback();
+ method public abstract void fillData(T[], int, int);
+ method public int getMaxCachedTiles();
+ method public void recycleData(T[], int);
+ method public abstract int refreshData();
+ }
+
+ public static abstract class AsyncListUtil.ViewCallback {
+ ctor public AsyncListUtil.ViewCallback();
+ method public void extendRangeInto(int[], int[], int);
+ method public abstract void getItemRangeInto(int[]);
+ method public abstract void onDataRefresh();
+ method public abstract void onItemLoaded(int);
+ field public static final int HINT_SCROLL_ASC = 2; // 0x2
+ field public static final int HINT_SCROLL_DESC = 1; // 0x1
+ field public static final int HINT_SCROLL_NONE = 0; // 0x0
+ }
+
+ public class SortedList {
+ ctor public SortedList(java.lang.Class<T>, android.support.v7.util.SortedList.Callback<T>);
+ ctor public SortedList(java.lang.Class<T>, android.support.v7.util.SortedList.Callback<T>, int);
+ method public int add(T);
+ method public void addAll(T[], boolean);
+ method public void addAll(T...);
+ method public void addAll(java.util.Collection<T>);
+ method public void beginBatchedUpdates();
+ method public void clear();
+ method public void endBatchedUpdates();
+ method public T get(int) throws java.lang.IndexOutOfBoundsException;
+ method public int indexOf(T);
+ method public void recalculatePositionOfItemAt(int);
+ method public boolean remove(T);
+ method public T removeItemAt(int);
+ method public int size();
+ method public void updateItemAt(int, T);
+ field public static final int INVALID_POSITION = -1; // 0xffffffff
+ }
+
+ public static class SortedList.BatchedCallback extends android.support.v7.util.SortedList.Callback {
+ ctor public SortedList.BatchedCallback(android.support.v7.util.SortedList.Callback<T2>);
+ method public boolean areContentsTheSame(T2, T2);
+ method public boolean areItemsTheSame(T2, T2);
+ method public int compare(T2, T2);
+ method public void dispatchLastEvent();
+ method public void onChanged(int, int);
+ method public void onInserted(int, int);
+ method public void onMoved(int, int);
+ method public void onRemoved(int, int);
+ }
+
+ public static abstract class SortedList.Callback implements java.util.Comparator {
+ ctor public SortedList.Callback();
+ method public abstract boolean areContentsTheSame(T2, T2);
+ method public abstract boolean areItemsTheSame(T2, T2);
+ method public abstract int compare(T2, T2);
+ method public abstract void onChanged(int, int);
+ method public abstract void onInserted(int, int);
+ method public abstract void onMoved(int, int);
+ method public abstract void onRemoved(int, int);
+ }
+
+}
+
+package android.support.v7.widget {
+
+ public class DefaultItemAnimator extends android.support.v7.widget.SimpleItemAnimator {
+ ctor public DefaultItemAnimator();
+ method public boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+ method public boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+ method public boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void endAnimations();
+ method public boolean isRunning();
+ method public void runPendingAnimations();
+ }
+
+ public class GridLayoutManager extends android.support.v7.widget.LinearLayoutManager {
+ ctor public GridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public GridLayoutManager(android.content.Context, int);
+ ctor public GridLayoutManager(android.content.Context, int, int, boolean);
+ method public int getSpanCount();
+ method public android.support.v7.widget.GridLayoutManager.SpanSizeLookup getSpanSizeLookup();
+ method public void setSpanCount(int);
+ method public void setSpanSizeLookup(android.support.v7.widget.GridLayoutManager.SpanSizeLookup);
+ field public static final int DEFAULT_SPAN_COUNT = -1; // 0xffffffff
+ }
+
+ public static final class GridLayoutManager.DefaultSpanSizeLookup extends android.support.v7.widget.GridLayoutManager.SpanSizeLookup {
+ ctor public GridLayoutManager.DefaultSpanSizeLookup();
+ method public int getSpanSize(int);
+ }
+
+ public static class GridLayoutManager.LayoutParams extends android.support.v7.widget.RecyclerView.LayoutParams {
+ ctor public GridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public GridLayoutManager.LayoutParams(int, int);
+ ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public GridLayoutManager.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+ method public int getSpanIndex();
+ method public int getSpanSize();
+ field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+ }
+
+ public static abstract class GridLayoutManager.SpanSizeLookup {
+ ctor public GridLayoutManager.SpanSizeLookup();
+ method public int getSpanGroupIndex(int, int);
+ method public int getSpanIndex(int, int);
+ method public abstract int getSpanSize(int);
+ method public void invalidateSpanIndexCache();
+ method public boolean isSpanIndexCacheEnabled();
+ method public void setSpanIndexCacheEnabled(boolean);
+ }
+
+ public class LinearLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager implements android.support.v7.widget.helper.ItemTouchHelper.ViewDropHandler {
+ ctor public LinearLayoutManager(android.content.Context);
+ ctor public LinearLayoutManager(android.content.Context, int, boolean);
+ ctor public LinearLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+ method public android.graphics.PointF computeScrollVectorForPosition(int);
+ method public int findFirstCompletelyVisibleItemPosition();
+ method public int findFirstVisibleItemPosition();
+ method public int findLastCompletelyVisibleItemPosition();
+ method public int findLastVisibleItemPosition();
+ method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+ method protected int getExtraLayoutSpace(android.support.v7.widget.RecyclerView.State);
+ method public int getOrientation();
+ method public boolean getRecycleChildrenOnDetach();
+ method public boolean getReverseLayout();
+ method public boolean getStackFromEnd();
+ method protected boolean isLayoutRTL();
+ method public boolean isSmoothScrollbarEnabled();
+ method public void prepareForDrop(android.view.View, android.view.View, int, int);
+ method public void scrollToPositionWithOffset(int, int);
+ method public void setOrientation(int);
+ method public void setRecycleChildrenOnDetach(boolean);
+ method public void setReverseLayout(boolean);
+ method public void setSmoothScrollbarEnabled(boolean);
+ method public void setStackFromEnd(boolean);
+ field public static final int HORIZONTAL = 0; // 0x0
+ field public static final int INVALID_OFFSET = -2147483648; // 0x80000000
+ field public static final int VERTICAL = 1; // 0x1
+ }
+
+ protected static class LinearLayoutManager.LayoutChunkResult {
+ ctor protected LinearLayoutManager.LayoutChunkResult();
+ field public int mConsumed;
+ field public boolean mFinished;
+ field public boolean mFocusable;
+ field public boolean mIgnoreConsumed;
+ }
+
+ public abstract class LinearSmoothScroller extends android.support.v7.widget.RecyclerView.SmoothScroller {
+ ctor public LinearSmoothScroller(android.content.Context);
+ method public int calculateDtToFit(int, int, int, int, int);
+ method public int calculateDxToMakeVisible(android.view.View, int);
+ method public int calculateDyToMakeVisible(android.view.View, int);
+ method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
+ method protected int calculateTimeForDeceleration(int);
+ method protected int calculateTimeForScrolling(int);
+ method public abstract android.graphics.PointF computeScrollVectorForPosition(int);
+ method protected int getHorizontalSnapPreference();
+ method protected int getVerticalSnapPreference();
+ method protected void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+ method protected void onStart();
+ method protected void onStop();
+ method protected void onTargetFound(android.view.View, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+ method protected void updateActionForInterimTarget(android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+ field public static final int SNAP_TO_ANY = 0; // 0x0
+ field public static final int SNAP_TO_END = 1; // 0x1
+ field public static final int SNAP_TO_START = -1; // 0xffffffff
+ field protected final android.view.animation.DecelerateInterpolator mDecelerateInterpolator;
+ field protected int mInterimTargetDx;
+ field protected int mInterimTargetDy;
+ field protected final android.view.animation.LinearInterpolator mLinearInterpolator;
+ field protected android.graphics.PointF mTargetVector;
+ }
+
+ public abstract class OrientationHelper {
+ method public static android.support.v7.widget.OrientationHelper createHorizontalHelper(android.support.v7.widget.RecyclerView.LayoutManager);
+ method public static android.support.v7.widget.OrientationHelper createOrientationHelper(android.support.v7.widget.RecyclerView.LayoutManager, int);
+ method public static android.support.v7.widget.OrientationHelper createVerticalHelper(android.support.v7.widget.RecyclerView.LayoutManager);
+ method public abstract int getDecoratedEnd(android.view.View);
+ method public abstract int getDecoratedMeasurement(android.view.View);
+ method public abstract int getDecoratedMeasurementInOther(android.view.View);
+ method public abstract int getDecoratedStart(android.view.View);
+ method public abstract int getEnd();
+ method public abstract int getEndAfterPadding();
+ method public abstract int getEndPadding();
+ method public abstract int getStartAfterPadding();
+ method public abstract int getTotalSpace();
+ method public int getTotalSpaceChange();
+ method public abstract void offsetChild(android.view.View, int);
+ method public abstract void offsetChildren(int);
+ method public void onLayoutComplete();
+ field public static final int HORIZONTAL = 0; // 0x0
+ field public static final int VERTICAL = 1; // 0x1
+ field protected final android.support.v7.widget.RecyclerView.LayoutManager mLayoutManager;
+ }
+
+ public class RecyclerView extends android.view.ViewGroup {
+ ctor public RecyclerView(android.content.Context);
+ ctor public RecyclerView(android.content.Context, android.util.AttributeSet);
+ ctor public RecyclerView(android.content.Context, android.util.AttributeSet, int);
+ method public void addItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration, int);
+ method public void addItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
+ method public void addOnChildAttachStateChangeListener(android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener);
+ method public void addOnItemTouchListener(android.support.v7.widget.RecyclerView.OnItemTouchListener);
+ method public void addOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+ method public void clearOnChildAttachStateChangeListeners();
+ method public void clearOnScrollListeners();
+ method public int computeHorizontalScrollExtent();
+ method public int computeHorizontalScrollOffset();
+ method public int computeHorizontalScrollRange();
+ method public int computeVerticalScrollExtent();
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
+ method public boolean drawChild(android.graphics.Canvas, android.view.View, long);
+ method public android.view.View findChildViewUnder(float, float);
+ method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForAdapterPosition(int);
+ method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForItemId(long);
+ method public android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForLayoutPosition(int);
+ method public deprecated android.support.v7.widget.RecyclerView.ViewHolder findViewHolderForPosition(int);
+ method public boolean fling(int, int);
+ method public android.support.v7.widget.RecyclerView.Adapter getAdapter();
+ method public int getChildAdapterPosition(android.view.View);
+ method public long getChildItemId(android.view.View);
+ method public int getChildLayoutPosition(android.view.View);
+ 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 android.support.v7.widget.RecyclerView.ItemAnimator getItemAnimator();
+ method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
+ method public int getMaxFlingVelocity();
+ method public int getMinFlingVelocity();
+ method public android.support.v7.widget.RecyclerView.RecycledViewPool getRecycledViewPool();
+ method public int getScrollState();
+ method public boolean hasFixedSize();
+ method public boolean hasPendingAdapterUpdates();
+ method public void invalidateItemDecorations();
+ method public boolean isAnimating();
+ method public boolean isComputingLayout();
+ method public boolean isLayoutFrozen();
+ method public void offsetChildrenHorizontal(int);
+ method public void offsetChildrenVertical(int);
+ method public void onChildAttachedToWindow(android.view.View);
+ method public void onChildDetachedFromWindow(android.view.View);
+ method public void onDraw(android.graphics.Canvas);
+ method protected void onLayout(boolean, int, int, int, int);
+ method public void onScrollStateChanged(int);
+ method public void onScrolled(int, int);
+ method public void removeItemDecoration(android.support.v7.widget.RecyclerView.ItemDecoration);
+ method public void removeOnChildAttachStateChangeListener(android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener);
+ method public void removeOnItemTouchListener(android.support.v7.widget.RecyclerView.OnItemTouchListener);
+ method public void removeOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+ method public void scrollToPosition(int);
+ method public void setAccessibilityDelegateCompat(android.support.v7.widget.RecyclerViewAccessibilityDelegate);
+ method public void setAdapter(android.support.v7.widget.RecyclerView.Adapter);
+ method public void setChildDrawingOrderCallback(android.support.v7.widget.RecyclerView.ChildDrawingOrderCallback);
+ method public void setHasFixedSize(boolean);
+ method public void setItemAnimator(android.support.v7.widget.RecyclerView.ItemAnimator);
+ method public void setItemViewCacheSize(int);
+ method public void setLayoutFrozen(boolean);
+ method public void setLayoutManager(android.support.v7.widget.RecyclerView.LayoutManager);
+ method public deprecated void setOnScrollListener(android.support.v7.widget.RecyclerView.OnScrollListener);
+ method public void setRecycledViewPool(android.support.v7.widget.RecyclerView.RecycledViewPool);
+ method public void setRecyclerListener(android.support.v7.widget.RecyclerView.RecyclerListener);
+ method public void setScrollingTouchSlop(int);
+ method public void setViewCacheExtension(android.support.v7.widget.RecyclerView.ViewCacheExtension);
+ method public void smoothScrollBy(int, int);
+ method public void smoothScrollToPosition(int);
+ method public void stopScroll();
+ method public void swapAdapter(android.support.v7.widget.RecyclerView.Adapter, boolean);
+ field public static final int HORIZONTAL = 0; // 0x0
+ field public static final int INVALID_TYPE = -1; // 0xffffffff
+ field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+ field public static final int NO_POSITION = -1; // 0xffffffff
+ 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
+ field public static final int TOUCH_SLOP_DEFAULT = 0; // 0x0
+ field public static final int TOUCH_SLOP_PAGING = 1; // 0x1
+ field public static final int VERTICAL = 1; // 0x1
+ }
+
+ public static abstract class RecyclerView.Adapter {
+ ctor public RecyclerView.Adapter();
+ method public final void bindViewHolder(VH, int);
+ method public final VH createViewHolder(android.view.ViewGroup, int);
+ method public abstract int getItemCount();
+ method public long getItemId(int);
+ method public int getItemViewType(int);
+ method public final boolean hasObservers();
+ method public final boolean hasStableIds();
+ method public final void notifyDataSetChanged();
+ method public final void notifyItemChanged(int);
+ method public final void notifyItemChanged(int, java.lang.Object);
+ method public final void notifyItemInserted(int);
+ method public final void notifyItemMoved(int, int);
+ method public final void notifyItemRangeChanged(int, int);
+ method public final void notifyItemRangeChanged(int, int, java.lang.Object);
+ method public final void notifyItemRangeInserted(int, int);
+ method public final void notifyItemRangeRemoved(int, int);
+ method public final void notifyItemRemoved(int);
+ method public void onAttachedToRecyclerView(android.support.v7.widget.RecyclerView);
+ method public abstract void onBindViewHolder(VH, int);
+ method public void onBindViewHolder(VH, int, java.util.List<java.lang.Object>);
+ method public abstract VH onCreateViewHolder(android.view.ViewGroup, int);
+ method public void onDetachedFromRecyclerView(android.support.v7.widget.RecyclerView);
+ method public boolean onFailedToRecycleView(VH);
+ method public void onViewAttachedToWindow(VH);
+ method public void onViewDetachedFromWindow(VH);
+ method public void onViewRecycled(VH);
+ method public void registerAdapterDataObserver(android.support.v7.widget.RecyclerView.AdapterDataObserver);
+ method public void setHasStableIds(boolean);
+ method public void unregisterAdapterDataObserver(android.support.v7.widget.RecyclerView.AdapterDataObserver);
+ }
+
+ public static abstract class RecyclerView.AdapterDataObserver {
+ ctor public RecyclerView.AdapterDataObserver();
+ method public void onChanged();
+ method public void onItemRangeChanged(int, int);
+ method public void onItemRangeChanged(int, int, java.lang.Object);
+ method public void onItemRangeInserted(int, int);
+ method public void onItemRangeMoved(int, int, int);
+ method public void onItemRangeRemoved(int, int);
+ }
+
+ public static abstract interface RecyclerView.ChildDrawingOrderCallback {
+ method public abstract int onGetChildDrawingOrder(int, int);
+ }
+
+ public static abstract class RecyclerView.ItemAnimator {
+ ctor public RecyclerView.ItemAnimator();
+ method public abstract boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public boolean canReuseUpdatedViewHolder(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAnimationsFinished();
+ method public abstract void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public abstract void endAnimations();
+ method public long getAddDuration();
+ method public long getChangeDuration();
+ method public long getMoveDuration();
+ method public long getRemoveDuration();
+ method public abstract boolean isRunning();
+ method public final boolean isRunning(android.support.v7.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener);
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+ method public void onAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder, int, java.util.List<java.lang.Object>);
+ method public abstract void runPendingAnimations();
+ method public void setAddDuration(long);
+ method public void setChangeDuration(long);
+ method public void setMoveDuration(long);
+ method public void setRemoveDuration(long);
+ field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+ field public static final int FLAG_CHANGED = 2; // 0x2
+ field public static final int FLAG_INVALIDATED = 4; // 0x4
+ field public static final int FLAG_MOVED = 2048; // 0x800
+ field public static final int FLAG_REMOVED = 8; // 0x8
+ }
+
+ public static abstract class RecyclerView.ItemAnimator.AdapterChanges implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
+ method public abstract void onAnimationsFinished();
+ }
+
+ public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+ ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder, int);
+ field public int bottom;
+ field public int changeFlags;
+ field public int left;
+ field public int right;
+ field public int top;
+ }
+
+ public static abstract class RecyclerView.ItemDecoration {
+ ctor public RecyclerView.ItemDecoration();
+ method public deprecated void getItemOffsets(android.graphics.Rect, int, android.support.v7.widget.RecyclerView);
+ method public void getItemOffsets(android.graphics.Rect, android.view.View, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+ method public void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+ method public deprecated void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView);
+ method public void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State);
+ method public deprecated void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView);
+ }
+
+ public static abstract class RecyclerView.LayoutManager {
+ ctor public RecyclerView.LayoutManager();
+ method public void addDisappearingView(android.view.View);
+ method public void addDisappearingView(android.view.View, int);
+ method public void addView(android.view.View);
+ method public void addView(android.view.View, int);
+ method public void assertInLayoutOrScroll(java.lang.String);
+ method public void assertNotInLayoutOrScroll(java.lang.String);
+ method public void attachView(android.view.View, int, android.support.v7.widget.RecyclerView.LayoutParams);
+ method public void attachView(android.view.View, int);
+ method public void attachView(android.view.View);
+ method public void calculateItemDecorationsForChild(android.view.View, android.graphics.Rect);
+ method public boolean canScrollHorizontally();
+ method public boolean canScrollVertically();
+ method public boolean checkLayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+ method public int computeHorizontalScrollExtent(android.support.v7.widget.RecyclerView.State);
+ method public int computeHorizontalScrollOffset(android.support.v7.widget.RecyclerView.State);
+ method public int computeHorizontalScrollRange(android.support.v7.widget.RecyclerView.State);
+ method public int computeVerticalScrollExtent(android.support.v7.widget.RecyclerView.State);
+ method public int computeVerticalScrollOffset(android.support.v7.widget.RecyclerView.State);
+ method public int computeVerticalScrollRange(android.support.v7.widget.RecyclerView.State);
+ method public void detachAndScrapAttachedViews(android.support.v7.widget.RecyclerView.Recycler);
+ method public void detachAndScrapView(android.view.View, android.support.v7.widget.RecyclerView.Recycler);
+ method public void detachAndScrapViewAt(int, android.support.v7.widget.RecyclerView.Recycler);
+ method public void detachView(android.view.View);
+ method public void detachViewAt(int);
+ method public void endAnimation(android.view.View);
+ method public android.view.View findViewByPosition(int);
+ method public abstract android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+ method public android.support.v7.widget.RecyclerView.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
+ method public android.support.v7.widget.RecyclerView.LayoutParams generateLayoutParams(android.content.Context, android.util.AttributeSet);
+ method public int getBaseline();
+ method public int getBottomDecorationHeight(android.view.View);
+ method public android.view.View getChildAt(int);
+ method public int getChildCount();
+ method public static int getChildMeasureSpec(int, int, int, boolean);
+ method public boolean getClipToPadding();
+ method public int getColumnCountForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+ method public int getDecoratedBottom(android.view.View);
+ method public int getDecoratedLeft(android.view.View);
+ method public int getDecoratedMeasuredHeight(android.view.View);
+ method public int getDecoratedMeasuredWidth(android.view.View);
+ method public int getDecoratedRight(android.view.View);
+ method public int getDecoratedTop(android.view.View);
+ method public android.view.View getFocusedChild();
+ method public int getHeight();
+ method public int getItemCount();
+ method public int getItemViewType(android.view.View);
+ method public int getLayoutDirection();
+ method public int getLeftDecorationWidth(android.view.View);
+ method public int getMinimumHeight();
+ method public int getMinimumWidth();
+ method public int getPaddingBottom();
+ method public int getPaddingEnd();
+ method public int getPaddingLeft();
+ method public int getPaddingRight();
+ method public int getPaddingStart();
+ method public int getPaddingTop();
+ method public int getPosition(android.view.View);
+ method public static android.support.v7.widget.RecyclerView.LayoutManager.Properties getProperties(android.content.Context, android.util.AttributeSet, int, int);
+ method public int getRightDecorationWidth(android.view.View);
+ method public int getRowCountForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+ method public int getSelectionModeForAccessibility(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+ method public int getTopDecorationHeight(android.view.View);
+ method public int getWidth();
+ method public boolean hasFocus();
+ method public void ignoreView(android.view.View);
+ method public boolean isAttachedToWindow();
+ method public boolean isFocused();
+ method public boolean isLayoutHierarchical(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+ method public boolean isSmoothScrolling();
+ method public void layoutDecorated(android.view.View, int, int, int, int);
+ method public void measureChild(android.view.View, int, int);
+ method public void measureChildWithMargins(android.view.View, int, int);
+ method public void moveView(int, int);
+ method public void offsetChildrenHorizontal(int);
+ method public void offsetChildrenVertical(int);
+ method public void onAdapterChanged(android.support.v7.widget.RecyclerView.Adapter, android.support.v7.widget.RecyclerView.Adapter);
+ method public boolean onAddFocusables(android.support.v7.widget.RecyclerView, java.util.ArrayList<android.view.View>, int, int);
+ method public void onAttachedToWindow(android.support.v7.widget.RecyclerView);
+ method public deprecated void onDetachedFromWindow(android.support.v7.widget.RecyclerView);
+ method public void onDetachedFromWindow(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.Recycler);
+ method public android.view.View onFocusSearchFailed(android.view.View, int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+ method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityEvent(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.accessibility.AccessibilityEvent);
+ method public void onInitializeAccessibilityNodeInfo(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method public void onInitializeAccessibilityNodeInfoForItem(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.View, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+ method public android.view.View onInterceptFocusSearch(android.view.View, int);
+ method public void onItemsAdded(android.support.v7.widget.RecyclerView, int, int);
+ method public void onItemsChanged(android.support.v7.widget.RecyclerView);
+ method public void onItemsMoved(android.support.v7.widget.RecyclerView, int, int, int);
+ method public void onItemsRemoved(android.support.v7.widget.RecyclerView, int, int);
+ method public void onItemsUpdated(android.support.v7.widget.RecyclerView, int, int);
+ method public void onItemsUpdated(android.support.v7.widget.RecyclerView, int, int, java.lang.Object);
+ method public void onLayoutChildren(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+ method public void onMeasure(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, int, int);
+ method public deprecated boolean onRequestChildFocus(android.support.v7.widget.RecyclerView, android.view.View, android.view.View);
+ method public boolean onRequestChildFocus(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State, android.view.View, android.view.View);
+ method public void onRestoreInstanceState(android.os.Parcelable);
+ method public android.os.Parcelable onSaveInstanceState();
+ method public void onScrollStateChanged(int);
+ method public boolean performAccessibilityAction(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, int, android.os.Bundle);
+ method public boolean performAccessibilityActionForItem(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State, android.view.View, int, android.os.Bundle);
+ method public void postOnAnimation(java.lang.Runnable);
+ method public void removeAllViews();
+ method public void removeAndRecycleAllViews(android.support.v7.widget.RecyclerView.Recycler);
+ method public void removeAndRecycleView(android.view.View, android.support.v7.widget.RecyclerView.Recycler);
+ method public void removeAndRecycleViewAt(int, android.support.v7.widget.RecyclerView.Recycler);
+ method public boolean removeCallbacks(java.lang.Runnable);
+ method public void removeDetachedView(android.view.View);
+ method public void removeView(android.view.View);
+ method public void removeViewAt(int);
+ method public boolean requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
+ method public void requestLayout();
+ method public void requestSimpleAnimationsInNextLayout();
+ method public int scrollHorizontallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
+ 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 setMeasuredDimension(int, int);
+ method public void smoothScrollToPosition(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.State, int);
+ method public void startSmoothScroll(android.support.v7.widget.RecyclerView.SmoothScroller);
+ method public void stopIgnoringView(android.view.View);
+ method public boolean supportsPredictiveItemAnimations();
+ }
+
+ public static class RecyclerView.LayoutManager.Properties {
+ ctor public RecyclerView.LayoutManager.Properties();
+ field public int orientation;
+ field public boolean reverseLayout;
+ field public int spanCount;
+ field public boolean stackFromEnd;
+ }
+
+ public static class RecyclerView.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+ ctor public RecyclerView.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public RecyclerView.LayoutParams(int, int);
+ ctor public RecyclerView.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public RecyclerView.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public RecyclerView.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+ method public int getViewAdapterPosition();
+ method public int getViewLayoutPosition();
+ method public deprecated int getViewPosition();
+ method public boolean isItemChanged();
+ method public boolean isItemRemoved();
+ method public boolean isViewInvalid();
+ method public boolean viewNeedsUpdate();
+ }
+
+ public static abstract interface RecyclerView.OnChildAttachStateChangeListener {
+ method public abstract void onChildViewAttachedToWindow(android.view.View);
+ method public abstract void onChildViewDetachedFromWindow(android.view.View);
+ }
+
+ public static abstract interface RecyclerView.OnItemTouchListener {
+ method public abstract boolean onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+ method public abstract void onRequestDisallowInterceptTouchEvent(boolean);
+ method public abstract void onTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+ }
+
+ public static abstract class RecyclerView.OnScrollListener {
+ ctor public RecyclerView.OnScrollListener();
+ method public void onScrollStateChanged(android.support.v7.widget.RecyclerView, int);
+ method public void onScrolled(android.support.v7.widget.RecyclerView, int, int);
+ }
+
+ public static class RecyclerView.RecycledViewPool {
+ ctor public RecyclerView.RecycledViewPool();
+ method public void clear();
+ method public android.support.v7.widget.RecyclerView.ViewHolder getRecycledView(int);
+ method public void putRecycledView(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void setMaxRecycledViews(int, int);
+ }
+
+ public final class RecyclerView.Recycler {
+ ctor public RecyclerView.Recycler();
+ method public void bindViewToPosition(android.view.View, int);
+ method public void clear();
+ method public int convertPreLayoutPositionToPostLayout(int);
+ method public java.util.List<android.support.v7.widget.RecyclerView.ViewHolder> getScrapList();
+ method public android.view.View getViewForPosition(int);
+ method public void recycleView(android.view.View);
+ method public void setViewCacheSize(int);
+ }
+
+ public static abstract interface RecyclerView.RecyclerListener {
+ method public abstract void onViewRecycled(android.support.v7.widget.RecyclerView.ViewHolder);
+ }
+
+ public static class RecyclerView.SimpleOnItemTouchListener implements android.support.v7.widget.RecyclerView.OnItemTouchListener {
+ ctor public RecyclerView.SimpleOnItemTouchListener();
+ method public boolean onInterceptTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+ method public void onRequestDisallowInterceptTouchEvent(boolean);
+ method public void onTouchEvent(android.support.v7.widget.RecyclerView, android.view.MotionEvent);
+ }
+
+ public static abstract class RecyclerView.SmoothScroller {
+ ctor public RecyclerView.SmoothScroller();
+ method public android.view.View findViewByPosition(int);
+ method public int getChildCount();
+ method public int getChildPosition(android.view.View);
+ method public android.support.v7.widget.RecyclerView.LayoutManager getLayoutManager();
+ method public int getTargetPosition();
+ method public deprecated void instantScrollToPosition(int);
+ method public boolean isPendingInitialRun();
+ method public boolean isRunning();
+ method protected void normalize(android.graphics.PointF);
+ method protected void onChildAttachedToWindow(android.view.View);
+ method protected abstract void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+ method protected abstract void onStart();
+ method protected abstract void onStop();
+ method protected abstract void onTargetFound(android.view.View, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
+ method public void setTargetPosition(int);
+ method protected final void stop();
+ }
+
+ public static class RecyclerView.SmoothScroller.Action {
+ ctor public RecyclerView.SmoothScroller.Action(int, int);
+ ctor public RecyclerView.SmoothScroller.Action(int, int, int);
+ ctor public RecyclerView.SmoothScroller.Action(int, int, int, android.view.animation.Interpolator);
+ method public int getDuration();
+ method public int getDx();
+ method public int getDy();
+ method public android.view.animation.Interpolator getInterpolator();
+ method public void jumpTo(int);
+ method public void setDuration(int);
+ method public void setDx(int);
+ method public void setDy(int);
+ method public void setInterpolator(android.view.animation.Interpolator);
+ method public void update(int, int, int, android.view.animation.Interpolator);
+ field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+ }
+
+ public static class RecyclerView.State {
+ ctor public RecyclerView.State();
+ method public boolean didStructureChange();
+ method public T get(int);
+ method public int getItemCount();
+ method public int getTargetScrollPosition();
+ method public boolean hasTargetScrollPosition();
+ method public boolean isPreLayout();
+ method public void put(int, java.lang.Object);
+ method public void remove(int);
+ method public boolean willRunPredictiveAnimations();
+ method public boolean willRunSimpleAnimations();
+ }
+
+ public static abstract class RecyclerView.ViewCacheExtension {
+ ctor public RecyclerView.ViewCacheExtension();
+ method public abstract android.view.View getViewForPositionAndType(android.support.v7.widget.RecyclerView.Recycler, int, int);
+ }
+
+ public static abstract class RecyclerView.ViewHolder {
+ ctor public RecyclerView.ViewHolder(android.view.View);
+ method public final int getAdapterPosition();
+ method public final long getItemId();
+ method public final int getItemViewType();
+ method public final int getLayoutPosition();
+ method public final int getOldPosition();
+ method public final deprecated int getPosition();
+ method public final boolean isRecyclable();
+ method public final void setIsRecyclable(boolean);
+ field public final android.view.View itemView;
+ }
+
+ public class RecyclerViewAccessibilityDelegate extends android.support.v4.view.AccessibilityDelegateCompat {
+ ctor public RecyclerViewAccessibilityDelegate(android.support.v7.widget.RecyclerView);
+ }
+
+ public abstract class SimpleItemAnimator extends android.support.v7.widget.RecyclerView.ItemAnimator {
+ ctor public SimpleItemAnimator();
+ method public abstract boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+ method public boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+ method public boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+ method public final void dispatchChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+ method public final void dispatchMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public boolean getSupportsChangeAnimations();
+ method public void onAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+ method public void onChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+ method public void onMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void setSupportsChangeAnimations(boolean);
+ }
+
+ public class StaggeredGridLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager {
+ ctor public StaggeredGridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public StaggeredGridLayoutManager(int, int);
+ method public int[] findFirstCompletelyVisibleItemPositions(int[]);
+ method public int[] findFirstVisibleItemPositions(int[]);
+ method public int[] findLastCompletelyVisibleItemPositions(int[]);
+ method public int[] findLastVisibleItemPositions(int[]);
+ method public android.support.v7.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+ method public int getGapStrategy();
+ method public int getOrientation();
+ method public boolean getReverseLayout();
+ method public int getSpanCount();
+ method public void invalidateSpanAssignments();
+ method public void scrollToPositionWithOffset(int, int);
+ method public void setGapStrategy(int);
+ method public void setOrientation(int);
+ method public void setReverseLayout(boolean);
+ method public void setSpanCount(int);
+ field public static final deprecated int GAP_HANDLING_LAZY = 1; // 0x1
+ field public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; // 0x2
+ field public static final int GAP_HANDLING_NONE = 0; // 0x0
+ field public static final int HORIZONTAL = 0; // 0x0
+ field public static final java.lang.String TAG = "StaggeredGridLayoutManager";
+ field public static final int VERTICAL = 1; // 0x1
+ }
+
+ public static class StaggeredGridLayoutManager.LayoutParams extends android.support.v7.widget.RecyclerView.LayoutParams {
+ ctor public StaggeredGridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
+ ctor public StaggeredGridLayoutManager.LayoutParams(int, int);
+ ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+ ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
+ ctor public StaggeredGridLayoutManager.LayoutParams(android.support.v7.widget.RecyclerView.LayoutParams);
+ method public final int getSpanIndex();
+ method public boolean isFullSpan();
+ method public void setFullSpan(boolean);
+ field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+ }
+
+}
+
+package android.support.v7.widget.helper {
+
+ public class ItemTouchHelper extends android.support.v7.widget.RecyclerView.ItemDecoration implements android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener {
+ ctor public ItemTouchHelper(android.support.v7.widget.helper.ItemTouchHelper.Callback);
+ method public void attachToRecyclerView(android.support.v7.widget.RecyclerView);
+ method public void onChildViewAttachedToWindow(android.view.View);
+ method public void onChildViewDetachedFromWindow(android.view.View);
+ method public void startDrag(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void startSwipe(android.support.v7.widget.RecyclerView.ViewHolder);
+ field public static final int ACTION_STATE_DRAG = 2; // 0x2
+ field public static final int ACTION_STATE_IDLE = 0; // 0x0
+ field public static final int ACTION_STATE_SWIPE = 1; // 0x1
+ field public static final int ANIMATION_TYPE_DRAG = 8; // 0x8
+ field public static final int ANIMATION_TYPE_SWIPE_CANCEL = 4; // 0x4
+ field public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 2; // 0x2
+ field public static final int DOWN = 2; // 0x2
+ field public static final int END = 32; // 0x20
+ field public static final int LEFT = 4; // 0x4
+ field public static final int RIGHT = 8; // 0x8
+ field public static final int START = 16; // 0x10
+ field public static final int UP = 1; // 0x1
+ }
+
+ public static abstract class ItemTouchHelper.Callback {
+ ctor public ItemTouchHelper.Callback();
+ method public boolean canDropOver(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public android.support.v7.widget.RecyclerView.ViewHolder chooseDropTarget(android.support.v7.widget.RecyclerView.ViewHolder, java.util.List<android.support.v7.widget.RecyclerView.ViewHolder>, int, int);
+ method public void clearView(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public int convertToAbsoluteDirection(int, int);
+ method public static int convertToRelativeDirection(int, int);
+ method public long getAnimationDuration(android.support.v7.widget.RecyclerView, int, float, float);
+ method public int getBoundingBoxMargin();
+ method public static android.support.v7.widget.helper.ItemTouchUIUtil getDefaultUIUtil();
+ method public float getMoveThreshold(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public abstract int getMovementFlags(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public float getSwipeThreshold(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public int interpolateOutOfBoundsScroll(android.support.v7.widget.RecyclerView, int, int, int, long);
+ method public boolean isItemViewSwipeEnabled();
+ method public boolean isLongPressDragEnabled();
+ method public static int makeFlag(int, int);
+ method public static int makeMovementFlags(int, int);
+ method public void onChildDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+ method public void onChildDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+ method public abstract boolean onMove(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onMoved(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int);
+ method public void onSelectedChanged(android.support.v7.widget.RecyclerView.ViewHolder, int);
+ method public abstract void onSwiped(android.support.v7.widget.RecyclerView.ViewHolder, int);
+ field public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; // 0xc8
+ field public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; // 0xfa
+ }
+
+ public static abstract class ItemTouchHelper.SimpleCallback extends android.support.v7.widget.helper.ItemTouchHelper.Callback {
+ ctor public ItemTouchHelper.SimpleCallback(int, int);
+ method public int getDragDirs(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public int getMovementFlags(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public int getSwipeDirs(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void setDefaultDragDirs(int);
+ method public void setDefaultSwipeDirs(int);
+ }
+
+ public static abstract interface ItemTouchHelper.ViewDropHandler {
+ method public abstract void prepareForDrop(android.view.View, android.view.View, int, int);
+ }
+
+ public abstract interface ItemTouchUIUtil {
+ method public abstract void clearView(android.view.View);
+ method public abstract void onDraw(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.view.View, float, float, int, boolean);
+ method public abstract void onDrawOver(android.graphics.Canvas, android.support.v7.widget.RecyclerView, android.view.View, float, float, int, boolean);
+ method public abstract void onSelected(android.view.View);
+ }
+
+}
+
+package android.support.v7.widget.util {
+
+ public abstract class SortedListAdapterCallback extends android.support.v7.util.SortedList.Callback {
+ ctor public SortedListAdapterCallback(android.support.v7.widget.RecyclerView.Adapter);
+ method public void onChanged(int, int);
+ method public void onInserted(int, int);
+ method public void onMoved(int, int);
+ method public void onRemoved(int, int);
+ }
+
+}
+
diff --git a/v7/recyclerview/api/current.txt b/v7/recyclerview/api/current.txt
index e37956e..1f91036 100644
--- a/v7/recyclerview/api/current.txt
+++ b/v7/recyclerview/api/current.txt
@@ -110,7 +110,7 @@
package android.support.v7.widget {
- public class DefaultItemAnimator extends android.support.v7.widget.RecyclerView.ItemAnimator {
+ public class DefaultItemAnimator extends android.support.v7.widget.SimpleItemAnimator {
ctor public DefaultItemAnimator();
method public boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
@@ -378,48 +378,57 @@
public static abstract class RecyclerView.ItemAnimator {
ctor public RecyclerView.ItemAnimator();
- method public abstract boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
- method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
- method public abstract boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
- method public abstract boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
- method public final void dispatchAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
- method public final void dispatchAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public abstract boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public boolean canReuseUpdatedViewHolder(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
method public final void dispatchAnimationsFinished();
- method public final void dispatchChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
- method public final void dispatchChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
- method public final void dispatchMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
- method public final void dispatchMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
- method public final void dispatchRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
- method public final void dispatchRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
method public abstract void endAnimation(android.support.v7.widget.RecyclerView.ViewHolder);
method public abstract void endAnimations();
method public long getAddDuration();
method public long getChangeDuration();
method public long getMoveDuration();
method public long getRemoveDuration();
- method public boolean getSupportsChangeAnimations();
method public abstract boolean isRunning();
method public final boolean isRunning(android.support.v7.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener);
- method public void onAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
- method public void onAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
- method public void onChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
- method public void onChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
- method public void onMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
- method public void onMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
- method public void onRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
- method public void onRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+ method public void onAnimationFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onAnimationStarted(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder);
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.ViewHolder, int, java.util.List<java.lang.Object>);
method public abstract void runPendingAnimations();
method public void setAddDuration(long);
method public void setChangeDuration(long);
method public void setMoveDuration(long);
method public void setRemoveDuration(long);
- method public void setSupportsChangeAnimations(boolean);
+ field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+ field public static final int FLAG_CHANGED = 2; // 0x2
+ field public static final int FLAG_INVALIDATED = 4; // 0x4
+ field public static final int FLAG_MOVED = 2048; // 0x800
+ field public static final int FLAG_REMOVED = 8; // 0x8
+ }
+
+ public static abstract class RecyclerView.ItemAnimator.AdapterChanges implements java.lang.annotation.Annotation {
}
public static abstract interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
method public abstract void onAnimationsFinished();
}
+ public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+ ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(android.support.v7.widget.RecyclerView.ViewHolder, int);
+ field public int bottom;
+ field public int changeFlags;
+ field public int left;
+ field public int right;
+ field public int top;
+ }
+
public static abstract class RecyclerView.ItemDecoration {
ctor public RecyclerView.ItemDecoration();
method public deprecated void getItemOffsets(android.graphics.Rect, int, android.support.v7.widget.RecyclerView);
@@ -670,7 +679,6 @@
method public int getTargetScrollPosition();
method public boolean hasTargetScrollPosition();
method public boolean isPreLayout();
- method public void onViewIgnored(android.support.v7.widget.RecyclerView.ViewHolder);
method public void put(int, java.lang.Object);
method public void remove(int);
method public boolean willRunPredictiveAnimations();
@@ -699,6 +707,36 @@
ctor public RecyclerViewAccessibilityDelegate(android.support.v7.widget.RecyclerView);
}
+ public abstract class SimpleItemAnimator extends android.support.v7.widget.RecyclerView.ItemAnimator {
+ ctor public SimpleItemAnimator();
+ method public abstract boolean animateAdd(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public boolean animateAppearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateChange(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+ method public boolean animateDisappearance(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateMove(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int, int);
+ method public boolean animatePersistence(android.support.v7.widget.RecyclerView.ViewHolder, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo, android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+ method public abstract boolean animateRemove(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+ method public final void dispatchChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+ method public final void dispatchMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public final void dispatchRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public boolean getSupportsChangeAnimations();
+ method public void onAddFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onAddStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onChangeFinished(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+ method public void onChangeStarting(android.support.v7.widget.RecyclerView.ViewHolder, boolean);
+ method public void onMoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onMoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onRemoveFinished(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void onRemoveStarting(android.support.v7.widget.RecyclerView.ViewHolder);
+ method public void setSupportsChangeAnimations(boolean);
+ }
+
public class StaggeredGridLayoutManager extends android.support.v7.widget.RecyclerView.LayoutManager {
ctor public StaggeredGridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
ctor public StaggeredGridLayoutManager(int, int);
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index 25b686d..c9f1a22 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -78,6 +78,17 @@
artifacts.add('archives', sourcesJarTask);
}
+// TODO make this generic for all projects
+afterEvaluate {
+ def originalTask = tasks['packageDebugAndroidTest']
+ tasks['assembleDebugAndroidTest'].doLast {
+ copy {
+ from(originalTask.outputFile)
+ into(rootProject.ext.testApkDistOut)
+ }
+ }
+}
+
uploadArchives {
repositories {
mavenDeployer {
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/widget/ViewInfoStoreTest.java b/v7/recyclerview/jvm-tests/src/android/support/v7/widget/ViewInfoStoreTest.java
new file mode 100644
index 0000000..559bc6b
--- /dev/null
+++ b/v7/recyclerview/jvm-tests/src/android/support/v7/widget/ViewInfoStoreTest.java
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import junit.framework.TestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.Pair;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_POST;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
+import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+
+@SuppressWarnings("ConstantConditions")
+@RunWith(JUnit4.class)
+public class ViewInfoStoreTest extends TestCase {
+ ViewInfoStore mStore;
+ LoggingProcessCallback mCallback;
+ @Before
+ public void prepare() {
+ mStore = new ViewInfoStore();
+ mCallback = new LoggingProcessCallback();
+ }
+
+ @Test
+ public void addToPreLayout() {
+ RecyclerView.ViewHolder vh = new MockViewHolder();
+ MockInfo info = new MockInfo();
+ mStore.addToPreLayout(vh, info);
+ assertSame(info, find(vh, FLAG_PRE));
+ assertTrue(mStore.isInPreLayout(vh));
+ mStore.removeViewHolder(vh);
+ assertFalse(mStore.isInPreLayout(vh));
+ }
+
+ @Test
+ public void addToPostLayout() {
+ RecyclerView.ViewHolder vh = new MockViewHolder();
+ MockInfo info = new MockInfo();
+ mStore.addToPostLayout(vh, info);
+ assertSame(info, find(vh, FLAG_POST));
+ mStore.removeViewHolder(vh);
+ assertNull(find(vh, FLAG_POST));
+ }
+
+ @Test
+ public void popFromPreLayout() {
+ assertEquals(0, sizeOf(FLAG_PRE));
+ RecyclerView.ViewHolder vh = new MockViewHolder();
+ MockInfo info = new MockInfo();
+ mStore.addToPreLayout(vh, info);
+ assertSame(info, mStore.popFromPreLayout(vh));
+ assertNull(mStore.popFromPreLayout(vh));
+ }
+
+ @Test
+ public void addToOldChangeHolders() {
+ RecyclerView.ViewHolder vh = new MockViewHolder();
+ mStore.addToOldChangeHolders(1, vh);
+ assertSame(vh, mStore.getFromOldChangeHolders(1));
+ mStore.removeViewHolder(vh);
+ assertNull(mStore.getFromOldChangeHolders(1));
+ }
+
+ @Test
+ public void appearListTests() {
+ RecyclerView.ViewHolder vh = new MockViewHolder();
+ RecyclerView.ItemAnimator.ItemHolderInfo info = new MockInfo();
+ mStore.addToAppearedInPreLayoutHolders(vh, info);
+ assertEquals(1, sizeOf(FLAG_APPEAR));
+ RecyclerView.ViewHolder vh2 = new MockViewHolder();
+ mStore.addToAppearedInPreLayoutHolders(vh2, info);
+ assertEquals(2, sizeOf(FLAG_APPEAR));
+ mStore.removeViewHolder(vh2);
+ assertEquals(1, sizeOf(FLAG_APPEAR));
+ }
+
+ @Test
+ public void disappearListTest() {
+ RecyclerView.ViewHolder vh = new MockViewHolder();
+ mStore.addToDisappearedInLayout(vh);
+ assertEquals(1, sizeOf(FLAG_DISAPPEARED));
+ mStore.addToDisappearedInLayout(vh);
+ assertEquals(1, sizeOf(FLAG_DISAPPEARED));
+ RecyclerView.ViewHolder vh2 = new MockViewHolder();
+ mStore.addToDisappearedInLayout(vh2);
+ assertEquals(2, sizeOf(FLAG_DISAPPEARED));
+ mStore.removeViewHolder(vh2);
+ assertEquals(1, sizeOf(FLAG_DISAPPEARED));
+ mStore.removeFromDisappearedInLayout(vh);
+ assertEquals(0, sizeOf(FLAG_DISAPPEARED));
+ }
+
+ @Test
+ public void processAppear() {
+ ViewHolder vh = new MockViewHolder();
+ MockInfo info = new MockInfo();
+ mStore.addToPostLayout(vh, info);
+ mStore.process(mCallback);
+ assertEquals(new Pair<>(null, info), mCallback.appeared.get(vh));
+ assertTrue(mCallback.disappeared.isEmpty());
+ assertTrue(mCallback.unused.isEmpty());
+ assertTrue(mCallback.persistent.isEmpty());
+ }
+
+ @Test
+ public void processDisappearNormal() {
+ ViewHolder vh = new MockViewHolder();
+ MockInfo info = new MockInfo();
+ mStore.addToPreLayout(vh, info);
+ mStore.process(mCallback);
+ assertEquals(new Pair<>(info, null), mCallback.disappeared.get(vh));
+ assertTrue(mCallback.appeared.isEmpty());
+ assertTrue(mCallback.unused.isEmpty());
+ assertTrue(mCallback.persistent.isEmpty());
+ }
+
+ @Test
+ public void processDisappearMissingLayout() {
+ ViewHolder vh = new MockViewHolder();
+ MockInfo info = new MockInfo();
+ mStore.addToPreLayout(vh, info);
+ mStore.addToDisappearedInLayout(vh);
+ mStore.process(mCallback);
+ assertEquals(new Pair<>(info, null), mCallback.disappeared.get(vh));
+ assertTrue(mCallback.appeared.isEmpty());
+ assertTrue(mCallback.unused.isEmpty());
+ assertTrue(mCallback.persistent.isEmpty());
+ }
+
+ @Test
+ public void processDisappearMoveOut() {
+ ViewHolder vh = new MockViewHolder();
+ MockInfo pre = new MockInfo();
+ MockInfo post = new MockInfo();
+ mStore.addToPreLayout(vh, pre);
+ mStore.addToDisappearedInLayout(vh);
+ mStore.addToPostLayout(vh, post);
+ mStore.process(mCallback);
+ assertEquals(new Pair<>(pre, post), mCallback.disappeared.get(vh));
+ assertTrue(mCallback.appeared.isEmpty());
+ assertTrue(mCallback.unused.isEmpty());
+ assertTrue(mCallback.persistent.isEmpty());
+ }
+
+ @Test
+ public void processDisappearAppear() {
+ ViewHolder vh = new MockViewHolder();
+ MockInfo pre = new MockInfo();
+ MockInfo post = new MockInfo();
+ mStore.addToPreLayout(vh, pre);
+ mStore.addToDisappearedInLayout(vh);
+ mStore.addToPostLayout(vh, post);
+ mStore.removeFromDisappearedInLayout(vh);
+ mStore.process(mCallback);
+ assertTrue(mCallback.disappeared.isEmpty());
+ assertTrue(mCallback.appeared.isEmpty());
+ assertTrue(mCallback.unused.isEmpty());
+ assertEquals(mCallback.persistent.get(vh), new Pair<>(pre, post));
+ }
+
+ static class MockViewHolder extends RecyclerView.ViewHolder {
+ public MockViewHolder() {
+ super(new View(null));
+ }
+ }
+
+ static class MockInfo extends RecyclerView.ItemAnimator.ItemHolderInfo {
+
+ }
+
+ private int sizeOf(int flags) {
+ int cnt = 0;
+ final int size = mStore.mLayoutHolderMap.size();
+ for (int i = 0; i < size; i ++) {
+ ViewInfoStore.InfoRecord record = mStore.mLayoutHolderMap.valueAt(i);
+ if ((record.flags & flags) != 0) {
+ cnt ++;
+ }
+ }
+ return cnt;
+ }
+
+ private RecyclerView.ItemAnimator.ItemHolderInfo find(RecyclerView.ViewHolder viewHolder,
+ int flags) {
+ final int size = mStore.mLayoutHolderMap.size();
+ for (int i = 0; i < size; i ++) {
+ ViewInfoStore.InfoRecord record = mStore.mLayoutHolderMap.valueAt(i);
+ RecyclerView.ViewHolder holder = mStore.mLayoutHolderMap.keyAt(i);
+ if ((record.flags & flags) != 0 && holder == viewHolder) {
+ if (flags == FLAG_PRE || flags == FLAG_APPEAR) {
+ return record.preInfo;
+ } else if (flags == FLAG_POST) {
+ return record.postInfo;
+ }
+ throw new UnsupportedOperationException("don't know this flag");
+ }
+ }
+ return null;
+ }
+
+ private static class LoggingProcessCallback implements ViewInfoStore.ProcessCallback {
+ final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> disappeared = new HashMap<>();
+ final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> appeared = new HashMap<>();
+ final Map<ViewHolder, Pair<ItemHolderInfo, ItemHolderInfo>> persistent = new HashMap<>();
+ final List<ViewHolder> unused = new ArrayList<>();
+ @Override
+ public void processDisappeared(ViewHolder viewHolder,
+ ItemHolderInfo preInfo,
+ @Nullable ItemHolderInfo postInfo) {
+ assertNotNull(preInfo);
+ assertFalse(disappeared.containsKey(viewHolder));
+ disappeared.put(viewHolder, new Pair<>(preInfo, postInfo));
+ }
+
+ @Override
+ public void processAppeared(ViewHolder viewHolder,
+ @Nullable ItemHolderInfo preInfo, @NonNull ItemHolderInfo info) {
+ assertNotNull(info);
+ assertFalse(appeared.containsKey(viewHolder));
+ appeared.put(viewHolder, new Pair<>(preInfo, info));
+ }
+
+ @Override
+ public void processPersistent(ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+ assertFalse(persistent.containsKey(viewHolder));
+ assertNotNull(preInfo);
+ assertNotNull(postInfo);
+ persistent.put(viewHolder, new Pair<>(preInfo, postInfo));
+ }
+
+ @Override
+ public void unused(ViewHolder holder) {
+ unused.add(holder);
+ }
+ }
+
+}
diff --git a/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java b/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
index 51f99bb..49efcf9 100644
--- a/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
+++ b/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
@@ -18,10 +18,11 @@
import android.os.Handler;
import android.os.Looper;
+import android.support.v4.content.ParallelExecutorCompat;
import android.util.Log;
import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
class MessageThreadUtil<T> implements ThreadUtil<T> {
@@ -83,7 +84,8 @@
public BackgroundCallback<T> getBackgroundProxy(final BackgroundCallback<T> callback) {
return new BackgroundCallback<T>() {
final private MessageQueue mQueue = new MessageQueue();
- final private Executor mExecutor = Executors.newSingleThreadExecutor();
+ final private Executor mExecutor = ParallelExecutorCompat.getParallelExecutor();
+ AtomicBoolean mBackgroundRunning = new AtomicBoolean(false);
private static final int REFRESH = 1;
private static final int UPDATE_RANGE = 2;
@@ -114,42 +116,51 @@
private void sendMessage(SyncQueueItem msg) {
mQueue.sendMessage(msg);
- mExecutor.execute(mBackgroundRunnable);
+ maybeExecuteBackgroundRunnable();
}
private void sendMessageAtFrontOfQueue(SyncQueueItem msg) {
mQueue.sendMessageAtFrontOfQueue(msg);
- mExecutor.execute(mBackgroundRunnable);
+ maybeExecuteBackgroundRunnable();
+ }
+
+ private void maybeExecuteBackgroundRunnable() {
+ if (mBackgroundRunning.compareAndSet(false, true)) {
+ mExecutor.execute(mBackgroundRunnable);
+ }
}
private Runnable mBackgroundRunnable = new Runnable() {
@Override
public void run() {
- SyncQueueItem msg = mQueue.next();
- if (msg == null) {
- return;
+ while (true) {
+ SyncQueueItem msg = mQueue.next();
+ if (msg == null) {
+ break;
+ }
+ switch (msg.what) {
+ case REFRESH:
+ mQueue.removeMessages(REFRESH);
+ callback.refresh(msg.arg1);
+ break;
+ case UPDATE_RANGE:
+ mQueue.removeMessages(UPDATE_RANGE);
+ mQueue.removeMessages(LOAD_TILE);
+ callback.updateRange(
+ msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
+ break;
+ case LOAD_TILE:
+ callback.loadTile(msg.arg1, msg.arg2);
+ break;
+ case RECYCLE_TILE:
+ //noinspection unchecked
+ callback.recycleTile((TileList.Tile<T>) msg.data);
+ break;
+ default:
+ Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
+ }
}
- switch (msg.what) {
- case REFRESH:
- mQueue.removeMessages(REFRESH);
- callback.refresh(msg.arg1);
- break;
- case UPDATE_RANGE:
- mQueue.removeMessages(UPDATE_RANGE);
- mQueue.removeMessages(LOAD_TILE);
- callback.updateRange(
- msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5);
- break;
- case LOAD_TILE:
- callback.loadTile(msg.arg1, msg.arg2);
- break;
- case RECYCLE_TILE:
- //noinspection unchecked
- callback.recycleTile((TileList.Tile<T>) msg.data);
- break;
- default:
- Log.e("ThreadUtil", "Unsupported message, what=" + msg.what);
- }
+ mBackgroundRunning.set(false);
}
};
};
diff --git a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java b/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
index e9feab8..9220c5e 100644
--- a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
@@ -67,6 +67,8 @@
final OpReorderer mOpReorderer;
+ private int mExistingUpdateTypes = 0;
+
AdapterHelper(Callback callback) {
this(callback, false);
}
@@ -85,6 +87,7 @@
void reset() {
recycleUpdateOpsAndClearList(mPendingUpdates);
recycleUpdateOpsAndClearList(mPostponedList);
+ mExistingUpdateTypes = 0;
}
void preProcess() {
@@ -119,6 +122,7 @@
mCallback.onDispatchSecondPass(mPostponedList.get(i));
}
recycleUpdateOpsAndClearList(mPostponedList);
+ mExistingUpdateTypes = 0;
}
private void applyMove(UpdateOp op) {
@@ -457,6 +461,10 @@
return mPendingUpdates.size() > 0;
}
+ boolean hasAnyUpdateTypes(int updateTypes) {
+ return (mExistingUpdateTypes & updateTypes) != 0;
+ }
+
int findPositionOffset(int position) {
return findPositionOffset(position, 0);
}
@@ -495,6 +503,7 @@
*/
boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
+ mExistingUpdateTypes |= UpdateOp.UPDATE;
return mPendingUpdates.size() == 1;
}
@@ -503,6 +512,7 @@
*/
boolean onItemRangeInserted(int positionStart, int itemCount) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null));
+ mExistingUpdateTypes |= UpdateOp.ADD;
return mPendingUpdates.size() == 1;
}
@@ -511,6 +521,7 @@
*/
boolean onItemRangeRemoved(int positionStart, int itemCount) {
mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));
+ mExistingUpdateTypes |= UpdateOp.REMOVE;
return mPendingUpdates.size() == 1;
}
@@ -525,6 +536,7 @@
throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
}
mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));
+ mExistingUpdateTypes |= UpdateOp.MOVE;
return mPendingUpdates.size() == 1;
}
@@ -561,6 +573,7 @@
}
}
recycleUpdateOpsAndClearList(mPendingUpdates);
+ mExistingUpdateTypes = 0;
}
public int applyPendingUpdatesToPosition(int position) {
@@ -604,13 +617,13 @@
*/
static class UpdateOp {
- static final int ADD = 0;
+ static final int ADD = 1;
- static final int REMOVE = 1;
+ static final int REMOVE = 1 << 1;
- static final int UPDATE = 2;
+ static final int UPDATE = 1 << 2;
- static final int MOVE = 3;
+ static final int MOVE = 1 << 3;
static final int POOL_SIZE = 30;
diff --git a/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java b/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
index 66ebab5..0afa405 100644
--- a/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
@@ -208,8 +208,8 @@
for (int i = 0; i < count; i++) {
final View view = mHiddenViews.get(i);
RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view);
- if (holder.getLayoutPosition() == position && !holder.isInvalid() &&
- (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
+ if (holder.getLayoutPosition() == position && !holder.isInvalid() && !holder.isRemoved()
+ && (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) {
return view;
}
}
@@ -339,6 +339,25 @@
}
}
+ /**
+ * Moves a child view from hidden list to regular list.
+ * Calling this method should probably be followed by a detach, otherwise, it will suddenly
+ * show up in LayoutManager's children list.
+ *
+ * @param view The hidden View to unhide
+ */
+ void unhide(View view) {
+ final int offset = mCallback.indexOfChild(view);
+ if (offset < 0) {
+ throw new IllegalArgumentException("view is not a child, cannot hide " + view);
+ }
+ if (!mBucket.get(offset)) {
+ throw new RuntimeException("trying to unhide a view that was not hidden" + view);
+ }
+ mBucket.clear(offset);
+ unhideViewInternal(view);
+ }
+
@Override
public String toString() {
return mBucket.toString() + ", hidden list:" + mHiddenViews.size();
diff --git a/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java b/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
index fa45d84..0809efe 100644
--- a/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
+++ b/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
@@ -32,23 +32,22 @@
*
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
*/
-public class DefaultItemAnimator extends RecyclerView.ItemAnimator {
+public class DefaultItemAnimator extends SimpleItemAnimator {
private static final boolean DEBUG = false;
- private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<ViewHolder>();
- private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<ViewHolder>();
- private ArrayList<MoveInfo> mPendingMoves = new ArrayList<MoveInfo>();
- private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<ChangeInfo>();
+ private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
+ private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
+ private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
+ private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
- private ArrayList<ArrayList<ViewHolder>> mAdditionsList =
- new ArrayList<ArrayList<ViewHolder>>();
- private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<ArrayList<MoveInfo>>();
- private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<ArrayList<ChangeInfo>>();
+ private ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();
+ private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
+ private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
- private ArrayList<ViewHolder> mAddAnimations = new ArrayList<ViewHolder>();
- private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<ViewHolder>();
- private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<ViewHolder>();
- private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<ViewHolder>();
+ private ArrayList<ViewHolder> mAddAnimations = new ArrayList<>();
+ private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();
+ private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();
+ private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();
private static class MoveInfo {
public ViewHolder holder;
@@ -110,7 +109,7 @@
mPendingRemovals.clear();
// Next, move stuff
if (movesPending) {
- final ArrayList<MoveInfo> moves = new ArrayList<MoveInfo>();
+ final ArrayList<MoveInfo> moves = new ArrayList<>();
moves.addAll(mPendingMoves);
mMovesList.add(moves);
mPendingMoves.clear();
@@ -134,7 +133,7 @@
}
// Next, change stuff, to run in parallel with move animations
if (changesPending) {
- final ArrayList<ChangeInfo> changes = new ArrayList<ChangeInfo>();
+ final ArrayList<ChangeInfo> changes = new ArrayList<>();
changes.addAll(mPendingChanges);
mChangesList.add(changes);
mPendingChanges.clear();
@@ -157,7 +156,7 @@
}
// Next, add stuff
if (additionsPending) {
- final ArrayList<ViewHolder> additions = new ArrayList<ViewHolder>();
+ final ArrayList<ViewHolder> additions = new ArrayList<>();
additions.addAll(mPendingAdditions);
mAdditionsList.add(additions);
mPendingAdditions.clear();
@@ -310,6 +309,11 @@
@Override
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
+ if (oldHolder == newHolder) {
+ // Don't know how to run change animations when the same view holder is re-used.
+ // run a move animation to handle position changes.
+ return animateMove(oldHolder, fromX, fromY, toX, toY);
+ }
final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
@@ -320,7 +324,7 @@
ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
- if (newHolder != null && newHolder.itemView != null) {
+ if (newHolder != null) {
// carry over translation values
resetAnimation(newHolder);
ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
@@ -479,21 +483,25 @@
}
// animations should be ended by the cancel above.
+ //noinspection PointlessBooleanExpression,ConstantConditions
if (mRemoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mRemoveAnimations list");
}
+ //noinspection PointlessBooleanExpression,ConstantConditions
if (mAddAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mAddAnimations list");
}
+ //noinspection PointlessBooleanExpression,ConstantConditions
if (mChangeAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mChangeAnimations list");
}
+ //noinspection PointlessBooleanExpression,ConstantConditions
if (mMoveAnimations.remove(item) && DEBUG) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mMoveAnimations list");
@@ -633,5 +641,5 @@
@Override
public void onAnimationCancel(View view) {}
- };
+ }
}
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
index 910405a..7dcaea0 100644
--- a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
@@ -303,11 +303,31 @@
if (state.getItemCount() > 0 && !state.isPreLayout()) {
ensureAnchorIsInFirstSpan(recycler, state, anchorInfo);
}
+ ensureViewSet();
+ }
+
+ private void ensureViewSet() {
if (mSet == null || mSet.length != mSpanCount) {
mSet = new View[mSpanCount];
}
}
+ @Override
+ public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ updateMeasurements();
+ ensureViewSet();
+ return super.scrollHorizontallyBy(dx, recycler, state);
+ }
+
+ @Override
+ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ updateMeasurements();
+ ensureViewSet();
+ return super.scrollVerticallyBy(dy, recycler, state);
+ }
+
private void ensureAnchorIsInFirstSpan(RecyclerView.Recycler recycler, RecyclerView.State state,
AnchorInfo anchorInfo) {
int span = getSpanIndex(recycler, state, anchorInfo.mPosition);
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index 632b05c..b896902 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -2035,7 +2035,10 @@
}
}
- static class SavedState implements Parcelable {
+ /**
+ * @hide
+ */
+ public static class SavedState implements Parcelable {
int mAnchorPosition;
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index d21f046..57684f8 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -16,7 +16,6 @@
package android.support.v7.widget;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.database.Observable;
@@ -27,11 +26,12 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.CallSuper;
import android.os.SystemClock;
+import android.support.annotation.CallSuper;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.TraceCompat;
-import android.support.v4.util.ArrayMap;
import android.support.v4.view.InputDeviceCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.NestedScrollingChild;
@@ -62,6 +62,8 @@
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
@@ -70,6 +72,7 @@
import static android.support.v7.widget.AdapterHelper.Callback;
import static android.support.v7.widget.AdapterHelper.UpdateOp;
+import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
/**
* A flexible view for providing a limited window into a large data set.
@@ -239,11 +242,22 @@
private SavedState mPendingSavedState;
+ /**
+ * Handles adapter updates
+ */
AdapterHelper mAdapterHelper;
+ /**
+ * Handles abstraction between LayoutManager children and RecyclerView children
+ */
ChildHelper mChildHelper;
/**
+ * Keeps data about views to be used for animations
+ */
+ final ViewInfoStore mViewInfoStore = new ViewInfoStore();
+
+ /**
* Prior to L, there is no way to query this variable which is why we override the setter and
* track it here.
*/
@@ -257,26 +271,15 @@
*/
private final Runnable mUpdateChildViewsRunnable = new Runnable() {
public void run() {
- if (!mFirstLayoutComplete) {
+ if (!mFirstLayoutComplete || isLayoutRequested()) {
// a layout request will happen, we should not do layout here.
return;
}
- if (mDataSetHasChangedAfterLayout) {
- TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
- dispatchLayout();
- TraceCompat.endSection();
- } else if (mAdapterHelper.hasPendingUpdates()) {
- TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
- eatRequestLayout();
- mAdapterHelper.preProcess();
- if (!mLayoutRequestEaten) {
- // We run this after pre-processing is complete so that ViewHolders have their
- // final adapter positions. No need to run it if a layout is already requested.
- rebindUpdatedViewHolders();
- }
- resumeRequestLayout(true);
- TraceCompat.endSection();
+ if (mLayoutFrozen) {
+ mLayoutRequestEaten = true;
+ return; //we'll process updates when ice age ends.
}
+ consumePendingUpdateOperations();
}
};
@@ -401,6 +404,44 @@
}
};
+ /**
+ * The callback to convert view info diffs into animations.
+ */
+ private final ViewInfoStore.ProcessCallback mViewInfoProcessCallback =
+ new ViewInfoStore.ProcessCallback() {
+ @Override
+ public void processDisappeared(ViewHolder viewHolder, ItemHolderInfo info,
+ ItemHolderInfo postInfo) {
+ mRecycler.unscrapView(viewHolder);
+ animateDisappearance(viewHolder, info, postInfo);
+ }
+ @Override
+ public void processAppeared(ViewHolder viewHolder,
+ ItemHolderInfo preInfo, ItemHolderInfo info) {
+ animateAppearance(viewHolder, preInfo, info);
+ }
+
+ @Override
+ public void processPersistent(ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+ viewHolder.setIsRecyclable(false);
+ if (mDataSetHasChangedAfterLayout) {
+ // since it was rebound, use change instead as we'll be mapping them from
+ // stable ids. If stable ids were false, we would not be running any
+ // animations
+ if (mItemAnimator.animateChange(viewHolder, viewHolder, preInfo, postInfo)) {
+ postAnimationRunner();
+ }
+ } else if (mItemAnimator.animatePersistence(viewHolder, preInfo, postInfo)) {
+ postAnimationRunner();
+ }
+ }
+ @Override
+ public void unused(ViewHolder viewHolder) {
+ mLayout.removeAndRecycleView(viewHolder.itemView, mRecycler);
+ }
+ };
+
public RecyclerView(Context context) {
this(context, null);
}
@@ -1338,8 +1379,8 @@
@Override
public void scrollTo(int x, int y) {
- throw new UnsupportedOperationException(
- "RecyclerView does not support scrolling to an absolute position.");
+ Log.w(TAG, "RecyclerView does not support scrolling to an absolute position. "
+ + "Use scrollToPosition instead");
}
@Override
@@ -1368,7 +1409,59 @@
* This method consumes all deferred changes to avoid that case.
*/
private void consumePendingUpdateOperations() {
- mUpdateChildViewsRunnable.run();
+ if (!mFirstLayoutComplete) {
+ // a layout request will happen, we should not do layout here.
+ return;
+ }
+ if (mDataSetHasChangedAfterLayout) {
+ TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
+ dispatchLayout();
+ TraceCompat.endSection();
+ return;
+ }
+ if (!mAdapterHelper.hasPendingUpdates()) {
+ return;
+ }
+
+ // if it is only an item change (no add-remove-notifyDataSetChanged) we can check if any
+ // of the visible items is affected and if not, just ignore the change.
+ if (mAdapterHelper.hasAnyUpdateTypes(UpdateOp.UPDATE) && !mAdapterHelper
+ .hasAnyUpdateTypes(UpdateOp.ADD | UpdateOp.REMOVE | UpdateOp.MOVE)) {
+ TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
+ eatRequestLayout();
+ mAdapterHelper.preProcess();
+ if (!mLayoutRequestEaten) {
+ if (hasUpdatedView()) {
+ dispatchLayout();
+ } else {
+ // no need to layout, clean state
+ mAdapterHelper.consumePostponedUpdates();
+ }
+ }
+ resumeRequestLayout(true);
+ TraceCompat.endSection();
+ } else if (mAdapterHelper.hasPendingUpdates()) {
+ TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
+ dispatchLayout();
+ TraceCompat.endSection();
+ }
+ }
+
+ /**
+ * @return True if an existing view holder needs to be updated
+ */
+ private boolean hasUpdatedView() {
+ final int childCount = mChildHelper.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
+ if (holder == null || holder.shouldIgnore()) {
+ continue;
+ }
+ if (holder.isUpdated()) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -1400,27 +1493,7 @@
unconsumedY = y - consumedY;
}
TraceCompat.endSection();
- if (supportsChangeAnimations()) {
- // Fix up shadow views used by changing animations
- int count = mChildHelper.getChildCount();
- for (int i = 0; i < count; i++) {
- View view = mChildHelper.getChildAt(i);
- ViewHolder holder = getChildViewHolder(view);
- if (holder != null && holder.mShadowingHolder != null) {
- ViewHolder shadowingHolder = holder.mShadowingHolder;
- View shadowingView = shadowingHolder != null ? shadowingHolder.itemView : null;
- if (shadowingView != null) {
- int left = view.getLeft();
- int top = view.getTop();
- if (left != shadowingView.getLeft() || top != shadowingView.getTop()) {
- shadowingView.layout(left, top,
- left + shadowingView.getWidth(),
- top + shadowingView.getHeight());
- }
- }
- }
- }
- }
+ repositionShadowingViews();
onExitLayoutOrScroll();
resumeRequestLayout(false);
}
@@ -2001,6 +2074,7 @@
mLayout.dispatchDetachedFromWindow(this, mRecycler);
}
removeCallbacks(mItemAnimatorRunner);
+ mViewInfoStore.onDetach();
}
/**
@@ -2164,6 +2238,9 @@
setScrollState(SCROLL_STATE_DRAGGING);
}
+ // Clear the nested offsets
+ mNestedOffsets[0] = mNestedOffsets[1] = 0;
+
int nestedScrollAxis = ViewCompat.SCROLL_AXIS_NONE;
if (canScrollHorizontally) {
nestedScrollAxis |= ViewCompat.SCROLL_AXIS_HORIZONTAL;
@@ -2203,10 +2280,6 @@
startScroll = true;
}
if (startScroll) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
setScrollState(SCROLL_STATE_DRAGGING);
}
}
@@ -2332,10 +2405,6 @@
startScroll = true;
}
if (startScroll) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
setScrollState(SCROLL_STATE_DRAGGING);
}
}
@@ -2662,10 +2731,6 @@
return mItemAnimator;
}
- private boolean supportsChangeAnimations() {
- return mItemAnimator != null && mItemAnimator.getSupportsChangeAnimations();
- }
-
/**
* Post a runnable to the next frame to run pending item animations. Only the first such
* request will be posted, governed by the mPostedAnimatorRunner flag.
@@ -2703,8 +2768,7 @@
} else {
mAdapterHelper.consumeUpdatesInOnePass();
}
- boolean animationTypeSupported = (mItemsAddedOrRemoved && !mItemsChanged) ||
- (mItemsAddedOrRemoved || (mItemsChanged && supportsChangeAnimations()));
+ boolean animationTypeSupported = mItemsAddedOrRemoved || mItemsChanged;
mState.mRunSimpleAnimations = mFirstLayoutComplete && mItemAnimator != null &&
(mDataSetHasChangedAfterLayout || animationTypeSupported ||
mLayout.mRequestedSimpleAnimations) &&
@@ -2730,11 +2794,14 @@
* The overall approach figures out what items exist before/after layout and
* infers one of the five above states for each of the items. Then the animations
* are set up accordingly:
- * PERSISTENT views are moved ({@link ItemAnimator#animateMove(ViewHolder, int, int, int, int)})
- * REMOVED views are removed ({@link ItemAnimator#animateRemove(ViewHolder)})
- * ADDED views are added ({@link ItemAnimator#animateAdd(ViewHolder)})
- * DISAPPEARING views are moved off screen
- * APPEARING views are moved on screen
+ * PERSISTENT views are animated via
+ * {@link ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+ * DISAPPEARING views are animated via
+ * {@link ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+ * APPEARING views are animated via
+ * {@link ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+ * and changed views are animated via
+ * {@link ItemAnimator#animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)}.
*/
void dispatchLayout() {
if (mAdapter == null) {
@@ -2745,33 +2812,42 @@
Log.e(TAG, "No layout manager attached; skipping layout");
return;
}
- mState.mDisappearingViewsInLayoutPass.clear();
+ mViewInfoStore.clear();
eatRequestLayout();
onEnterLayoutOrScroll();
processAdapterUpdatesAndSetAnimationFlags();
-
- mState.mOldChangedHolders = mState.mRunSimpleAnimations && mItemsChanged
- && supportsChangeAnimations() ? new ArrayMap<Long, ViewHolder>() : null;
+ mState.mTrackOldChangeHolders = mState.mRunSimpleAnimations && mItemsChanged;
mItemsAddedOrRemoved = mItemsChanged = false;
- ArrayMap<View, Rect> appearingViewInitialBounds = null;
mState.mInPreLayout = mState.mRunPredictiveAnimations;
mState.mItemCount = mAdapter.getItemCount();
findMinMaxChildLayoutPositions(mMinMaxLayoutPositions);
if (mState.mRunSimpleAnimations) {
// Step 0: Find out where all non-removed items are, pre-layout
- mState.mPreLayoutHolderMap.clear();
- mState.mPostLayoutHolderMap.clear();
int count = mChildHelper.getChildCount();
for (int i = 0; i < count; ++i) {
final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
if (holder.shouldIgnore() || (holder.isInvalid() && !mAdapter.hasStableIds())) {
continue;
}
- final View view = holder.itemView;
- mState.mPreLayoutHolderMap.put(holder, new ItemHolderInfo(holder,
- view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+ final ItemHolderInfo animationInfo = mItemAnimator
+ .recordPreLayoutInformation(mState, holder,
+ ItemAnimator.buildAdapterChangeFlagsForAnimations(holder),
+ holder.getUnmodifiedPayloads());
+ mViewInfoStore.addToPreLayout(holder, animationInfo);
+ if (mState.mTrackOldChangeHolders && holder.isUpdated() && !holder.isRemoved()
+ && !holder.shouldIgnore() && !holder.isInvalid()) {
+ long key = getChangedHolderKey(holder);
+ // This is NOT the only place where a ViewHolder is added to old change holders
+ // list. There is another case where:
+ // * A VH is currently hidden but not deleted
+ // * The hidden item is changed in the adapter
+ // * Layout manager decides to layout the item in the pre-Layout pass (step1)
+ // When this case is detected, RV will un-hide that view and add to the old
+ // change holders list.
+ mViewInfoStore.addToOldChangeHolders(key, holder);
+ }
}
}
if (mState.mRunPredictiveAnimations) {
@@ -2782,42 +2858,32 @@
// Save old positions so that LayoutManager can run its mapping logic.
saveOldPositions();
- // processAdapterUpdatesAndSetAnimationFlags already run pre-layout animations.
- if (mState.mOldChangedHolders != null) {
- int count = mChildHelper.getChildCount();
- for (int i = 0; i < count; ++i) {
- final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
- if (holder.isChanged() && !holder.isRemoved() && !holder.shouldIgnore()) {
- long key = getChangedHolderKey(holder);
- mState.mOldChangedHolders.put(key, holder);
- mState.mPreLayoutHolderMap.remove(holder);
- }
- }
- }
-
final boolean didStructureChange = mState.mStructureChanged;
mState.mStructureChanged = false;
// temporarily disable flag because we are asking for previous layout
mLayout.onLayoutChildren(mRecycler, mState);
mState.mStructureChanged = didStructureChange;
- appearingViewInitialBounds = new ArrayMap<View, Rect>();
for (int i = 0; i < mChildHelper.getChildCount(); ++i) {
- boolean found = false;
- View child = mChildHelper.getChildAt(i);
- if (getChildViewHolderInt(child).shouldIgnore()) {
+ final View child = mChildHelper.getChildAt(i);
+ final ViewHolder viewHolder = getChildViewHolderInt(child);
+ if (viewHolder.shouldIgnore()) {
continue;
}
- for (int j = 0; j < mState.mPreLayoutHolderMap.size(); ++j) {
- ViewHolder holder = mState.mPreLayoutHolderMap.keyAt(j);
- if (holder.itemView == child) {
- found = true;
- break;
+ if (!mViewInfoStore.isInPreLayout(viewHolder)) {
+ int flags = ItemAnimator.buildAdapterChangeFlagsForAnimations(viewHolder);
+ boolean wasHidden = viewHolder
+ .hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+ if (!wasHidden) {
+ flags |= ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT;
}
- }
- if (!found) {
- appearingViewInitialBounds.put(child, new Rect(child.getLeft(), child.getTop(),
- child.getRight(), child.getBottom()));
+ final ItemHolderInfo animationInfo = mItemAnimator.recordPreLayoutInformation(
+ mState, viewHolder, flags, viewHolder.getUnmodifiedPayloads());
+ if (wasHidden) {
+ recordAnimationInfoIfBouncedHiddenView(viewHolder, animationInfo);
+ } else {
+ mViewInfoStore.addToAppearedInPreLayoutHolders(viewHolder, animationInfo);
+ }
}
}
// we don't process disappearing list because they may re-appear in post layout pass.
@@ -2825,19 +2891,6 @@
mAdapterHelper.consumePostponedUpdates();
} else {
clearOldPositions();
- // in case pre layout did run but we decided not to run predictive animations.
- mAdapterHelper.consumeUpdatesInOnePass();
- if (mState.mOldChangedHolders != null) {
- int count = mChildHelper.getChildCount();
- for (int i = 0; i < count; ++i) {
- final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
- if (holder.isChanged() && !holder.isRemoved() && !holder.shouldIgnore()) {
- long key = getChangedHolderKey(holder);
- mState.mOldChangedHolders.put(key, holder);
- mState.mPreLayoutHolderMap.remove(holder);
- }
- }
- }
}
mState.mItemCount = mAdapter.getItemCount();
mState.mDeletedInvisibleItemCountSincePreviousLayout = 0;
@@ -2853,112 +2906,64 @@
mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null;
if (mState.mRunSimpleAnimations) {
- // Step 3: Find out where things are now, post-layout
- ArrayMap<Long, ViewHolder> newChangedHolders = mState.mOldChangedHolders != null ?
- new ArrayMap<Long, ViewHolder>() : null;
+ // Step 3: Find out where things are now, and process change animations.
int count = mChildHelper.getChildCount();
for (int i = 0; i < count; ++i) {
ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
if (holder.shouldIgnore()) {
continue;
}
- final View view = holder.itemView;
long key = getChangedHolderKey(holder);
- if (newChangedHolders != null && mState.mOldChangedHolders.get(key) != null) {
- newChangedHolders.put(key, holder);
+ final ItemHolderInfo animationInfo = mItemAnimator
+ .recordPostLayoutInformation(mState, holder);
+ ViewHolder oldChangeViewHolder = mViewInfoStore.getFromOldChangeHolders(key);
+ if (oldChangeViewHolder != null && !oldChangeViewHolder.shouldIgnore()) {
+ // run a change animation
+ final ItemHolderInfo preInfo = mViewInfoStore.popFromPreLayout(
+ oldChangeViewHolder);
+ animateChange(oldChangeViewHolder, holder, preInfo, animationInfo);
} else {
- mState.mPostLayoutHolderMap.put(holder, new ItemHolderInfo(holder,
- view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+ mViewInfoStore.addToPostLayout(holder, animationInfo);
}
}
- processDisappearingList(appearingViewInitialBounds);
- // Step 4: Animate DISAPPEARING and REMOVED items
- int preLayoutCount = mState.mPreLayoutHolderMap.size();
- for (int i = preLayoutCount - 1; i >= 0; i--) {
- ViewHolder itemHolder = mState.mPreLayoutHolderMap.keyAt(i);
- if (!mState.mPostLayoutHolderMap.containsKey(itemHolder)) {
- ItemHolderInfo disappearingItem = mState.mPreLayoutHolderMap.valueAt(i);
- mState.mPreLayoutHolderMap.removeAt(i);
- View disappearingItemView = disappearingItem.holder.itemView;
- mRecycler.unscrapView(disappearingItem.holder);
- animateDisappearance(disappearingItem);
- }
- }
- // Step 5: Animate APPEARING and ADDED items
- int postLayoutCount = mState.mPostLayoutHolderMap.size();
- if (postLayoutCount > 0) {
- for (int i = postLayoutCount - 1; i >= 0; i--) {
- ViewHolder itemHolder = mState.mPostLayoutHolderMap.keyAt(i);
- ItemHolderInfo info = mState.mPostLayoutHolderMap.valueAt(i);
- if ((mState.mPreLayoutHolderMap.isEmpty() ||
- !mState.mPreLayoutHolderMap.containsKey(itemHolder))) {
- mState.mPostLayoutHolderMap.removeAt(i);
- Rect initialBounds = (appearingViewInitialBounds != null) ?
- appearingViewInitialBounds.get(itemHolder.itemView) : null;
- animateAppearance(itemHolder, initialBounds,
- info.left, info.top);
- }
- }
- }
- // Step 6: Animate PERSISTENT items
- count = mState.mPostLayoutHolderMap.size();
- for (int i = 0; i < count; ++i) {
- ViewHolder postHolder = mState.mPostLayoutHolderMap.keyAt(i);
- ItemHolderInfo postInfo = mState.mPostLayoutHolderMap.valueAt(i);
- ItemHolderInfo preInfo = mState.mPreLayoutHolderMap.get(postHolder);
- if (preInfo != null && postInfo != null) {
- if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
- postHolder.setIsRecyclable(false);
- if (DEBUG) {
- Log.d(TAG, "PERSISTENT: " + postHolder +
- " with view " + postHolder.itemView);
- }
- if (mItemAnimator.animateMove(postHolder,
- preInfo.left, preInfo.top, postInfo.left, postInfo.top)) {
- postAnimationRunner();
- }
- }
- }
- }
- // Step 7: Animate CHANGING items
- count = mState.mOldChangedHolders != null ? mState.mOldChangedHolders.size() : 0;
- // traverse reverse in case view gets recycled while we are traversing the list.
- for (int i = count - 1; i >= 0; i--) {
- long key = mState.mOldChangedHolders.keyAt(i);
- ViewHolder oldHolder = mState.mOldChangedHolders.get(key);
- View oldView = oldHolder.itemView;
- if (oldHolder.shouldIgnore()) {
- continue;
- }
- // We probably don't need this check anymore since these views are removed from
- // the list if they are recycled.
- if (mRecycler.mChangedScrap != null &&
- mRecycler.mChangedScrap.contains(oldHolder)) {
- animateChange(oldHolder, newChangedHolders.get(key));
- } else if (DEBUG) {
- Log.e(TAG, "cannot find old changed holder in changed scrap :/" + oldHolder);
- }
- }
+ // Step 4: Process view info lists and trigger animations
+ mViewInfoStore.process(mViewInfoProcessCallback);
}
resumeRequestLayout(false);
mLayout.removeAndRecycleScrapInt(mRecycler);
mState.mPreviousLayoutItemCount = mState.mItemCount;
mDataSetHasChangedAfterLayout = false;
mState.mRunSimpleAnimations = false;
+
mState.mRunPredictiveAnimations = false;
onExitLayoutOrScroll();
mLayout.mRequestedSimpleAnimations = false;
if (mRecycler.mChangedScrap != null) {
mRecycler.mChangedScrap.clear();
}
- mState.mOldChangedHolders = null;
-
+ mViewInfoStore.clear();
if (didChildRangeChange(mMinMaxLayoutPositions[0], mMinMaxLayoutPositions[1])) {
dispatchOnScrolled(0, 0);
}
}
+ /**
+ * Records the animation information for a view holder that was bounced from hidden list. It
+ * also clears the bounce back flag.
+ */
+ private void recordAnimationInfoIfBouncedHiddenView(ViewHolder viewHolder,
+ ItemHolderInfo animationInfo) {
+ // looks like this view bounced back from hidden list!
+ viewHolder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+ if (mState.mTrackOldChangeHolders && viewHolder.isUpdated()
+ && !viewHolder.isRemoved() && !viewHolder.shouldIgnore()) {
+ long key = getChangedHolderKey(viewHolder);
+ mViewInfoStore.addToOldChangeHolders(key, viewHolder);
+ }
+ mViewInfoStore.addToPreLayout(viewHolder, animationInfo);
+ }
+
private void findMinMaxChildLayoutPositions(int[] into) {
final int count = mChildHelper.getChildCount();
if (count == 0) {
@@ -3026,114 +3031,35 @@
return mAdapter.hasStableIds() ? holder.getItemId() : holder.mPosition;
}
- /**
- * A LayoutManager may want to layout a view just to animate disappearance.
- * This method handles those views and triggers remove animation on them.
- */
- private void processDisappearingList(ArrayMap<View, Rect> appearingViews) {
- final List<View> disappearingList = mState.mDisappearingViewsInLayoutPass;
- for (int i = disappearingList.size() - 1; i >= 0; i --) {
- View view = disappearingList.get(i);
- ViewHolder vh = getChildViewHolderInt(view);
- final ItemHolderInfo info = mState.mPreLayoutHolderMap.remove(vh);
- if (!mState.isPreLayout()) {
- mState.mPostLayoutHolderMap.remove(vh);
- }
- if (appearingViews.remove(view) != null) {
- mLayout.removeAndRecycleView(view, mRecycler);
- continue;
- }
- if (info != null) {
- animateDisappearance(info);
- } else {
- // let it disappear from the position it becomes visible
- animateDisappearance(new ItemHolderInfo(vh, view.getLeft(), view.getTop(),
- view.getRight(), view.getBottom()));
- }
- }
- disappearingList.clear();
- }
-
- private void animateAppearance(ViewHolder itemHolder, Rect beforeBounds, int afterLeft,
- int afterTop) {
- View newItemView = itemHolder.itemView;
- if (beforeBounds != null &&
- (beforeBounds.left != afterLeft || beforeBounds.top != afterTop)) {
- // slide items in if before/after locations differ
- itemHolder.setIsRecyclable(false);
- if (DEBUG) {
- Log.d(TAG, "APPEARING: " + itemHolder + " with view " + newItemView);
- }
- if (mItemAnimator.animateMove(itemHolder,
- beforeBounds.left, beforeBounds.top,
- afterLeft, afterTop)) {
- postAnimationRunner();
- }
- } else {
- if (DEBUG) {
- Log.d(TAG, "ADDED: " + itemHolder + " with view " + newItemView);
- }
- itemHolder.setIsRecyclable(false);
- if (mItemAnimator.animateAdd(itemHolder)) {
- postAnimationRunner();
- }
+ private void animateAppearance(@NonNull ViewHolder itemHolder,
+ @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
+ itemHolder.setIsRecyclable(false);
+ if (mItemAnimator.animateAppearance(itemHolder, preLayoutInfo, postLayoutInfo)) {
+ postAnimationRunner();
}
}
- private void animateDisappearance(ItemHolderInfo disappearingItem) {
- View disappearingItemView = disappearingItem.holder.itemView;
- addAnimatingView(disappearingItem.holder);
- int oldLeft = disappearingItem.left;
- int oldTop = disappearingItem.top;
- int newLeft = disappearingItemView.getLeft();
- int newTop = disappearingItemView.getTop();
- if (!disappearingItem.holder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) {
- disappearingItem.holder.setIsRecyclable(false);
- disappearingItemView.layout(newLeft, newTop,
- newLeft + disappearingItemView.getWidth(),
- newTop + disappearingItemView.getHeight());
- if (DEBUG) {
- Log.d(TAG, "DISAPPEARING: " + disappearingItem.holder +
- " with view " + disappearingItemView);
- }
- if (mItemAnimator.animateMove(disappearingItem.holder, oldLeft, oldTop,
- newLeft, newTop)) {
- postAnimationRunner();
- }
- } else {
- if (DEBUG) {
- Log.d(TAG, "REMOVED: " + disappearingItem.holder +
- " with view " + disappearingItemView);
- }
- disappearingItem.holder.setIsRecyclable(false);
- if (mItemAnimator.animateRemove(disappearingItem.holder)) {
- postAnimationRunner();
- }
+ private void animateDisappearance(@NonNull ViewHolder holder,
+ @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) {
+ addAnimatingView(holder);
+ holder.setIsRecyclable(false);
+ if (mItemAnimator.animateDisappearance(holder, preLayoutInfo, postLayoutInfo)) {
+ postAnimationRunner();
}
}
- private void animateChange(ViewHolder oldHolder, ViewHolder newHolder) {
+ private void animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder,
+ @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
oldHolder.setIsRecyclable(false);
- addAnimatingView(oldHolder);
- oldHolder.mShadowedHolder = newHolder;
- mRecycler.unscrapView(oldHolder);
- if (DEBUG) {
- Log.d(TAG, "CHANGED: " + oldHolder + " with view " + oldHolder.itemView);
- }
- final int fromLeft = oldHolder.itemView.getLeft();
- final int fromTop = oldHolder.itemView.getTop();
- final int toLeft, toTop;
- if (newHolder == null || newHolder.shouldIgnore()) {
- toLeft = fromLeft;
- toTop = fromTop;
- } else {
- toLeft = newHolder.itemView.getLeft();
- toTop = newHolder.itemView.getTop();
+ if (oldHolder != newHolder) {
+ oldHolder.mShadowedHolder = newHolder;
+ // old holder should disappear after animation ends
+ addAnimatingView(oldHolder);
+ mRecycler.unscrapView(oldHolder);
newHolder.setIsRecyclable(false);
newHolder.mShadowingHolder = oldHolder;
}
- if(mItemAnimator.animateChange(oldHolder, newHolder,
- fromLeft, fromTop, toLeft, toTop)) {
+ if (mItemAnimator.animateChange(oldHolder, newHolder, preInfo, postInfo)) {
postAnimationRunner();
}
}
@@ -3405,9 +3331,6 @@
// ViewHolders have their final positions assigned.
holder.addFlags(ViewHolder.FLAG_UPDATE);
holder.addChangePayload(payload);
- if (supportsChangeAnimations()) {
- holder.addFlags(ViewHolder.FLAG_CHANGED);
- }
// lp cannot be null since we get ViewHolder from it.
((LayoutParams) child.getLayoutParams()).mInsetsDirty = true;
}
@@ -3415,36 +3338,8 @@
mRecycler.viewRangeUpdate(positionStart, itemCount);
}
- void rebindUpdatedViewHolders() {
- final int childCount = mChildHelper.getChildCount();
- for (int i = 0; i < childCount; i++) {
- final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
- // validate type is correct
- if (holder == null || holder.shouldIgnore()) {
- continue;
- }
- if (holder.isRemoved() || holder.isInvalid()) {
- requestLayout();
- } else if (holder.needsUpdate()) {
- final int type = mAdapter.getItemViewType(holder.mPosition);
- if (holder.getItemViewType() == type) {
- // Binding an attached view will request a layout if needed.
- if (!holder.isChanged() || !supportsChangeAnimations()) {
- mAdapter.bindViewHolder(holder, holder.mPosition);
- } else {
- // Don't rebind changed holders if change animations are enabled.
- // We want the old contents for the animation and will get a new
- // holder for the new contents.
- requestLayout();
- }
- } else {
- // binding to a new view will need re-layout anyways. We can as well trigger
- // it here so that it happens during layout
- requestLayout();
- break;
- }
- }
- }
+ private boolean canReuseUpdatedViewHolder(ViewHolder viewHolder) {
+ return mItemAnimator == null || mItemAnimator.canReuseUpdatedViewHolder(viewHolder);
}
private void setDataSetChangedAfterLayout() {
@@ -3913,25 +3808,8 @@
overscrollY = dy - vresult;
}
TraceCompat.endSection();
- if (supportsChangeAnimations()) {
- // Fix up shadow views used by changing animations
- int count = mChildHelper.getChildCount();
- for (int i = 0; i < count; i++) {
- View view = mChildHelper.getChildAt(i);
- ViewHolder holder = getChildViewHolder(view);
- if (holder != null && holder.mShadowingHolder != null) {
- View shadowingView = holder.mShadowingHolder.itemView;
- int left = view.getLeft();
- int top = view.getTop();
- if (left != shadowingView.getLeft() ||
- top != shadowingView.getTop()) {
- shadowingView.layout(left, top,
- left + shadowingView.getWidth(),
- top + shadowingView.getHeight());
- }
- }
- }
- }
+ repositionShadowingViews();
+
onExitLayoutOrScroll();
resumeRequestLayout(false);
@@ -4097,6 +3975,26 @@
}
+ private void repositionShadowingViews() {
+ // Fix up shadow views used by change animations
+ int count = mChildHelper.getChildCount();
+ for (int i = 0; i < count; i++) {
+ View view = mChildHelper.getChildAt(i);
+ ViewHolder holder = getChildViewHolder(view);
+ if (holder != null && holder.mShadowingHolder != null) {
+ View shadowingView = holder.mShadowingHolder.itemView;
+ int left = view.getLeft();
+ int top = view.getTop();
+ if (left != shadowingView.getLeft() ||
+ top != shadowingView.getTop()) {
+ shadowingView.layout(left, top,
+ left + shadowingView.getWidth(),
+ top + shadowingView.getHeight());
+ }
+ }
+ }
+ }
+
private class RecyclerViewDataObserver extends AdapterDataObserver {
@Override
public void onChanged() {
@@ -4343,7 +4241,11 @@
// if it is a removed holder, nothing to verify since we cannot ask adapter anymore
// if it is not removed, verify the type and id.
if (holder.isRemoved()) {
- return true;
+ if (DEBUG && !mState.isPreLayout()) {
+ throw new IllegalStateException("should not receive a removed view unelss it"
+ + " is pre layout");
+ }
+ return mState.isPreLayout();
}
if (holder.mPosition < 0 || holder.mPosition >= mAdapter.getItemCount()) {
throw new IndexOutOfBoundsException("Inconsistency detected. Invalid view holder "
@@ -4554,6 +4456,23 @@
}
}
}
+
+ // This is very ugly but the only place we can grab this information
+ // before the View is rebound and returned to the LayoutManager for post layout ops.
+ // We don't need this in pre-layout since the VH is not updated by the LM.
+ if (fromScrap && !mState.isPreLayout() && holder
+ .hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST)) {
+ holder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+ if (mState.mRunSimpleAnimations) {
+ int changeFlags = ItemAnimator
+ .buildAdapterChangeFlagsForAnimations(holder);
+ changeFlags |= ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT;
+ final ItemHolderInfo info = mItemAnimator.recordPreLayoutInformation(mState,
+ holder, changeFlags, holder.getUnmodifiedPayloads());
+ recordAnimationInfoIfBouncedHiddenView(holder, info);
+ }
+ }
+
boolean bound = false;
if (mState.isPreLayout() && holder.isBound()) {
// do not update unless we absolutely have to.
@@ -4730,8 +4649,8 @@
holder);
}
if (forceRecycle || holder.isRecyclable()) {
- if (!holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED |
- ViewHolder.FLAG_CHANGED | ViewHolder.FLAG_UPDATE)) {
+ if (!holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED
+ | ViewHolder.FLAG_UPDATE)) {
// Retire oldest cached view
final int cachedViewSize = mCachedViews.size();
if (cachedViewSize == mViewCacheMax && cachedViewSize > 0) {
@@ -4752,7 +4671,7 @@
}
// even if the holder is not removed, we still call this method so that it is removed
// from view holder lists.
- mState.onViewRecycled(holder);
+ mViewInfoStore.removeViewHolder(holder);
if (!cached && !recycled && transientStatePreventsRecycling) {
holder.mOwnerRecyclerView = null;
}
@@ -4773,6 +4692,7 @@
void quickRecycleScrapView(View view) {
final ViewHolder holder = getChildViewHolderInt(view);
holder.mScrapContainer = null;
+ holder.mInChangeScrap = false;
holder.clearReturnedFromScrapFlag();
recycleViewHolderInternal(holder);
}
@@ -4788,18 +4708,20 @@
*/
void scrapView(View view) {
final ViewHolder holder = getChildViewHolderInt(view);
- holder.setScrapContainer(this);
- if (!holder.isChanged() || !supportsChangeAnimations()) {
+ if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)
+ || !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) {
if (holder.isInvalid() && !holder.isRemoved() && !mAdapter.hasStableIds()) {
throw new IllegalArgumentException("Called scrap view with an invalid view."
+ " Invalid views cannot be reused from scrap, they should rebound from"
+ " recycler pool.");
}
+ holder.setScrapContainer(this, false);
mAttachedScrap.add(holder);
} else {
if (mChangedScrap == null) {
mChangedScrap = new ArrayList<ViewHolder>();
}
+ holder.setScrapContainer(this, true);
mChangedScrap.add(holder);
}
}
@@ -4811,12 +4733,13 @@
* until it is explicitly removed and recycled.</p>
*/
void unscrapView(ViewHolder holder) {
- if (!holder.isChanged() || !supportsChangeAnimations() || mChangedScrap == null) {
- mAttachedScrap.remove(holder);
- } else {
+ if (holder.mInChangeScrap) {
mChangedScrap.remove(holder);
+ } else {
+ mAttachedScrap.remove(holder);
}
holder.mScrapContainer = null;
+ holder.mInChangeScrap = false;
holder.clearReturnedFromScrapFlag();
}
@@ -4830,6 +4753,9 @@
void clearScrap() {
mAttachedScrap.clear();
+ if (mChangedScrap != null) {
+ mChangedScrap.clear();
+ }
}
ViewHolder getChangedScrapViewForPosition(int position) {
@@ -4894,8 +4820,20 @@
if (!dryRun) {
View view = mChildHelper.findHiddenNonRemovedView(position, type);
if (view != null) {
- // ending the animation should cause it to get recycled before we reuse it
- mItemAnimator.endAnimation(getChildViewHolder(view));
+ // This View is good to be used. We just need to unhide, detach and move to the
+ // scrap list.
+ final ViewHolder vh = getChildViewHolderInt(view);
+ mChildHelper.unhide(view);
+ int layoutIndex = mChildHelper.indexOfChild(view);
+ if (layoutIndex == RecyclerView.NO_POSITION) {
+ throw new IllegalStateException("layout index should not be -1 after "
+ + "unhiding a view:" + vh);
+ }
+ mChildHelper.detachViewFromParent(layoutIndex);
+ scrapView(view);
+ vh.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP
+ | ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+ return vh;
}
}
@@ -4943,6 +4881,8 @@
}
return holder;
} else if (!dryRun) {
+ // if we are running animations, it is actually better to keep it in scrap
+ // but this would force layout manager to lay it out which would be bad.
// Recycle this scrap. Type mismatch.
mAttachedScrap.remove(i);
removeDetachedView(holder.itemView, false);
@@ -4977,7 +4917,7 @@
mAdapter.onViewRecycled(holder);
}
if (mState != null) {
- mState.onViewRecycled(holder);
+ mViewInfoStore.removeViewHolder(holder);
}
if (DEBUG) Log.d(TAG, "dispatchViewRecycled: " + holder);
}
@@ -6276,14 +6216,14 @@
final ViewHolder holder = getChildViewHolderInt(child);
if (disappearing || holder.isRemoved()) {
// these views will be hidden at the end of the layout pass.
- mRecyclerView.mState.addToDisappearingList(child);
+ mRecyclerView.mViewInfoStore.addToDisappearedInLayout(holder);
} else {
// This may look like unnecessary but may happen if layout manager supports
// predictive layouts and adapter removed then re-added the same item.
// In this case, added version will be visible in the post layout (because add is
// deferred) but RV will still bind it to the same View.
// So if a View re-appears in post layout pass, remove it from disappearing list.
- mRecyclerView.mState.removeFromDisappearingList(child);
+ mRecyclerView.mViewInfoStore.removeFromDisappearedInLayout(holder);
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (holder.wasReturnedFromScrap() || holder.isScrap()) {
@@ -6485,9 +6425,9 @@
public void attachView(View child, int index, LayoutParams lp) {
ViewHolder vh = getChildViewHolderInt(child);
if (vh.isRemoved()) {
- mRecyclerView.mState.addToDisappearingList(child);
+ mRecyclerView.mViewInfoStore.addToDisappearedInLayout(vh);
} else {
- mRecyclerView.mState.removeFromDisappearingList(child);
+ mRecyclerView.mViewInfoStore.removeFromDisappearedInLayout(vh);
}
mChildHelper.attachViewToParent(child, index, lp, vh.isRemoved());
if (DISPATCH_TEMP_DETACH) {
@@ -6785,7 +6725,7 @@
}
final ViewHolder vh = getChildViewHolderInt(view);
vh.addFlags(ViewHolder.FLAG_IGNORE);
- mRecyclerView.mState.onViewIgnored(vh);
+ mRecyclerView.mViewInfoStore.removeViewHolder(vh);
}
/**
@@ -6827,7 +6767,7 @@
}
return;
}
- if (viewHolder.isInvalid() && !viewHolder.isRemoved() && !viewHolder.isChanged() &&
+ if (viewHolder.isInvalid() && !viewHolder.isRemoved() &&
!mRecyclerView.mAdapter.hasStableIds()) {
removeViewAt(index);
recycler.recycleViewHolderInternal(viewHolder);
@@ -8236,12 +8176,6 @@
static final int FLAG_RETURNED_FROM_SCRAP = 1 << 5;
/**
- * This ViewHolder's contents have changed. This flag is used as an indication that
- * change animations may be used, if supported by the ItemAnimator.
- */
- static final int FLAG_CHANGED = 1 << 6;
-
- /**
* This ViewHolder is fully managed by the LayoutManager. We do not scrap, recycle or remove
* it unless LayoutManager is replaced.
* It is still fully visible to the LayoutManager.
@@ -8268,6 +8202,31 @@
*/
static final int FLAG_ADAPTER_FULLUPDATE = 1 << 10;
+ /**
+ * Used by ItemAnimator when a ViewHolder's position changes
+ */
+ static final int FLAG_MOVED = 1 << 11;
+
+ /**
+ * Used by ItemAnimator when a ViewHolder appears in pre-layout
+ */
+ static final int FLAG_APPEARED_IN_PRE_LAYOUT = 1 << 12;
+
+ /**
+ * Used when a ViewHolder starts the layout pass as a hidden ViewHolder but is re-used from
+ * hidden list (as if it was scrap) without being recycled in between.
+ *
+ * When a ViewHolder is hidden, there are 2 paths it can be re-used:
+ * a) Animation ends, view is recycled and used from the recycle pool.
+ * b) LayoutManager asks for the View for that position while the ViewHolder is hidden.
+ *
+ * This flag is used to represent "case b" where the ViewHolder is reused without being
+ * recycled (thus "bounced" from the hidden list). This state requires special handling
+ * because the ViewHolder must be added to pre layout maps for animations as if it was
+ * already there.
+ */
+ static final int FLAG_BOUNCED_FROM_HIDDEN_LIST = 1 << 13;
+
private int mFlags;
private static final List<Object> FULLUPDATE_PAYLOADS = Collections.EMPTY_LIST;
@@ -8280,6 +8239,8 @@
// If non-null, view is currently considered scrap and may be reused for other data by the
// scrap container.
private Recycler mScrapContainer = null;
+ // Keeps whether this ViewHolder lives in Change scrap or Attached scrap
+ private boolean mInChangeScrap = false;
// Saves isImportantForAccessibility value for the view item while it's in hidden state and
// marked as unimportant for accessibility.
@@ -8460,8 +8421,9 @@
mFlags = mFlags & ~FLAG_IGNORE;
}
- void setScrapContainer(Recycler recycler) {
+ void setScrapContainer(Recycler recycler, boolean isChangeScrap) {
mScrapContainer = recycler;
+ mInChangeScrap = isChangeScrap;
}
boolean isInvalid() {
@@ -8472,10 +8434,6 @@
return (mFlags & FLAG_UPDATE) != 0;
}
- boolean isChanged() {
- return (mFlags & FLAG_CHANGED) != 0;
- }
-
boolean isBound() {
return (mFlags & FLAG_BOUND) != 0;
}
@@ -8579,16 +8537,18 @@
final StringBuilder sb = new StringBuilder("ViewHolder{" +
Integer.toHexString(hashCode()) + " position=" + mPosition + " id=" + mItemId +
", oldPos=" + mOldPosition + ", pLpos:" + mPreLayoutPosition);
- if (isScrap()) sb.append(" scrap");
+ if (isScrap()) {
+ sb.append(" scrap ")
+ .append(mInChangeScrap ? "[changeScrap]" : "[attachedScrap]");
+ }
if (isInvalid()) sb.append(" invalid");
if (!isBound()) sb.append(" unbound");
if (needsUpdate()) sb.append(" update");
if (isRemoved()) sb.append(" removed");
if (shouldIgnore()) sb.append(" ignored");
- if (isChanged()) sb.append(" changed");
if (isTmpDetached()) sb.append(" tmpDetached");
if (!isRecyclable()) sb.append(" not recyclable(" + mIsRecyclableCount + ")");
- if (isAdapterPositionUnknown()) sb.append("undefined adapter position");
+ if (isAdapterPositionUnknown()) sb.append(" undefined adapter position");
if (itemView.getParent() == null) sb.append(" no parent");
sb.append("}");
@@ -8651,6 +8611,10 @@
private boolean doesTransientStatePreventRecycling() {
return (mFlags & FLAG_NOT_RECYCLABLE) == 0 && ViewCompat.hasTransientState(itemView);
}
+
+ boolean isUpdated() {
+ return (mFlags & FLAG_UPDATE) != 0;
+ }
}
private int getAdapterPositionFor(ViewHolder viewHolder) {
@@ -8785,7 +8749,7 @@
* @return true if the item the view corresponds to was changed in the data set
*/
public boolean isItemChanged() {
- return mViewHolder.isChanged();
+ return mViewHolder.isUpdated();
}
/**
@@ -9320,7 +9284,11 @@
}
}
- static class SavedState extends android.view.View.BaseSavedState {
+ /**
+ * This is public so that the CREATOR can be access on cold launch.
+ * @hide
+ */
+ public static class SavedState extends android.view.View.BaseSavedState {
Parcelable mLayoutState;
@@ -9375,15 +9343,6 @@
public static class State {
private int mTargetPosition = RecyclerView.NO_POSITION;
- ArrayMap<ViewHolder, ItemHolderInfo> mPreLayoutHolderMap =
- new ArrayMap<ViewHolder, ItemHolderInfo>();
- ArrayMap<ViewHolder, ItemHolderInfo> mPostLayoutHolderMap =
- new ArrayMap<ViewHolder, ItemHolderInfo>();
- // nullable
- ArrayMap<Long, ViewHolder> mOldChangedHolders = new ArrayMap<Long, ViewHolder>();
-
- // we use this like a set
- final List<View> mDisappearingViewsInLayoutPass = new ArrayList<View>();
private SparseArray<Object> mData;
@@ -9411,6 +9370,8 @@
private boolean mRunPredictiveAnimations = false;
+ private boolean mTrackOldChangeHolders = false;
+
State reset() {
mTargetPosition = RecyclerView.NO_POSITION;
if (mData != null) {
@@ -9547,45 +9508,10 @@
mItemCount;
}
- void onViewRecycled(ViewHolder holder) {
- mPreLayoutHolderMap.remove(holder);
- mPostLayoutHolderMap.remove(holder);
- if (mOldChangedHolders != null) {
- removeFrom(mOldChangedHolders, holder);
- }
- mDisappearingViewsInLayoutPass.remove(holder.itemView);
- // holder cannot be in new list.
- }
-
- public void onViewIgnored(ViewHolder holder) {
- onViewRecycled(holder);
- }
-
- private void removeFrom(ArrayMap<Long, ViewHolder> holderMap, ViewHolder holder) {
- for (int i = holderMap.size() - 1; i >= 0; i --) {
- if (holder == holderMap.valueAt(i)) {
- holderMap.removeAt(i);
- return;
- }
- }
- }
-
- void removeFromDisappearingList(View child) {
- mDisappearingViewsInLayoutPass.remove(child);
- }
-
- void addToDisappearingList(View child) {
- if (!mDisappearingViewsInLayoutPass.contains(child)) {
- mDisappearingViewsInLayoutPass.add(child);
- }
- }
-
@Override
public String toString() {
return "State{" +
"mTargetPosition=" + mTargetPosition +
- ", mPreLayoutHolderMap=" + mPreLayoutHolderMap +
- ", mPostLayoutHolderMap=" + mPostLayoutHolderMap +
", mData=" + mData +
", mItemCount=" + mItemCount +
", mPreviousLayoutItemCount=" + mPreviousLayoutItemCount +
@@ -9608,71 +9534,21 @@
private class ItemAnimatorRestoreListener implements ItemAnimator.ItemAnimatorListener {
@Override
- public void onRemoveFinished(ViewHolder item) {
+ public void onAnimationFinished(ViewHolder item) {
item.setIsRecyclable(true);
- if (!removeAnimatingView(item.itemView) && item.isTmpDetached()) {
- removeDetachedView(item.itemView, false);
- }
- }
-
- @Override
- public void onAddFinished(ViewHolder item) {
- item.setIsRecyclable(true);
- if (!item.shouldBeKeptAsChild()) {
- removeAnimatingView(item.itemView);
- }
- }
-
- @Override
- public void onMoveFinished(ViewHolder item) {
- item.setIsRecyclable(true);
- if (!item.shouldBeKeptAsChild()) {
- removeAnimatingView(item.itemView);
- }
- }
-
- @Override
- public void onChangeFinished(ViewHolder item) {
- item.setIsRecyclable(true);
- /**
- * We check both shadowed and shadowing because a ViewHolder may get both roles at the
- * same time.
- *
- * Assume this flow:
- * item X is represented by VH_1. Then itemX changes, so we create VH_2 .
- * RV sets the following and calls item animator:
- * VH_1.shadowed = VH_2;
- * VH_1.mChanged = true;
- * VH_2.shadowing =VH_1;
- *
- * Then, before the first change finishes, item changes again so we create VH_3.
- * RV sets the following and calls item animator:
- * VH_2.shadowed = VH_3
- * VH_2.mChanged = true
- * VH_3.shadowing = VH_2
- *
- * Because VH_2 already has an animation, it will be cancelled. At this point VH_2 has
- * both shadowing and shadowed fields set. Shadowing information is obsolete now
- * because the first animation where VH_2 is newViewHolder is not valid anymore.
- * We ended up in this case because VH_2 played both roles. On the other hand,
- * we DO NOT want to clear its changed flag.
- *
- * If second change was simply reverting first change, we would find VH_1 in
- * {@link Recycler#getScrapViewForPosition(int, int, boolean)} and recycle it before
- * re-using
- */
if (item.mShadowedHolder != null && item.mShadowingHolder == null) { // old vh
item.mShadowedHolder = null;
- item.setFlags(~ViewHolder.FLAG_CHANGED, item.mFlags);
}
// always null this because an OldViewHolder can never become NewViewHolder w/o being
// recycled.
item.mShadowingHolder = null;
if (!item.shouldBeKeptAsChild()) {
- removeAnimatingView(item.itemView);
+ if (!removeAnimatingView(item.itemView) && item.isTmpDetached()) {
+ removeDetachedView(item.itemView, false);
+ }
}
}
- };
+ }
/**
* This class defines the animations that take place on items as changes are made
@@ -9680,22 +9556,78 @@
*
* Subclasses of ItemAnimator can be used to implement custom animations for actions on
* ViewHolder items. The RecyclerView will manage retaining these items while they
- * are being animated, but implementors must call the appropriate "Starting"
- * ({@link #dispatchRemoveStarting(ViewHolder)}, {@link #dispatchMoveStarting(ViewHolder)},
- * {@link #dispatchChangeStarting(ViewHolder, boolean)}, or
- * {@link #dispatchAddStarting(ViewHolder)})
- * and "Finished" ({@link #dispatchRemoveFinished(ViewHolder)},
- * {@link #dispatchMoveFinished(ViewHolder)},
- * {@link #dispatchChangeFinished(ViewHolder, boolean)},
- * or {@link #dispatchAddFinished(ViewHolder)}) methods when each item animation is
- * being started and ended.
+ * are being animated, but implementors must call {@link #dispatchAnimationFinished(ViewHolder)}
+ * when a ViewHolder's animation is finished. In other words, there must be a matching
+ * {@link #dispatchAnimationFinished(ViewHolder)} call for each
+ * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) animateAppearance()},
+ * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateChange()}
+ * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) animatePersistence()},
+ * and
+ * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateDisappearance()} call.
*
- * <p>By default, RecyclerView uses {@link DefaultItemAnimator}</p>
+ * <p>By default, RecyclerView uses {@link DefaultItemAnimator}.</p>
*
* @see #setItemAnimator(ItemAnimator)
*/
+ @SuppressWarnings("UnusedParameters")
public static abstract class ItemAnimator {
+ /**
+ * The Item represented by this ViewHolder is updated.
+ * <p>
+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+ */
+ public static final int FLAG_CHANGED = ViewHolder.FLAG_UPDATE;
+
+ /**
+ * The Item represented by this ViewHolder is removed from the adapter.
+ * <p>
+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+ */
+ public static final int FLAG_REMOVED = ViewHolder.FLAG_REMOVED;
+
+ /**
+ * Adapter {@link Adapter#notifyDataSetChanged()} has been called and the content
+ * represented by this ViewHolder is invalid.
+ * <p>
+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+ */
+ public static final int FLAG_INVALIDATED = ViewHolder.FLAG_INVALID;
+
+ /**
+ * The position of the Item represented by this ViewHolder has been changed. This flag is
+ * not bound to {@link Adapter#notifyItemMoved(int, int)}. It might be set in response to
+ * any adapter change that may have a side effect on this item. (e.g. The item before this
+ * one has been removed from the Adapter).
+ * <p>
+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+ */
+ public static final int FLAG_MOVED = ViewHolder.FLAG_MOVED;
+
+ /**
+ * This ViewHolder was not laid out but has been added to the layout in pre-layout state
+ * by the {@link LayoutManager}. This means that the item was already in the Adapter but
+ * invisible and it may become visible in the post layout phase. LayoutManagers may prefer
+ * to add new items in pre-layout to specify their virtual location when they are invisible
+ * (e.g. to specify the item should <i>animate in</i> from below the visible area).
+ * <p>
+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+ */
+ public static final int FLAG_APPEARED_IN_PRE_LAYOUT
+ = ViewHolder.FLAG_APPEARED_IN_PRE_LAYOUT;
+
+ /**
+ * The set of flags that might be passed to
+ * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ */
+ @IntDef(flag=true, value={
+ FLAG_CHANGED, FLAG_REMOVED, FLAG_MOVED, FLAG_INVALIDATED,
+ FLAG_APPEARED_IN_PRE_LAYOUT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AdapterChanges {}
private ItemAnimatorListener mListener = null;
private ArrayList<ItemAnimatorFinishedListener> mFinishedListeners =
new ArrayList<ItemAnimatorFinishedListener>();
@@ -9705,8 +9637,6 @@
private long mMoveDuration = 250;
private long mChangeDuration = 250;
- private boolean mSupportsChangeAnimations = true;
-
/**
* Gets the current duration for which all move animations will run.
*
@@ -9780,35 +9710,6 @@
}
/**
- * Returns whether this ItemAnimator supports animations of change events.
- *
- * @return true if change animations are supported, false otherwise
- */
- public boolean getSupportsChangeAnimations() {
- return mSupportsChangeAnimations;
- }
-
- /**
- * Sets whether this ItemAnimator supports animations of item change events.
- * If you set this property to false, actions on the data set which change the
- * contents of items will not be animated. What those animations are is left
- * up to the discretion of the ItemAnimator subclass, in its
- * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} implementation.
- * The value of this property is true by default.
- *
- * @see Adapter#notifyItemChanged(int)
- * @see Adapter#notifyItemRangeChanged(int, int)
- *
- * @param supportsChangeAnimations true if change animations are supported by
- * this ItemAnimator, false otherwise. If the property is false, the ItemAnimator
- * will not receive a call to
- * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} when changes occur.
- */
- public void setSupportsChangeAnimations(boolean supportsChangeAnimations) {
- mSupportsChangeAnimations = supportsChangeAnimations;
- }
-
- /**
* Internal only:
* Sets the listener that must be called when the animator is finished
* animating the item (or immediately if no animation happens). This is set
@@ -9821,219 +9722,255 @@
}
/**
+ * Called by the RecyclerView before the layout begins. Item animator should record
+ * necessary information about the View before it is potentially rebound, moved or removed.
+ * <p>
+ * The data returned from this method will be passed to the related <code>animate**</code>
+ * methods.
+ * <p>
+ * Note that this method may be called after pre-layout phase if LayoutManager adds new
+ * Views to the layout in pre-layout pass.
+ * <p>
+ * The default implementation returns an {@link ItemHolderInfo} which holds the bounds of
+ * the View and the adapter change flags.
+ *
+ * @param state The current State of RecyclerView which includes some useful data
+ * about the layout that will be calculated.
+ * @param viewHolder The ViewHolder whose information should be recorded.
+ * @param changeFlags Additional information about what changes happened in the Adapter
+ * about the Item represented by this ViewHolder. For instance, if
+ * item is deleted from the adapter, {@link #FLAG_REMOVED} will be set.
+ * @param payloads The payload list that was previously passed to
+ * {@link Adapter#notifyItemChanged(int, Object)} or
+ * {@link Adapter#notifyItemRangeChanged(int, int, Object)}.
+ *
+ * @return An ItemHolderInfo instance that preserves necessary information about the
+ * ViewHolder. This object will be passed back to related <code>animate**</code> methods
+ * after layout is complete.
+ *
+ * @see #recordPostLayoutInformation(State, ViewHolder)
+ * @see #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * @see #animateDisappearance(ViewHolder, ItemHolderInfo)
+ * @see #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * @see #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ */
+ public @NonNull ItemHolderInfo recordPreLayoutInformation(@NonNull State state,
+ @NonNull ViewHolder viewHolder, @AdapterChanges int changeFlags,
+ @NonNull List<Object> payloads) {
+ return obtainHolderInfo().setFrom(viewHolder);
+ }
+
+ /**
+ * Called by the RecyclerView after the layout is complete. Item animator should record
+ * necessary information about the View's final state.
+ * <p>
+ * The data returned from this method will be passed to the related <code>animate**</code>
+ * methods.
+ * <p>
+ * The default implementation returns an {@link ItemHolderInfo} which holds the bounds of
+ * the View.
+ *
+ * @param state The current State of RecyclerView which includes some useful data about
+ * the layout that will be calculated.
+ * @param viewHolder The ViewHolder whose information should be recorded.
+ *
+ * @return An ItemHolderInfo that preserves necessary information about the ViewHolder.
+ * This object will be passed back to related <code>animate**</code> methods when
+ * RecyclerView decides how items should be animated.
+ *
+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+ * @see #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * @see #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * @see #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * @see #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ */
+ public @NonNull ItemHolderInfo recordPostLayoutInformation(@NonNull State state,
+ @NonNull ViewHolder viewHolder) {
+ return obtainHolderInfo().setFrom(viewHolder);
+ }
+
+ /**
+ * Called by the RecyclerView when a ViewHolder has disappeared from the layout.
+ * <p>
+ * This means that the View was a child of the LayoutManager when layout started but has
+ * been removed by the LayoutManager. It might have been removed from the adapter or simply
+ * become invisible due to other factors. You can distinguish these two cases by checking
+ * the change flags that were passed to
+ * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ * <p>
+ * If LayoutManager supports predictive animations, it might provide a target disappear
+ * location for the View by laying it out in that location. When that happens,
+ * RecyclerView will call {@link #recordPostLayoutInformation(State, ViewHolder)} and the
+ * response of that call will be passed to this method as the <code>postLayoutInfo</code>.
+ * <p>
+ * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+ * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+ * decides not to animate the view).
+ *
+ * @param viewHolder The ViewHolder which should be animated
+ * @param preLayoutInfo The information that was returned from
+ * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ * @param postLayoutInfo The information that was returned from
+ * {@link #recordPostLayoutInformation(State, ViewHolder)}. Might be
+ * null if the LayoutManager did not layout the item.
+ *
+ * @return true if a later call to {@link #runPendingAnimations()} is requested,
+ * false otherwise.
+ */
+ public abstract boolean animateDisappearance(@NonNull ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo);
+
+ /**
+ * Called by the RecyclerView when a ViewHolder is added to the layout.
+ * <p>
+ * In detail, this means that the ViewHolder was <b>not</b> a child when the layout started
+ * but has been added by the LayoutManager. It might be newly added to the adapter or
+ * simply become visible due to other factors.
+ * <p>
+ * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+ * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+ * decides not to animate the view).
+ *
+ * @param viewHolder The ViewHolder which should be animated
+ * @param preLayoutInfo The information that was returned from
+ * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ * Might be null if Item was just added to the adapter or
+ * LayoutManager does not support predictive animations or it could
+ * not predict that this ViewHolder will become visible.
+ * @param postLayoutInfo The information that was returned from {@link
+ * #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ *
+ * @return true if a later call to {@link #runPendingAnimations()} is requested,
+ * false otherwise.
+ */
+ public abstract boolean animateAppearance(@NonNull ViewHolder viewHolder,
+ @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+ /**
+ * Called by the RecyclerView when a ViewHolder is present in both before and after the
+ * layout and RecyclerView has not received a {@link Adapter#notifyItemChanged(int)} call
+ * for it or a {@link Adapter#notifyDataSetChanged()} call.
+ * <p>
+ * This ViewHolder still represents the same data that it was representing when the layout
+ * started but its position / size may be changed by the LayoutManager.
+ * <p>
+ * If the Item's layout position didn't change, RecyclerView still calls this method because
+ * it does not track this information (or does not necessarily know that an animation is
+ * not required). Your ItemAnimator should handle this case and if there is nothing to
+ * animate, it should call {@link #dispatchAnimationFinished(ViewHolder)} and return
+ * <code>false</code>.
+ * <p>
+ * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+ * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+ * decides not to animate the view).
+ *
+ * @param viewHolder The ViewHolder which should be animated
+ * @param preLayoutInfo The information that was returned from
+ * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ * @param postLayoutInfo The information that was returned from {@link
+ * #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ *
+ * @return true if a later call to {@link #runPendingAnimations()} is requested,
+ * false otherwise.
+ */
+ public abstract boolean animatePersistence(@NonNull ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+ /**
+ * Called by the RecyclerView when an adapter item is present both before and after the
+ * layout and RecyclerView has received a {@link Adapter#notifyItemChanged(int)} call
+ * for it. This method may also be called when
+ * {@link Adapter#notifyDataSetChanged()} is called and adapter has stable ids so that
+ * RecyclerView could still rebind views to the same ViewHolders. If viewType changes when
+ * {@link Adapter#notifyDataSetChanged()} is called, this method <b>will not</b> be called,
+ * instead, {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)} will be
+ * called for the new ViewHolder and the old one will be recycled.
+ * <p>
+ * If this method is called due to a {@link Adapter#notifyDataSetChanged()} call, there is
+ * a good possibility that item contents didn't really change but it is rebound from the
+ * adapter. {@link DefaultItemAnimator} will skip animating the View if its location on the
+ * screen didn't change and your animator should handle this case as well and avoid creating
+ * unnecessary animations.
+ * <p>
+ * When an item is updated, ItemAnimator has a chance to ask RecyclerView to keep the
+ * previous presentation of the item as-is and supply a new ViewHolder for the updated
+ * presentation (see: {@link #canReuseUpdatedViewHolder(ViewHolder)}.
+ * This is useful if you don't know the contents of the Item and would like
+ * to cross-fade the old and the new one ({@link DefaultItemAnimator} uses this technique).
+ * <p>
+ * When you are writing a custom item animator for your layout, it might be more performant
+ * and elegant to re-use the same ViewHolder and animate the content changes manually.
+ * <p>
+ * When {@link Adapter#notifyItemChanged(int)} is called, the Item's view type may change.
+ * If the Item's view type has changed or ItemAnimator returned <code>false</code> for
+ * this ViewHolder when {@link #canReuseUpdatedViewHolder(ViewHolder)} was called, the
+ * <code>oldHolder</code> and <code>newHolder</code> will be different ViewHolder instances
+ * which represent the same Item. In that case, only the new ViewHolder is visible
+ * to the LayoutManager but RecyclerView keeps old ViewHolder attached for animations.
+ * <p>
+ * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} for each distinct
+ * ViewHolder when their animation is complete
+ * (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it decides not to
+ * animate the view).
+ * <p>
+ * If oldHolder and newHolder are the same instance, you should call
+ * {@link #dispatchAnimationFinished(ViewHolder)} <b>only once</b>.
+ *
+ * @param oldHolder The ViewHolder before the layout is started, might be the same
+ * instance with newHolder.
+ * @param newHolder The ViewHolder after the layout is finished, might be the same
+ * instance with oldHolder.
+ * @param preLayoutInfo The information that was returned from
+ * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ * @param postLayoutInfo The information that was returned from {@link
+ * #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+ *
+ * @return true if a later call to {@link #runPendingAnimations()} is requested,
+ * false otherwise.
+ */
+ public abstract boolean animateChange(@NonNull ViewHolder oldHolder,
+ @NonNull ViewHolder newHolder,
+ @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+ @AdapterChanges static int buildAdapterChangeFlagsForAnimations(ViewHolder viewHolder) {
+ int flags = viewHolder.mFlags & (FLAG_INVALIDATED | FLAG_REMOVED | FLAG_CHANGED);
+ if (viewHolder.isInvalid()) {
+ return FLAG_INVALIDATED;
+ }
+ if ((flags & FLAG_INVALIDATED) == 0) {
+ final int oldPos = viewHolder.getOldPosition();
+ final int pos = viewHolder.getAdapterPosition();
+ if (oldPos != NO_POSITION && pos != NO_POSITION && oldPos != pos){
+ flags |= FLAG_MOVED;
+ }
+ }
+ return flags;
+ }
+
+ /**
* Called when there are pending animations waiting to be started. This state
- * is governed by the return values from {@link #animateAdd(ViewHolder) animateAdd()},
- * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()}, and
- * {@link #animateRemove(ViewHolder) animateRemove()}, which inform the
- * RecyclerView that the ItemAnimator wants to be called later to start the
- * associated animations. runPendingAnimations() will be scheduled to be run
- * on the next frame.
+ * is governed by the return values from
+ * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateAppearance()},
+ * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateChange()}
+ * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animatePersistence()}, and
+ * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateDisappearance()}, which inform the RecyclerView that the ItemAnimator wants to be
+ * called later to start the associated animations. runPendingAnimations() will be scheduled
+ * to be run on the next frame.
*/
abstract public void runPendingAnimations();
/**
- * Called when an item is removed from the RecyclerView. Implementors can choose
- * whether and how to animate that change, but must always call
- * {@link #dispatchRemoveFinished(ViewHolder)} when done, either
- * immediately (if no animation will occur) or after the animation actually finishes.
- * The return value indicates whether an animation has been set up and whether the
- * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
- * next opportunity. This mechanism allows ItemAnimator to set up individual animations
- * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
- * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
- * {@link #animateRemove(ViewHolder) animateRemove()}, and
- * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
- * then start the animations together in the later call to {@link #runPendingAnimations()}.
- *
- * <p>This method may also be called for disappearing items which continue to exist in the
- * RecyclerView, but for which the system does not have enough information to animate
- * them out of view. In that case, the default animation for removing items is run
- * on those items as well.</p>
- *
- * @param holder The item that is being removed.
- * @return true if a later call to {@link #runPendingAnimations()} is requested,
- * false otherwise.
- */
- abstract public boolean animateRemove(ViewHolder holder);
-
- /**
- * Called when an item is added to the RecyclerView. Implementors can choose
- * whether and how to animate that change, but must always call
- * {@link #dispatchAddFinished(ViewHolder)} when done, either
- * immediately (if no animation will occur) or after the animation actually finishes.
- * The return value indicates whether an animation has been set up and whether the
- * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
- * next opportunity. This mechanism allows ItemAnimator to set up individual animations
- * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
- * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
- * {@link #animateRemove(ViewHolder) animateRemove()}, and
- * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
- * then start the animations together in the later call to {@link #runPendingAnimations()}.
- *
- * <p>This method may also be called for appearing items which were already in the
- * RecyclerView, but for which the system does not have enough information to animate
- * them into view. In that case, the default animation for adding items is run
- * on those items as well.</p>
- *
- * @param holder The item that is being added.
- * @return true if a later call to {@link #runPendingAnimations()} is requested,
- * false otherwise.
- */
- abstract public boolean animateAdd(ViewHolder holder);
-
- /**
- * Called when an item is moved in the RecyclerView. Implementors can choose
- * whether and how to animate that change, but must always call
- * {@link #dispatchMoveFinished(ViewHolder)} when done, either
- * immediately (if no animation will occur) or after the animation actually finishes.
- * The return value indicates whether an animation has been set up and whether the
- * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
- * next opportunity. This mechanism allows ItemAnimator to set up individual animations
- * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
- * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
- * {@link #animateRemove(ViewHolder) animateRemove()}, and
- * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
- * then start the animations together in the later call to {@link #runPendingAnimations()}.
- *
- * @param holder The item that is being moved.
- * @return true if a later call to {@link #runPendingAnimations()} is requested,
- * false otherwise.
- */
- abstract public boolean animateMove(ViewHolder holder, int fromX, int fromY,
- int toX, int toY);
-
- /**
- * Called when an item is changed in the RecyclerView, as indicated by a call to
- * {@link Adapter#notifyItemChanged(int)} or
- * {@link Adapter#notifyItemRangeChanged(int, int)}.
- * <p>
- * Implementers can choose whether and how to animate changes, but must always call
- * {@link #dispatchChangeFinished(ViewHolder, boolean)} for each non-null ViewHolder,
- * either immediately (if no animation will occur) or after the animation actually finishes.
- * The return value indicates whether an animation has been set up and whether the
- * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
- * next opportunity. This mechanism allows ItemAnimator to set up individual animations
- * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
- * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
- * {@link #animateRemove(ViewHolder) animateRemove()}, and
- * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
- * then start the animations together in the later call to {@link #runPendingAnimations()}.
- *
- * @param oldHolder The original item that changed.
- * @param newHolder The new item that was created with the changed content. Might be null
- * @param fromLeft Left of the old view holder
- * @param fromTop Top of the old view holder
- * @param toLeft Left of the new view holder
- * @param toTop Top of the new view holder
- * @return true if a later call to {@link #runPendingAnimations()} is requested,
- * false otherwise.
- */
- abstract public boolean animateChange(ViewHolder oldHolder,
- ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop);
-
-
- /**
- * Method to be called by subclasses when a remove animation is done.
- *
- * @param item The item which has been removed
- */
- public final void dispatchRemoveFinished(ViewHolder item) {
- onRemoveFinished(item);
- if (mListener != null) {
- mListener.onRemoveFinished(item);
- }
- }
-
- /**
- * Method to be called by subclasses when a move animation is done.
- *
- * @param item The item which has been moved
- */
- public final void dispatchMoveFinished(ViewHolder item) {
- onMoveFinished(item);
- if (mListener != null) {
- mListener.onMoveFinished(item);
- }
- }
-
- /**
- * Method to be called by subclasses when an add animation is done.
- *
- * @param item The item which has been added
- */
- public final void dispatchAddFinished(ViewHolder item) {
- onAddFinished(item);
- if (mListener != null) {
- mListener.onAddFinished(item);
- }
- }
-
- /**
- * Method to be called by subclasses when a change animation is done.
- *
- * @see #animateChange(ViewHolder, ViewHolder, int, int, int, int)
- * @param item The item which has been changed (this method must be called for
- * each non-null ViewHolder passed into
- * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
- * @param oldItem true if this is the old item that was changed, false if
- * it is the new item that replaced the old item.
- */
- public final void dispatchChangeFinished(ViewHolder item, boolean oldItem) {
- onChangeFinished(item, oldItem);
- if (mListener != null) {
- mListener.onChangeFinished(item);
- }
- }
-
- /**
- * Method to be called by subclasses when a remove animation is being started.
- *
- * @param item The item being removed
- */
- public final void dispatchRemoveStarting(ViewHolder item) {
- onRemoveStarting(item);
- }
-
- /**
- * Method to be called by subclasses when a move animation is being started.
- *
- * @param item The item being moved
- */
- public final void dispatchMoveStarting(ViewHolder item) {
- onMoveStarting(item);
- }
-
- /**
- * Method to be called by subclasses when an add animation is being started.
- *
- * @param item The item being added
- */
- public final void dispatchAddStarting(ViewHolder item) {
- onAddStarting(item);
- }
-
- /**
- * Method to be called by subclasses when a change animation is being started.
- *
- * @param item The item which has been changed (this method must be called for
- * each non-null ViewHolder passed into
- * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
- * @param oldItem true if this is the old item that was changed, false if
- * it is the new item that replaced the old item.
- */
- public final void dispatchChangeStarting(ViewHolder item, boolean oldItem) {
- onChangeStarting(item, oldItem);
- }
-
- /**
* Method called when an animation on a view should be ended immediately.
* This could happen when other events, like scrolling, occur, so that
* animating views can be quickly put into their proper end locations.
* Implementations should ensure that any animations running on the item
* are canceled and affected properties are set to their end values.
- * Also, appropriate dispatch methods (e.g., {@link #dispatchAddFinished(ViewHolder)}
- * should be called since the animations are effectively done when this
- * method is called.
+ * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished
+ * animation since the animations are effectively done when this method is called.
*
* @param item The item for which an animation should be stopped.
*/
@@ -10045,9 +9982,8 @@
* animating views can be quickly put into their proper end locations.
* Implementations should ensure that any animations running on any items
* are canceled and affected properties are set to their end values.
- * Also, appropriate dispatch methods (e.g., {@link #dispatchAddFinished(ViewHolder)}
- * should be called since the animations are effectively done when this
- * method is called.
+ * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished
+ * animation since the animations are effectively done when this method is called.
*/
abstract public void endAnimations();
@@ -10061,6 +9997,82 @@
abstract public boolean isRunning();
/**
+ * Method to be called by subclasses when an animation is finished.
+ * <p>
+ * For each call RecyclerView makes to
+ * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateAppearance()},
+ * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animatePersistence()}, or
+ * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateDisappearance()}, there
+ * should
+ * be a matching {@link #dispatchAnimationFinished(ViewHolder)} call by the subclass.
+ * <p>
+ * For {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateChange()}, sublcass should call this method for both the <code>oldHolder</code>
+ * and <code>newHolder</code> (if they are not the same instance).
+ *
+ * @param viewHolder The ViewHolder whose animation is finished.
+ * @see #onAnimationFinished(ViewHolder)
+ */
+ public final void dispatchAnimationFinished(ViewHolder viewHolder) {
+ onAnimationFinished(viewHolder);
+ if (mListener != null) {
+ mListener.onAnimationFinished(viewHolder);
+ }
+ }
+
+ /**
+ * Called after {@link #dispatchAnimationFinished(ViewHolder)} is called by the
+ * ItemAniamtor.
+ *
+ * @param viewHolder The ViewHolder whose animation is finished. There might still be other
+ * animations running on this ViewHolder.
+ * @see #dispatchAnimationFinished(ViewHolder)
+ */
+ public void onAnimationFinished(ViewHolder viewHolder) {
+ }
+
+ /**
+ * Method to be called by subclasses when an animation is started.
+ * <p>
+ * For each call RecyclerView makes to
+ * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateAppearance()},
+ * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animatePersistence()}, or
+ * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateDisappearance()}, there should be a matching
+ * {@link #dispatchAnimationStarted(ViewHolder)} call by the subclass.
+ * <p>
+ * For {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * animateChange()}, sublcass should call this method for both the <code>oldHolder</code>
+ * and <code>newHolder</code> (if they are not the same instance).
+ * <p>
+ * If your ItemAnimator decides not to animate a ViewHolder, it should call
+ * {@link #dispatchAnimationFinished(ViewHolder)} <b>without</b> calling
+ * {@link #dispatchAnimationStarted(ViewHolder)}.
+ *
+ * @param viewHolder The ViewHolder whose animation is starting.
+ * @see #onAnimationStarted(ViewHolder)
+ */
+ public final void dispatchAnimationStarted(ViewHolder viewHolder) {
+ onAnimationStarted(viewHolder);
+ }
+
+ /**
+ * Called when a new animation is started on the given ViewHolder.
+ *
+ * @param viewHolder The ViewHolder which started animating. Note that the ViewHolder
+ * might already be animating and this might be another animation.
+ * @see #dispatchAnimationStarted(ViewHolder)
+ */
+ public void onAnimationStarted(ViewHolder viewHolder) {
+
+ }
+
+ /**
* Like {@link #isRunning()}, this method returns whether there are any item
* animations currently running. Addtionally, the listener passed in will be called
* when there are no item animations running, either immediately (before the method
@@ -10089,15 +10101,23 @@
}
/**
- * The interface to be implemented by listeners to animation events from this
- * ItemAnimator. This is used internally and is not intended for developers to
- * create directly.
+ * When an item is changed, ItemAnimator can decide whether it wants to re-use
+ * the same ViewHolder for animations or RecyclerView should create a copy of the
+ * item and ItemAnimator will use both to run the animation (e.g. cross-fade).
+ * <p>
+ * Note that this method will only be called if the {@link ViewHolder} still has the same
+ * type ({@link Adapter#getItemViewType(int)}). Otherwise, ItemAnimator will always receive
+ * both {@link ViewHolder}s in the
+ * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)} method.
+ *
+ * @param viewHolder The ViewHolder which represents the changed item's old content.
+ *
+ * @return True if RecyclerView should just rebind to the same ViewHolder or false if
+ * RecyclerView should create a new ViewHolder and pass this ViewHolder to the
+ * ItemAnimator to animate. Default implementation returns <code>true</code>.
*/
- interface ItemAnimatorListener {
- void onRemoveFinished(ViewHolder item);
- void onAddFinished(ViewHolder item);
- void onMoveFinished(ViewHolder item);
- void onChangeFinished(ViewHolder item);
+ public boolean canReuseUpdatedViewHolder(ViewHolder viewHolder) {
+ return true;
}
/**
@@ -10113,6 +10133,28 @@
}
/**
+ * Returns a new {@link ItemHolderInfo} which will be used to store information about the
+ * ViewHolder. This information will later be passed into <code>animate**</code> methods.
+ * <p>
+ * You can override this method if you want to extend {@link ItemHolderInfo} and provide
+ * your own instances.
+ *
+ * @return A new {@link ItemHolderInfo}.
+ */
+ public ItemHolderInfo obtainHolderInfo() {
+ return new ItemHolderInfo();
+ }
+
+ /**
+ * The interface to be implemented by listeners to animation events from this
+ * ItemAnimator. This is used internally and is not intended for developers to
+ * create directly.
+ */
+ interface ItemAnimatorListener {
+ void onAnimationFinished(ViewHolder item);
+ }
+
+ /**
* This interface is used to inform listeners when all pending or running animations
* in an ItemAnimator are finished. This can be used, for example, to delay an action
* in a data set until currently-running animations are complete.
@@ -10124,105 +10166,79 @@
}
/**
- * Called when a remove animation is being started on the given ViewHolder.
- * The default implementation does nothing. Subclasses may wish to override
- * this method to handle any ViewHolder-specific operations linked to animation
- * lifecycles.
- *
- * @param item The ViewHolder being animated.
+ * A simple data structure that holds information about an item's bounds.
+ * This information is used in calculating item animations. Default implementation of
+ * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, List)} and
+ * {@link #recordPostLayoutInformation(RecyclerView.State, ViewHolder)} returns this data
+ * structure. You can extend this class if you would like to keep more information about
+ * the Views.
+ * <p>
+ * If you want to provide your own implementation butstill use `super` methods to record
+ * basic information, you can override {@link #obtainHolderInfo()} to provide your own
+ * instances.
*/
- public void onRemoveStarting(ViewHolder item) {}
+ public static class ItemHolderInfo {
- /**
- * Called when a remove animation has ended on the given ViewHolder.
- * The default implementation does nothing. Subclasses may wish to override
- * this method to handle any ViewHolder-specific operations linked to animation
- * lifecycles.
- *
- * @param item The ViewHolder being animated.
- */
- public void onRemoveFinished(ViewHolder item) {}
+ /**
+ * The left edge of the View (excluding decorations)
+ */
+ public int left;
- /**
- * Called when an add animation is being started on the given ViewHolder.
- * The default implementation does nothing. Subclasses may wish to override
- * this method to handle any ViewHolder-specific operations linked to animation
- * lifecycles.
- *
- * @param item The ViewHolder being animated.
- */
- public void onAddStarting(ViewHolder item) {}
+ /**
+ * The top edge of the View (excluding decorations)
+ */
+ public int top;
- /**
- * Called when an add animation has ended on the given ViewHolder.
- * The default implementation does nothing. Subclasses may wish to override
- * this method to handle any ViewHolder-specific operations linked to animation
- * lifecycles.
- *
- * @param item The ViewHolder being animated.
- */
- public void onAddFinished(ViewHolder item) {}
+ /**
+ * The right edge of the View (excluding decorations)
+ */
+ public int right;
- /**
- * Called when a move animation is being started on the given ViewHolder.
- * The default implementation does nothing. Subclasses may wish to override
- * this method to handle any ViewHolder-specific operations linked to animation
- * lifecycles.
- *
- * @param item The ViewHolder being animated.
- */
- public void onMoveStarting(ViewHolder item) {}
+ /**
+ * The bottom edge of the View (excluding decorations)
+ */
+ public int bottom;
- /**
- * Called when a move animation has ended on the given ViewHolder.
- * The default implementation does nothing. Subclasses may wish to override
- * this method to handle any ViewHolder-specific operations linked to animation
- * lifecycles.
- *
- * @param item The ViewHolder being animated.
- */
- public void onMoveFinished(ViewHolder item) {}
+ /**
+ * The change flags that were passed to
+ * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, List)}.
+ */
+ @AdapterChanges
+ public int changeFlags;
- /**
- * Called when a change animation is being started on the given ViewHolder.
- * The default implementation does nothing. Subclasses may wish to override
- * this method to handle any ViewHolder-specific operations linked to animation
- * lifecycles.
- *
- * @param item The ViewHolder being animated.
- * @param oldItem true if this is the old item that was changed, false if
- * it is the new item that replaced the old item.
- */
- public void onChangeStarting(ViewHolder item, boolean oldItem) {}
+ public ItemHolderInfo() {
+ }
- /**
- * Called when a change animation has ended on the given ViewHolder.
- * The default implementation does nothing. Subclasses may wish to override
- * this method to handle any ViewHolder-specific operations linked to animation
- * lifecycles.
- *
- * @param item The ViewHolder being animated.
- * @param oldItem true if this is the old item that was changed, false if
- * it is the new item that replaced the old item.
- */
- public void onChangeFinished(ViewHolder item, boolean oldItem) {}
+ /**
+ * Sets the {@link #left}, {@link #top}, {@link #right} and {@link #bottom} values from
+ * the given ViewHolder. Clears all {@link #changeFlags}.
+ *
+ * @param holder The ViewHolder whose bounds should be copied.
+ * @return This {@link ItemHolderInfo}
+ */
+ public ItemHolderInfo setFrom(RecyclerView.ViewHolder holder) {
+ return setFrom(holder, 0);
+ }
- }
-
- /**
- * Internal data structure that holds information about an item's bounds.
- * This information is used in calculating item animations.
- */
- private static class ItemHolderInfo {
- ViewHolder holder;
- int left, top, right, bottom;
-
- ItemHolderInfo(ViewHolder holder, int left, int top, int right, int bottom) {
- this.holder = holder;
- this.left = left;
- this.top = top;
- this.right = right;
- this.bottom = bottom;
+ /**
+ * Sets the {@link #left}, {@link #top}, {@link #right} and {@link #bottom} values from
+ * the given ViewHolder and sets the {@link #changeFlags} to the given flags parameter.
+ *
+ * @param holder The ViewHolder whose bounds should be copied.
+ * @param flags The adapter change flags that were passed into
+ * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int,
+ * List)}.
+ * @return This {@link ItemHolderInfo}
+ */
+ public ItemHolderInfo setFrom(RecyclerView.ViewHolder holder,
+ @AdapterChanges int flags) {
+ final View view = holder.itemView;
+ this.left = view.getLeft();
+ this.top = view.getTop();
+ this.right = view.getRight();
+ this.bottom = view.getBottom();
+ return this;
+ }
}
}
@@ -10243,7 +10259,7 @@
* order of two views will not have any effect if their elevation values are different since
* elevation overrides the result of this callback.
*/
- public static interface ChildDrawingOrderCallback {
+ public interface ChildDrawingOrderCallback {
/**
* Returns the index of the child to draw for this iteration. Override this
* if you want to change the drawing order of children. By default, it
@@ -10254,6 +10270,6 @@
*
* @see RecyclerView#setChildDrawingOrderCallback(RecyclerView.ChildDrawingOrderCallback)
*/
- public int onGetChildDrawingOrder(int childCount, int i);
+ int onGetChildDrawingOrder(int childCount, int i);
}
}
diff --git a/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java b/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java
new file mode 100644
index 0000000..1266236
--- /dev/null
+++ b/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java
@@ -0,0 +1,429 @@
+package android.support.v7.widget;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * A wrapper class for ItemAnimator that records View bounds and decides whether it should run
+ * move, change, add or remove animations. This class also replicates the original ItemAnimator
+ * API.
+ * <p>
+ * It uses {@link ItemHolderInfo} to track the bounds information of the Views. If you would like
+ * to
+ * extend this class, you can override {@link #obtainHolderInfo()} method to provide your own info
+ * class that extends {@link ItemHolderInfo}.
+ */
+abstract public class
+ SimpleItemAnimator extends RecyclerView.ItemAnimator {
+
+ private static final boolean DEBUG = false;
+
+ private static final String TAG = "SimpleItemAnimator";
+
+ boolean mSupportsChangeAnimations = true;
+
+ /**
+ * Returns whether this ItemAnimator supports animations of change events.
+ *
+ * @return true if change animations are supported, false otherwise
+ */
+ @SuppressWarnings("unused")
+ public boolean getSupportsChangeAnimations() {
+ return mSupportsChangeAnimations;
+ }
+
+ /**
+ * Sets whether this ItemAnimator supports animations of item change events.
+ * If you set this property to false, actions on the data set which change the
+ * contents of items will not be animated. What those animations do is left
+ * up to the discretion of the ItemAnimator subclass, in its
+ * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} implementation.
+ * The value of this property is true by default.
+ *
+ * @param supportsChangeAnimations true if change animations are supported by
+ * this ItemAnimator, false otherwise. If the property is false,
+ * the ItemAnimator
+ * will not receive a call to
+ * {@link #animateChange(ViewHolder, ViewHolder, int, int, int,
+ * int)} when changes occur.
+ * @see Adapter#notifyItemChanged(int)
+ * @see Adapter#notifyItemRangeChanged(int, int)
+ */
+ public void setSupportsChangeAnimations(boolean supportsChangeAnimations) {
+ mSupportsChangeAnimations = supportsChangeAnimations;
+ }
+
+ @Override
+ public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
+ return !mSupportsChangeAnimations || viewHolder.isInvalid();
+ }
+
+ @Override
+ public boolean animateDisappearance(@NonNull ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) {
+ int oldLeft = preLayoutInfo.left;
+ int oldTop = preLayoutInfo.top;
+ View disappearingItemView = viewHolder.itemView;
+ int newLeft = postLayoutInfo == null ? disappearingItemView.getLeft() : postLayoutInfo.left;
+ int newTop = postLayoutInfo == null ? disappearingItemView.getTop() : postLayoutInfo.top;
+ if (!viewHolder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) {
+ disappearingItemView.layout(newLeft, newTop,
+ newLeft + disappearingItemView.getWidth(),
+ newTop + disappearingItemView.getHeight());
+ if (DEBUG) {
+ Log.d(TAG, "DISAPPEARING: " + viewHolder + " with view " + disappearingItemView);
+ }
+ return animateMove(viewHolder, oldLeft, oldTop, newLeft, newTop);
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "REMOVED: " + viewHolder + " with view " + disappearingItemView);
+ }
+ return animateRemove(viewHolder);
+ }
+ }
+
+ @Override
+ public boolean animateAppearance(@NonNull ViewHolder viewHolder,
+ @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
+ if (preLayoutInfo != null && (preLayoutInfo.left != postLayoutInfo.left
+ || preLayoutInfo.top != postLayoutInfo.top)) {
+ // slide items in if before/after locations differ
+ if (DEBUG) {
+ Log.d(TAG, "APPEARING: " + viewHolder + " with view " + viewHolder);
+ }
+ return animateMove(viewHolder, preLayoutInfo.left, preLayoutInfo.top,
+ postLayoutInfo.left, postLayoutInfo.top);
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "ADDED: " + viewHolder + " with view " + viewHolder);
+ }
+ return animateAdd(viewHolder);
+ }
+ }
+
+ @Override
+ public boolean animatePersistence(@NonNull ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+ if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
+ if (DEBUG) {
+ Log.d(TAG, "PERSISTENT: " + viewHolder +
+ " with view " + viewHolder.itemView);
+ }
+ return animateMove(viewHolder,
+ preInfo.left, preInfo.top, postInfo.left, postInfo.top);
+ }
+ dispatchMoveFinished(viewHolder);
+ return false;
+ }
+
+ @Override
+ public boolean animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder,
+ @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+ if (DEBUG) {
+ Log.d(TAG, "CHANGED: " + oldHolder + " with view " + oldHolder.itemView);
+ }
+ final int fromLeft = preInfo.left;
+ final int fromTop = preInfo.top;
+ final int toLeft, toTop;
+ if (newHolder.shouldIgnore()) {
+ toLeft = preInfo.left;
+ toTop = preInfo.top;
+ } else {
+ toLeft = postInfo.left;
+ toTop = postInfo.top;
+ }
+ return animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft, toTop);
+ }
+
+ /**
+ * Called when an item is removed from the RecyclerView. Implementors can choose
+ * whether and how to animate that change, but must always call
+ * {@link #dispatchRemoveFinished(ViewHolder)} when done, either
+ * immediately (if no animation will occur) or after the animation actually finishes.
+ * The return value indicates whether an animation has been set up and whether the
+ * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+ * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+ * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+ * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+ * {@link #animateRemove(ViewHolder) animateRemove()}, and
+ * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+ * then start the animations together in the later call to {@link #runPendingAnimations()}.
+ *
+ * <p>This method may also be called for disappearing items which continue to exist in the
+ * RecyclerView, but for which the system does not have enough information to animate
+ * them out of view. In that case, the default animation for removing items is run
+ * on those items as well.</p>
+ *
+ * @param holder The item that is being removed.
+ * @return true if a later call to {@link #runPendingAnimations()} is requested,
+ * false otherwise.
+ */
+ abstract public boolean animateRemove(ViewHolder holder);
+
+ /**
+ * Called when an item is added to the RecyclerView. Implementors can choose
+ * whether and how to animate that change, but must always call
+ * {@link #dispatchAddFinished(ViewHolder)} when done, either
+ * immediately (if no animation will occur) or after the animation actually finishes.
+ * The return value indicates whether an animation has been set up and whether the
+ * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+ * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+ * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+ * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+ * {@link #animateRemove(ViewHolder) animateRemove()}, and
+ * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+ * then start the animations together in the later call to {@link #runPendingAnimations()}.
+ *
+ * <p>This method may also be called for appearing items which were already in the
+ * RecyclerView, but for which the system does not have enough information to animate
+ * them into view. In that case, the default animation for adding items is run
+ * on those items as well.</p>
+ *
+ * @param holder The item that is being added.
+ * @return true if a later call to {@link #runPendingAnimations()} is requested,
+ * false otherwise.
+ */
+ abstract public boolean animateAdd(ViewHolder holder);
+
+ /**
+ * Called when an item is moved in the RecyclerView. Implementors can choose
+ * whether and how to animate that change, but must always call
+ * {@link #dispatchMoveFinished(ViewHolder)} when done, either
+ * immediately (if no animation will occur) or after the animation actually finishes.
+ * The return value indicates whether an animation has been set up and whether the
+ * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+ * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+ * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+ * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+ * {@link #animateRemove(ViewHolder) animateRemove()}, and
+ * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+ * then start the animations together in the later call to {@link #runPendingAnimations()}.
+ *
+ * @param holder The item that is being moved.
+ * @return true if a later call to {@link #runPendingAnimations()} is requested,
+ * false otherwise.
+ */
+ abstract public boolean animateMove(ViewHolder holder, int fromX, int fromY,
+ int toX, int toY);
+
+ /**
+ * Called when an item is changed in the RecyclerView, as indicated by a call to
+ * {@link Adapter#notifyItemChanged(int)} or
+ * {@link Adapter#notifyItemRangeChanged(int, int)}.
+ * <p>
+ * Implementers can choose whether and how to animate changes, but must always call
+ * {@link #dispatchChangeFinished(ViewHolder, boolean)} for each non-null ViewHolder,
+ * either immediately (if no animation will occur) or after the animation actually finishes.
+ * The return value indicates whether an animation has been set up and whether the
+ * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+ * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+ * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+ * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+ * {@link #animateRemove(ViewHolder) animateRemove()}, and
+ * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+ * then start the animations together in the later call to {@link #runPendingAnimations()}.
+ *
+ * @param oldHolder The original item that changed.
+ * @param newHolder The new item that was created with the changed content. Might be null
+ * @param fromLeft Left of the old view holder
+ * @param fromTop Top of the old view holder
+ * @param toLeft Left of the new view holder
+ * @param toTop Top of the new view holder
+ * @return true if a later call to {@link #runPendingAnimations()} is requested,
+ * false otherwise.
+ */
+ abstract public boolean animateChange(ViewHolder oldHolder,
+ ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop);
+
+ /**
+ * Method to be called by subclasses when a remove animation is done.
+ *
+ * @param item The item which has been removed
+ * @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo,
+ * ItemHolderInfo)
+ */
+ public final void dispatchRemoveFinished(ViewHolder item) {
+ onRemoveFinished(item);
+ dispatchAnimationFinished(item);
+ }
+
+ /**
+ * Method to be called by subclasses when a move animation is done.
+ *
+ * @param item The item which has been moved
+ * @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo,
+ * ItemHolderInfo)
+ * @see RecyclerView.ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ * @see RecyclerView.ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+ */
+ public final void dispatchMoveFinished(ViewHolder item) {
+ onMoveFinished(item);
+ dispatchAnimationFinished(item);
+ }
+
+ /**
+ * Method to be called by subclasses when an add animation is done.
+ *
+ * @param item The item which has been added
+ */
+ public final void dispatchAddFinished(ViewHolder item) {
+ onAddFinished(item);
+ dispatchAnimationFinished(item);
+ }
+
+ /**
+ * Method to be called by subclasses when a change animation is done.
+ *
+ * @param item The item which has been changed (this method must be called for
+ * each non-null ViewHolder passed into
+ * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
+ * @param oldItem true if this is the old item that was changed, false if
+ * it is the new item that replaced the old item.
+ * @see #animateChange(ViewHolder, ViewHolder, int, int, int, int)
+ */
+ public final void dispatchChangeFinished(ViewHolder item, boolean oldItem) {
+ onChangeFinished(item, oldItem);
+ dispatchAnimationFinished(item);
+ }
+
+ /**
+ * Method to be called by subclasses when a remove animation is being started.
+ *
+ * @param item The item being removed
+ */
+ public final void dispatchRemoveStarting(ViewHolder item) {
+ onRemoveStarting(item);
+ }
+
+ /**
+ * Method to be called by subclasses when a move animation is being started.
+ *
+ * @param item The item being moved
+ */
+ public final void dispatchMoveStarting(ViewHolder item) {
+ onMoveStarting(item);
+ }
+
+ /**
+ * Method to be called by subclasses when an add animation is being started.
+ *
+ * @param item The item being added
+ */
+ public final void dispatchAddStarting(ViewHolder item) {
+ onAddStarting(item);
+ }
+
+ /**
+ * Method to be called by subclasses when a change animation is being started.
+ *
+ * @param item The item which has been changed (this method must be called for
+ * each non-null ViewHolder passed into
+ * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
+ * @param oldItem true if this is the old item that was changed, false if
+ * it is the new item that replaced the old item.
+ */
+ public final void dispatchChangeStarting(ViewHolder item, boolean oldItem) {
+ onChangeStarting(item, oldItem);
+ }
+
+ /**
+ * Called when a remove animation is being started on the given ViewHolder.
+ * The default implementation does nothing. Subclasses may wish to override
+ * this method to handle any ViewHolder-specific operations linked to animation
+ * lifecycles.
+ *
+ * @param item The ViewHolder being animated.
+ */
+ @SuppressWarnings("UnusedParameters")
+ public void onRemoveStarting(ViewHolder item) {
+ }
+
+ /**
+ * Called when a remove animation has ended on the given ViewHolder.
+ * The default implementation does nothing. Subclasses may wish to override
+ * this method to handle any ViewHolder-specific operations linked to animation
+ * lifecycles.
+ *
+ * @param item The ViewHolder being animated.
+ */
+ public void onRemoveFinished(ViewHolder item) {
+ }
+
+ /**
+ * Called when an add animation is being started on the given ViewHolder.
+ * The default implementation does nothing. Subclasses may wish to override
+ * this method to handle any ViewHolder-specific operations linked to animation
+ * lifecycles.
+ *
+ * @param item The ViewHolder being animated.
+ */
+ @SuppressWarnings("UnusedParameters")
+ public void onAddStarting(ViewHolder item) {
+ }
+
+ /**
+ * Called when an add animation has ended on the given ViewHolder.
+ * The default implementation does nothing. Subclasses may wish to override
+ * this method to handle any ViewHolder-specific operations linked to animation
+ * lifecycles.
+ *
+ * @param item The ViewHolder being animated.
+ */
+ public void onAddFinished(ViewHolder item) {
+ }
+
+ /**
+ * Called when a move animation is being started on the given ViewHolder.
+ * The default implementation does nothing. Subclasses may wish to override
+ * this method to handle any ViewHolder-specific operations linked to animation
+ * lifecycles.
+ *
+ * @param item The ViewHolder being animated.
+ */
+ @SuppressWarnings("UnusedParameters")
+ public void onMoveStarting(ViewHolder item) {
+ }
+
+ /**
+ * Called when a move animation has ended on the given ViewHolder.
+ * The default implementation does nothing. Subclasses may wish to override
+ * this method to handle any ViewHolder-specific operations linked to animation
+ * lifecycles.
+ *
+ * @param item The ViewHolder being animated.
+ */
+ public void onMoveFinished(ViewHolder item) {
+ }
+
+ /**
+ * Called when a change animation is being started on the given ViewHolder.
+ * The default implementation does nothing. Subclasses may wish to override
+ * this method to handle any ViewHolder-specific operations linked to animation
+ * lifecycles.
+ *
+ * @param item The ViewHolder being animated.
+ * @param oldItem true if this is the old item that was changed, false if
+ * it is the new item that replaced the old item.
+ */
+ @SuppressWarnings("UnusedParameters")
+ public void onChangeStarting(ViewHolder item, boolean oldItem) {
+ }
+
+ /**
+ * Called when a change animation has ended on the given ViewHolder.
+ * The default implementation does nothing. Subclasses may wish to override
+ * this method to handle any ViewHolder-specific operations linked to animation
+ * lifecycles.
+ *
+ * @param item The ViewHolder being animated.
+ * @param oldItem true if this is the old item that was changed, false if
+ * it is the new item that replaced the old item.
+ */
+ public void onChangeFinished(ViewHolder item, boolean oldItem) {
+ }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
index 322fe34..071bb4e 100644
--- a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
@@ -1040,7 +1040,7 @@
final int mode = View.MeasureSpec.getMode(spec);
if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
return View.MeasureSpec.makeMeasureSpec(
- View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
+ Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode);
}
return spec;
}
@@ -2676,7 +2676,10 @@
}
}
- static class SavedState implements Parcelable {
+ /**
+ * @hide
+ */
+ public static class SavedState implements Parcelable {
int mAnchorPosition;
int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated
diff --git a/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java b/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java
new file mode 100644
index 0000000..0af8dfb
--- /dev/null
+++ b/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.util.LongSparseArray;
+import android.support.v4.util.Pools;
+
+import static android.support.v7.widget.RecyclerView.ViewHolder;
+import static android.support.v7.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_PRE_AND_POST;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_AND_DISAPPEAR;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE_AND_POST;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
+import static android.support.v7.widget.ViewInfoStore.InfoRecord.FLAG_POST;
+/**
+ * This class abstracts all tracking for Views to run animations
+ *
+ * @hide
+ */
+class ViewInfoStore {
+
+ private static final boolean DEBUG = false;
+
+ /**
+ * View data records for pre-layout
+ */
+ @VisibleForTesting
+ final ArrayMap<ViewHolder, InfoRecord> mLayoutHolderMap = new ArrayMap<>();
+
+ @VisibleForTesting
+ final LongSparseArray<ViewHolder> mOldChangedHolders = new LongSparseArray<>();
+
+ /**
+ * Clears the state and all existing tracking data
+ */
+ void clear() {
+ mLayoutHolderMap.clear();
+ mOldChangedHolders.clear();
+ }
+
+ /**
+ * Adds the item information to the prelayout tracking
+ * @param holder The ViewHolder whose information is being saved
+ * @param info The information to save
+ */
+ void addToPreLayout(ViewHolder holder, ItemHolderInfo info) {
+ InfoRecord record = mLayoutHolderMap.get(holder);
+ if (record == null) {
+ record = InfoRecord.obtain();
+ mLayoutHolderMap.put(holder, record);
+ }
+ record.preInfo = info;
+ record.flags |= FLAG_PRE;
+ }
+
+ /**
+ * Finds the ItemHolderInfo for the given ViewHolder in preLayout list and removes it.
+ * @param vh The ViewHolder whose information is being queried
+ * @return The ItemHolderInfo for the given ViewHolder or null if it does not exist
+ */
+ @Nullable
+ ItemHolderInfo popFromPreLayout(ViewHolder vh) {
+ int index = mLayoutHolderMap.indexOfKey(vh);
+ if (index < 0) {
+ return null;
+ }
+ final InfoRecord record = mLayoutHolderMap.valueAt(index);
+ if (record != null && (record.flags & FLAG_PRE) != 0) {
+ record.flags &= ~FLAG_PRE;
+ final ItemHolderInfo info = record.preInfo;
+ if (record.flags == 0) {
+ mLayoutHolderMap.removeAt(index);
+ InfoRecord.recycle(record);
+ }
+ return info;
+ }
+ return null;
+ }
+
+ /**
+ * Adds the given ViewHolder to the oldChangeHolders list
+ * @param key The key to identify the ViewHolder.
+ * @param holder The ViewHolder to store
+ */
+ void addToOldChangeHolders(long key, ViewHolder holder) {
+ mOldChangedHolders.put(key, holder);
+ }
+
+ /**
+ * Adds the given ViewHolder to the appeared in pre layout list. These are Views added by the
+ * LayoutManager during a pre-layout pass. We distinguish them from other views that were
+ * already in the pre-layout so that ItemAnimator can choose to run a different animation for
+ * them.
+ *
+ * @param holder The ViewHolder to store
+ * @param info The information to save
+ */
+ void addToAppearedInPreLayoutHolders(ViewHolder holder, ItemHolderInfo info) {
+ InfoRecord record = mLayoutHolderMap.get(holder);
+ if (record == null) {
+ record = InfoRecord.obtain();
+ mLayoutHolderMap.put(holder, record);
+ }
+ record.flags |= FLAG_APPEAR;
+ record.preInfo = info;
+ }
+
+ /**
+ * Checks whether the given ViewHolder is in preLayout list
+ * @param viewHolder The ViewHolder to query
+ *
+ * @return True if the ViewHolder is present in preLayout, false otherwise
+ */
+ boolean isInPreLayout(ViewHolder viewHolder) {
+ final InfoRecord record = mLayoutHolderMap.get(viewHolder);
+ return record != null && (record.flags & FLAG_PRE) != 0;
+ }
+
+ /**
+ * Queries the oldChangeHolder list for the given key. If they are not tracked, simply returns
+ * null.
+ * @param key The key to be used to find the ViewHolder.
+ *
+ * @return A ViewHolder if exists or null if it does not exist.
+ */
+ ViewHolder getFromOldChangeHolders(long key) {
+ return mOldChangedHolders.get(key);
+ }
+
+ /**
+ * Adds the item information to the post layout list
+ * @param holder The ViewHolder whose information is being saved
+ * @param info The information to save
+ */
+ void addToPostLayout(ViewHolder holder, ItemHolderInfo info) {
+ InfoRecord record = mLayoutHolderMap.get(holder);
+ if (record == null) {
+ record = InfoRecord.obtain();
+ mLayoutHolderMap.put(holder, record);
+ }
+ record.postInfo = info;
+ record.flags |= FLAG_POST;
+ }
+
+ /**
+ * A ViewHolder might be added by the LayoutManager just to animate its disappearance.
+ * This list holds such items so that we can animate / recycle these ViewHolders properly.
+ *
+ * @param holder The ViewHolder which disappeared during a layout.
+ */
+ void addToDisappearedInLayout(ViewHolder holder) {
+ InfoRecord record = mLayoutHolderMap.get(holder);
+ if (record == null) {
+ record = InfoRecord.obtain();
+ mLayoutHolderMap.put(holder, record);
+ }
+ record.flags |= FLAG_DISAPPEARED;
+ }
+
+ /**
+ * Removes a ViewHolder from disappearing list.
+ * @param holder The ViewHolder to be removed from the disappearing list.
+ */
+ void removeFromDisappearedInLayout(ViewHolder holder) {
+ InfoRecord record = mLayoutHolderMap.get(holder);
+ if (record == null) {
+ return;
+ }
+ record.flags &= ~FLAG_DISAPPEARED;
+ }
+
+ void process(ProcessCallback callback) {
+ for (int index = mLayoutHolderMap.size() - 1; index >= 0; index --) {
+ final ViewHolder viewHolder = mLayoutHolderMap.keyAt(index);
+ final InfoRecord record = mLayoutHolderMap.removeAt(index);
+ if ((record.flags & FLAG_APPEAR_AND_DISAPPEAR) == FLAG_APPEAR_AND_DISAPPEAR) {
+ // Appeared then disappeared. Not useful for animations.
+ callback.unused(viewHolder);
+ } else if ((record.flags & FLAG_DISAPPEARED) != 0) {
+ // Set as "disappeared" by the LayoutManager (addDisappearingView)
+ callback.processDisappeared(viewHolder, record.preInfo, record.postInfo);
+ } else if ((record.flags & FLAG_APPEAR_PRE_AND_POST) == FLAG_APPEAR_PRE_AND_POST) {
+ // Appeared in the layout but not in the adapter (e.g. entered the viewport)
+ callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
+ } else if ((record.flags & FLAG_PRE_AND_POST) == FLAG_PRE_AND_POST) {
+ // Persistent in both passes. Animate persistence
+ callback.processPersistent(viewHolder, record.preInfo, record.postInfo);
+ } else if ((record.flags & FLAG_PRE) != 0) {
+ // Was in pre-layout, never been added to post layout
+ callback.processDisappeared(viewHolder, record.preInfo, null);
+ } else if ((record.flags & FLAG_POST) != 0) {
+ // Was not in pre-layout, been added to post layout
+ callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
+ } else if ((record.flags & FLAG_APPEAR) != 0) {
+ // Scrap view. RecyclerView will handle removing/recycling this.
+ } else if (DEBUG) {
+ throw new IllegalStateException("record without any reasonable flag combination:/");
+ }
+ InfoRecord.recycle(record);
+ }
+ }
+
+ /**
+ * Removes the ViewHolder from all list
+ * @param holder The ViewHolder which we should stop tracking
+ */
+ void removeViewHolder(ViewHolder holder) {
+ for (int i = mOldChangedHolders.size() - 1; i >= 0; i--) {
+ if (holder == mOldChangedHolders.valueAt(i)) {
+ mOldChangedHolders.removeAt(i);
+ break;
+ }
+ }
+ final InfoRecord info = mLayoutHolderMap.remove(holder);
+ if (info != null) {
+ InfoRecord.recycle(info);
+ }
+ }
+
+ void onDetach() {
+ InfoRecord.drainCache();
+ }
+
+ interface ProcessCallback {
+ void processDisappeared(ViewHolder viewHolder, ItemHolderInfo preInfo,
+ @Nullable ItemHolderInfo postInfo);
+ void processAppeared(ViewHolder viewHolder, @Nullable ItemHolderInfo preInfo,
+ ItemHolderInfo postInfo);
+ void processPersistent(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo,
+ @NonNull ItemHolderInfo postInfo);
+ void unused(ViewHolder holder);
+ }
+
+ static class InfoRecord {
+ // disappearing list
+ static final int FLAG_DISAPPEARED = 1;
+ // appear in pre layout list
+ static final int FLAG_APPEAR = 1 << 1;
+ // pre layout, this is necessary to distinguish null item info
+ static final int FLAG_PRE = 1 << 2;
+ // post layout, this is necessary to distinguish null item info
+ static final int FLAG_POST = 1 << 3;
+ static final int FLAG_APPEAR_AND_DISAPPEAR = FLAG_APPEAR | FLAG_DISAPPEARED;
+ static final int FLAG_PRE_AND_POST = FLAG_PRE | FLAG_POST;
+ static final int FLAG_APPEAR_PRE_AND_POST = FLAG_APPEAR | FLAG_PRE | FLAG_POST;
+ int flags;
+ @Nullable ItemHolderInfo preInfo;
+ @Nullable ItemHolderInfo postInfo;
+ static Pools.Pool<InfoRecord> sPool = new Pools.SimplePool<>(20);
+
+ private InfoRecord() {
+ }
+
+ static InfoRecord obtain() {
+ InfoRecord record = sPool.acquire();
+ return record == null ? new InfoRecord() : record;
+ }
+
+ static void recycle(InfoRecord record) {
+ record.flags = 0;
+ record.preInfo = null;
+ record.postInfo = null;
+ sPool.release(record);
+ }
+
+ static void drainCache() {
+ //noinspection StatementWithEmptyBody
+ while (sPool.acquire() != null);
+ }
+ }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
index 0c22d1c..72d3e8c 100644
--- a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
@@ -873,7 +873,6 @@
anim.cancel();
}
mRecoverAnimations.remove(i);
- anim.mViewHolder.setIsRecyclable(true);
return anim.mAnimationType;
}
}
@@ -1902,7 +1901,6 @@
final RecoverAnimation anim = recoverAnimationList.get(i);
if (anim.mEnded && !anim.mIsPendingCleanup) {
recoverAnimationList.remove(i);
- anim.mViewHolder.setIsRecyclable(true);
} else if (!anim.mEnded) {
hasRunningAnimation = true;
}
@@ -2314,6 +2312,9 @@
@Override
public void onAnimationEnd(ValueAnimatorCompat animation) {
+ if (!mEnded) {
+ mViewHolder.setIsRecyclable(true);
+ }
mEnded = true;
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java b/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
index e9147a0..f985898 100644
--- a/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
@@ -16,22 +16,13 @@
package android.support.v7.util;
-import android.support.test.runner.AndroidJUnit4;
+import android.support.annotation.UiThread;
import android.util.SparseBooleanArray;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
-@RunWith(AndroidJUnit4.class)
-public class AsyncListUtilTest {
+public class AsyncListUtilTest extends BaseThreadedTest {
private static final int TILE_SIZE = 10;
@@ -40,34 +31,37 @@
AsyncListUtil<String> mAsyncListUtil;
-
- @Before
+ @Override
public void setUp() throws Exception {
mDataCallback = new TestDataCallback();
mViewCallback = new TestViewCallback();
mDataCallback.expectTiles(0, 10, 20);
- mAsyncListUtil = new AsyncListUtil<String>(String.class, TILE_SIZE, mDataCallback,
- mViewCallback);
+ super.setUp();
mDataCallback.waitForTiles("initial load");
}
- @After
+ @Override
+ @UiThread
+ protected void setUpUi() {
+ mAsyncListUtil = new AsyncListUtil<String>(
+ String.class, TILE_SIZE, mDataCallback, mViewCallback);
+ }
+
+ @Override
public void tearDown() throws Exception {
/// Wait a little extra to catch spurious messages.
new CountDownLatch(1).await(500, TimeUnit.MILLISECONDS);
}
- @Test
- public void testWithNoPreload() throws InterruptedException {
+ public void testWithNoPreload() throws Throwable {
scrollAndExpectTiles(10, "scroll to 10", 30);
scrollAndExpectTiles(25, "scroll to 25", 40);
scrollAndExpectTiles(45, "scroll to 45", 50, 60);
scrollAndExpectTiles(70, "scroll to 70", 70, 80, 90);
}
- @Test
- public void testWithPreload() throws InterruptedException {
+ public void testWithPreload() throws Throwable {
mViewCallback.mStartPreload = 5;
mViewCallback.mEndPreload = 15;
scrollAndExpectTiles(50, "scroll down a lot", 40, 50, 60, 70, 80);
@@ -78,8 +72,7 @@
scrollAndExpectTiles(40, "scroll up a little, no new tiles loaded");
}
- @Test
- public void testTileCaching() throws InterruptedException {
+ public void testTileCaching() throws Throwable {
scrollAndExpectTiles(25, "next screen", 30, 40);
scrollAndExpectTiles(0, "back at top, no new page loads");
@@ -90,35 +83,34 @@
scrollAndExpectTiles(0, "scroll back to top, all pages should reload", 0, 10, 20);
}
- @Test
- public void testDataRefresh() throws InterruptedException {
+ public void testDataRefresh() throws Throwable {
mViewCallback.expectDataSetChanged(40);
mDataCallback.expectTiles(0, 10, 20);
- mAsyncListUtil.refresh();
+ refreshOnUiThread();
mViewCallback.waitForDataSetChanged("increasing item count");
mDataCallback.waitForTiles("increasing item count");
mViewCallback.expectDataSetChanged(15);
mDataCallback.expectTiles(0, 10);
- mAsyncListUtil.refresh();
+ refreshOnUiThread();
mViewCallback.waitForDataSetChanged("decreasing item count");
mDataCallback.waitForTiles("decreasing item count");
}
- @Test
- public void testItemChanged() throws InterruptedException {
+ public void testItemChanged() throws Throwable {
final int position = 30;
final int count = 20;
- assertEquals("no new items should be loaded", 0, getLoadedItemCount(position, count));
+ assertLoadedItemsOnUiThread("no new items should be loaded", 0, position, count);
mViewCallback.expectItemRangeChanged(position, count);
scrollAndExpectTiles(20, "scrolling to missing items", 30, 40);
mViewCallback.waitForItems();
- assertEquals("all new items should be loaded", count, getLoadedItemCount(position, count));
+ assertLoadedItemsOnUiThread("all new items should be loaded", count, position, count);
}
+ @UiThread
private int getLoadedItemCount(int startPosition, int itemCount) {
int loaded = 0;
for (int i = 0; i < itemCount; i++) {
@@ -130,9 +122,9 @@
}
private void scrollAndExpectTiles(int position, String context, int... positions)
- throws InterruptedException {
+ throws Throwable {
mDataCallback.expectTiles(positions);
- mViewCallback.scrollTo(position);
+ scrollOnUiThread(position);
mDataCallback.waitForTiles(context);
}
@@ -141,6 +133,36 @@
assertTrue("timed out waiting for " + context, latch.await(1, TimeUnit.SECONDS));
}
+ private void refreshOnUiThread() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mAsyncListUtil.refresh();
+ }
+ });
+ }
+
+ private void assertLoadedItemsOnUiThread(final String message,
+ final int expectedCount,
+ final int position,
+ final int count) throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertEquals(message, expectedCount, getLoadedItemCount(position, count));
+ }
+ });
+ }
+
+ private void scrollOnUiThread(final int position) throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mViewCallback.scrollTo(position);
+ }
+ });
+ }
+
private class TestDataCallback extends AsyncListUtil.DataCallback<String> {
private int mCacheSize = 10;
@@ -205,6 +227,7 @@
}
@Override
+ @UiThread
public void onDataRefresh() {
if (mDataRefreshLatch == null) {
return;
@@ -239,12 +262,14 @@
waitForLatch("onItemChanged", mItemsChangedLatch.mLatch);
}
+ @UiThread
public void scrollTo(int position) {
mLastVisibleItem += position - mFirstVisibleItem;
mFirstVisibleItem = position;
mAsyncListUtil.onRangeChanged();
}
+ @UiThread
private void updateViewport() {
int itemCount = mAsyncListUtil.getItemCount();
if (mLastVisibleItem < itemCount) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/BaseThreadedTest.java b/v7/recyclerview/tests/src/android/support/v7/util/BaseThreadedTest.java
new file mode 100644
index 0000000..73df9a7
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/util/BaseThreadedTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.util;
+
+import android.support.annotation.UiThread;
+import android.support.v7.widget.TestActivity;
+import android.test.ActivityInstrumentationTestCase2;
+
+abstract public class BaseThreadedTest extends ActivityInstrumentationTestCase2<TestActivity> {
+ public BaseThreadedTest() {
+ super(TestActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception{
+ try {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ setUpUi();
+ }
+ });
+ } catch (Throwable throwable) {
+ fail(throwable.getMessage());
+ }
+ }
+
+ @UiThread
+ protected abstract void setUpUi();
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java b/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java
index daa2ffc..472374d 100644
--- a/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java
@@ -19,27 +19,23 @@
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.CoreMatchers.*;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import android.os.Looper;
-import android.support.test.runner.AndroidJUnit4;
+import android.support.annotation.UiThread;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-@RunWith(AndroidJUnit4.class)
-public class ThreadUtilTest {
+public class ThreadUtilTest extends BaseThreadedTest {
Map<String, LockedObject> results = new HashMap<>();
ThreadUtil.MainThreadCallback<Integer> mMainThreadProxy;
ThreadUtil.BackgroundCallback<Integer> mBackgroundProxy;
- @Before
- public void setup() {
+ @Override
+ @UiThread
+ public void setUpUi() {
ThreadUtil<Integer> threadUtil = new MessageThreadUtil<>();
mMainThreadProxy = threadUtil.getMainThreadProxy(
@@ -93,15 +89,15 @@
});
}
- @Test
public void testUpdateItemCount() throws InterruptedException {
initWait("updateItemCount");
+ // In this test and below the calls to mMainThreadProxy are not really made from the UI
+ // thread. That's OK since the message queue inside mMainThreadProxy is synchronized.
mMainThreadProxy.updateItemCount(7, 9);
Object[] data = waitFor("updateItemCount");
assertThat(data, is(new Object[]{7, 9}));
}
- @Test
public void testAddTile() throws InterruptedException {
initWait("addTile");
TileList.Tile<Integer> tile = new TileList.Tile<Integer>(Integer.class, 10);
@@ -110,7 +106,6 @@
assertThat(data, is(new Object[]{3, tile}));
}
- @Test
public void testRemoveTile() throws InterruptedException {
initWait("removeTile");
mMainThreadProxy.removeTile(1, 2);
@@ -118,15 +113,15 @@
assertThat(data, is(new Object[]{1, 2}));
}
- @Test
public void testRefresh() throws InterruptedException {
initWait("refresh");
+ // In this test and below the calls to mBackgroundProxy are not really made from the worker
+ // thread. That's OK since the message queue inside mBackgroundProxy is synchronized.
mBackgroundProxy.refresh(2);
Object[] data = waitFor("refresh");
assertThat(data, is(new Object[]{2}));
}
- @Test
public void testRangeUpdate() throws InterruptedException {
initWait("updateRange");
mBackgroundProxy.updateRange(10, 20, 5, 25, 1);
@@ -134,7 +129,6 @@
assertThat(data, is(new Object[] {10, 20, 5, 25, 1}));
}
- @Test
public void testLoadTile() throws InterruptedException {
initWait("loadTile");
mBackgroundProxy.loadTile(2, 1);
@@ -142,7 +136,6 @@
assertThat(data, is(new Object[]{2, 1}));
}
- @Test
public void testRecycleTile() throws InterruptedException {
initWait("recycleTile");
TileList.Tile<Integer> tile = new TileList.Tile<Integer>(Integer.class, 10);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
index 3889cfa..b8f6788 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
@@ -76,8 +76,13 @@
mDataCallback.expectTilesInRange(rangeStart, rangeSize);
mAdapter.expectItemsInRange(rangeStart, rangeSize);
- mAsyncListUtil = new AsyncListUtil<String>(String.class, TILE_SIZE, mDataCallback,
- mViewCallback);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mAsyncListUtil = new AsyncListUtil<String>(
+ String.class, TILE_SIZE, mDataCallback, mViewCallback);
+ }
+ });
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java
new file mode 100644
index 0000000..4764c00
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java
@@ -0,0 +1,729 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base class for animation related tests.
+ */
+public class BaseRecyclerViewAnimationsTest extends BaseRecyclerViewInstrumentationTest {
+
+ protected static final boolean DEBUG = false;
+
+ protected static final String TAG = "RecyclerViewAnimationsTest";
+
+ AnimationLayoutManager mLayoutManager;
+
+ TestAdapter mTestAdapter;
+
+ public BaseRecyclerViewAnimationsTest() {
+ super(DEBUG);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ RecyclerView setupBasic(int itemCount) throws Throwable {
+ return setupBasic(itemCount, 0, itemCount);
+ }
+
+ RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount)
+ throws Throwable {
+ return setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null);
+ }
+
+ RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount,
+ TestAdapter testAdapter)
+ throws Throwable {
+ final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
+ recyclerView.setHasFixedSize(true);
+ if (testAdapter == null) {
+ mTestAdapter = new TestAdapter(itemCount);
+ } else {
+ mTestAdapter = testAdapter;
+ }
+ recyclerView.setAdapter(mTestAdapter);
+ recyclerView.setItemAnimator(createItemAnimator());
+ mLayoutManager = new AnimationLayoutManager();
+ recyclerView.setLayoutManager(mLayoutManager);
+ mLayoutManager.mOnLayoutCallbacks.mLayoutMin = firstLayoutStartIndex;
+ mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = firstLayoutItemCount;
+
+ mLayoutManager.expectLayouts(1);
+ recyclerView.expectDraw(1);
+ setRecyclerView(recyclerView);
+ mLayoutManager.waitForLayout(2);
+ recyclerView.waitForDraw(1);
+ mLayoutManager.mOnLayoutCallbacks.reset();
+ getInstrumentation().waitForIdleSync();
+ checkForMainThreadException();
+ assertEquals("extra layouts should not happen", 1, mLayoutManager.getTotalLayoutCount());
+ assertEquals("all expected children should be laid out", firstLayoutItemCount,
+ mLayoutManager.getChildCount());
+ return recyclerView;
+ }
+
+ protected RecyclerView.ItemAnimator createItemAnimator() {
+ return new DefaultItemAnimator();
+ }
+
+ public TestRecyclerView getTestRecyclerView() {
+ return (TestRecyclerView) mRecyclerView;
+ }
+
+ class AnimationLayoutManager extends TestLayoutManager {
+
+ protected int mTotalLayoutCount = 0;
+ private String log;
+
+ OnLayoutCallbacks mOnLayoutCallbacks = new OnLayoutCallbacks() {
+ };
+
+
+
+ @Override
+ public boolean supportsPredictiveItemAnimations() {
+ return true;
+ }
+
+ public String getLog() {
+ return log;
+ }
+
+ private String prepareLog(RecyclerView.Recycler recycler, RecyclerView.State state, boolean done) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("is pre layout:").append(state.isPreLayout()).append(", done:").append(done);
+ builder.append("\nViewHolders:\n");
+ for (RecyclerView.ViewHolder vh : ((TestRecyclerView)mRecyclerView).collectViewHolders()) {
+ builder.append(vh).append("\n");
+ }
+ builder.append("scrap:\n");
+ for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
+ builder.append(vh).append("\n");
+ }
+
+ if (state.isPreLayout() && !done) {
+ log = "\n" + builder.toString();
+ } else {
+ log += "\n" + builder.toString();
+ }
+ return log;
+ }
+
+ @Override
+ public void expectLayouts(int count) {
+ super.expectLayouts(count);
+ mOnLayoutCallbacks.mLayoutCount = 0;
+ }
+
+ public void setOnLayoutCallbacks(OnLayoutCallbacks onLayoutCallbacks) {
+ mOnLayoutCallbacks = onLayoutCallbacks;
+ }
+
+ @Override
+ public final void onLayoutChildren(RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ try {
+ mTotalLayoutCount++;
+ prepareLog(recycler, state, false);
+ if (state.isPreLayout()) {
+ validateOldPositions(recycler, state);
+ } else {
+ validateClearedOldPositions(recycler, state);
+ }
+ mOnLayoutCallbacks.onLayoutChildren(recycler, this, state);
+ prepareLog(recycler, state, true);
+ } finally {
+ layoutLatch.countDown();
+ }
+ }
+
+ private void validateClearedOldPositions(RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ if (getTestRecyclerView() == null) {
+ return;
+ }
+ for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
+ assertEquals("there should NOT be an old position in post layout",
+ RecyclerView.NO_POSITION, viewHolder.mOldPosition);
+ assertEquals("there should NOT be a pre layout position in post layout",
+ RecyclerView.NO_POSITION, viewHolder.mPreLayoutPosition);
+ }
+ }
+
+ private void validateOldPositions(RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ if (getTestRecyclerView() == null) {
+ return;
+ }
+ for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
+ if (!viewHolder.isRemoved() && !viewHolder.isInvalid()) {
+ assertTrue("there should be an old position in pre-layout",
+ viewHolder.mOldPosition != RecyclerView.NO_POSITION);
+ }
+ }
+ }
+
+ public int getTotalLayoutCount() {
+ return mTotalLayoutCount;
+ }
+
+ @Override
+ public boolean canScrollVertically() {
+ return true;
+ }
+
+ @Override
+ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ mOnLayoutCallbacks.onScroll(dy, recycler, state);
+ return super.scrollVerticallyBy(dy, recycler, state);
+ }
+
+ public void onPostDispatchLayout() {
+ mOnLayoutCallbacks.postDispatchLayout();
+ }
+
+ @Override
+ public void waitForLayout(long timeout, TimeUnit timeUnit) throws Throwable {
+ super.waitForLayout(timeout, timeUnit);
+ checkForMainThreadException();
+ }
+ }
+
+ abstract class OnLayoutCallbacks {
+
+ int mLayoutMin = Integer.MIN_VALUE;
+
+ int mLayoutItemCount = Integer.MAX_VALUE;
+
+ int expectedPreLayoutItemCount = -1;
+
+ int expectedPostLayoutItemCount = -1;
+
+ int mDeletedViewCount;
+
+ int mLayoutCount = 0;
+
+ void setExpectedItemCounts(int preLayout, int postLayout) {
+ expectedPreLayoutItemCount = preLayout;
+ expectedPostLayoutItemCount = postLayout;
+ }
+
+ void reset() {
+ mLayoutMin = Integer.MIN_VALUE;
+ mLayoutItemCount = Integer.MAX_VALUE;
+ expectedPreLayoutItemCount = -1;
+ expectedPostLayoutItemCount = -1;
+ mLayoutCount = 0;
+ }
+
+ void beforePreLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager lm, RecyclerView.State state) {
+ mDeletedViewCount = 0;
+ for (int i = 0; i < lm.getChildCount(); i++) {
+ View v = lm.getChildAt(i);
+ if (lm.getLp(v).isItemRemoved()) {
+ mDeletedViewCount++;
+ }
+ }
+ }
+
+ void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
+ RecyclerView.State state) {
+ if (DEBUG) {
+ Log.d(TAG, "item count " + state.getItemCount());
+ }
+ lm.detachAndScrapAttachedViews(recycler);
+ final int start = mLayoutMin == Integer.MIN_VALUE ? 0 : mLayoutMin;
+ final int count = mLayoutItemCount
+ == Integer.MAX_VALUE ? state.getItemCount() : mLayoutItemCount;
+ lm.layoutRange(recycler, start, start + count);
+ assertEquals("correct # of children should be laid out",
+ count, lm.getChildCount());
+ lm.assertVisibleItemPositions();
+ }
+
+ private void assertNoPreLayoutPosition(RecyclerView.Recycler recycler) {
+ for (RecyclerView.ViewHolder vh : recycler.mAttachedScrap) {
+ assertPreLayoutPosition(vh);
+ }
+ }
+
+ private void assertNoPreLayoutPosition(RecyclerView.LayoutManager lm) {
+ for (int i = 0; i < lm.getChildCount(); i ++) {
+ final RecyclerView.ViewHolder vh = mRecyclerView
+ .getChildViewHolder(lm.getChildAt(i));
+ assertPreLayoutPosition(vh);
+ }
+ }
+
+ private void assertPreLayoutPosition(RecyclerView.ViewHolder vh) {
+ assertEquals("in post layout, there should not be a view holder w/ a pre "
+ + "layout position", RecyclerView.NO_POSITION, vh.mPreLayoutPosition);
+ assertEquals("in post layout, there should not be a view holder w/ an old "
+ + "layout position", RecyclerView.NO_POSITION, vh.mOldPosition);
+ }
+
+ void onLayoutChildren(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
+ RecyclerView.State state) {
+ if (state.isPreLayout()) {
+ if (expectedPreLayoutItemCount != -1) {
+ assertEquals("on pre layout, state should return abstracted adapter size",
+ expectedPreLayoutItemCount, state.getItemCount());
+ }
+ beforePreLayout(recycler, lm, state);
+ } else {
+ if (expectedPostLayoutItemCount != -1) {
+ assertEquals("on post layout, state should return real adapter size",
+ expectedPostLayoutItemCount, state.getItemCount());
+ }
+ beforePostLayout(recycler, lm, state);
+ }
+ if (!state.isPreLayout()) {
+ assertNoPreLayoutPosition(recycler);
+ }
+ doLayout(recycler, lm, state);
+ if (state.isPreLayout()) {
+ afterPreLayout(recycler, lm, state);
+ } else {
+ afterPostLayout(recycler, lm, state);
+ assertNoPreLayoutPosition(lm);
+ }
+ mLayoutCount++;
+ }
+
+ void afterPreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
+ RecyclerView.State state) {
+ }
+
+ void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
+ RecyclerView.State state) {
+ }
+
+ void afterPostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
+ RecyclerView.State state) {
+ }
+
+ void postDispatchLayout() {
+ }
+
+ public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
+
+ }
+ }
+
+ class TestRecyclerView extends RecyclerView {
+
+ CountDownLatch drawLatch;
+
+ public TestRecyclerView(Context context) {
+ super(context);
+ }
+
+ public TestRecyclerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public TestRecyclerView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ void initAdapterManager() {
+ super.initAdapterManager();
+ mAdapterHelper.mOnItemProcessedCallback = new Runnable() {
+ @Override
+ public void run() {
+ validatePostUpdateOp();
+ }
+ };
+ }
+
+ @Override
+ boolean isAccessibilityEnabled() {
+ return true;
+ }
+
+ public void expectDraw(int count) {
+ drawLatch = new CountDownLatch(count);
+ }
+
+ public void waitForDraw(long timeout) throws Throwable {
+ drawLatch.await(timeout * (DEBUG ? 100 : 1), TimeUnit.SECONDS);
+ assertEquals("all expected draws should happen at the expected time frame",
+ 0, drawLatch.getCount());
+ }
+
+ List<ViewHolder> collectViewHolders() {
+ List<ViewHolder> holders = new ArrayList<ViewHolder>();
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ ViewHolder holder = getChildViewHolderInt(getChildAt(i));
+ if (holder != null) {
+ holders.add(holder);
+ }
+ }
+ return holders;
+ }
+
+
+ private void validateViewHolderPositions() {
+ final Set<Integer> existingOffsets = new HashSet<Integer>();
+ int childCount = getChildCount();
+ StringBuilder log = new StringBuilder();
+ for (int i = 0; i < childCount; i++) {
+ ViewHolder vh = getChildViewHolderInt(getChildAt(i));
+ TestViewHolder tvh = (TestViewHolder) vh;
+ log.append(tvh.mBoundItem).append(vh)
+ .append(" hidden:")
+ .append(mChildHelper.mHiddenViews.contains(vh.itemView))
+ .append("\n");
+ }
+ for (int i = 0; i < childCount; i++) {
+ ViewHolder vh = getChildViewHolderInt(getChildAt(i));
+ if (vh.isInvalid()) {
+ continue;
+ }
+ if (vh.getLayoutPosition() < 0) {
+ LayoutManager lm = getLayoutManager();
+ for (int j = 0; j < lm.getChildCount(); j ++) {
+ assertNotSame("removed view holder should not be in LM's child list",
+ vh.itemView, lm.getChildAt(j));
+ }
+ } else if (!mChildHelper.mHiddenViews.contains(vh.itemView)) {
+ if (!existingOffsets.add(vh.getLayoutPosition())) {
+ throw new IllegalStateException("view holder position conflict for "
+ + "existing views " + vh + "\n" + log);
+ }
+ }
+ }
+ }
+
+ void validatePostUpdateOp() {
+ try {
+ validateViewHolderPositions();
+ if (super.mState.isPreLayout()) {
+ validatePreLayoutSequence((AnimationLayoutManager) getLayoutManager());
+ }
+ validateAdapterPosition((AnimationLayoutManager) getLayoutManager());
+ } catch (Throwable t) {
+ postExceptionToInstrumentation(t);
+ }
+ }
+
+
+
+ private void validateAdapterPosition(AnimationLayoutManager lm) {
+ for (ViewHolder vh : collectViewHolders()) {
+ if (!vh.isRemoved() && vh.mPreLayoutPosition >= 0) {
+ assertEquals("adapter position calculations should match view holder "
+ + "pre layout:" + mState.isPreLayout()
+ + " positions\n" + vh + "\n" + lm.getLog(),
+ mAdapterHelper.findPositionOffset(vh.mPreLayoutPosition), vh.mPosition);
+ }
+ }
+ }
+
+ // ensures pre layout positions are continuous block. This is not necessarily a case
+ // but valid in test RV
+ private void validatePreLayoutSequence(AnimationLayoutManager lm) {
+ Set<Integer> preLayoutPositions = new HashSet<Integer>();
+ for (ViewHolder vh : collectViewHolders()) {
+ assertTrue("pre layout positions should be distinct " + lm.getLog(),
+ preLayoutPositions.add(vh.mPreLayoutPosition));
+ }
+ int minPos = Integer.MAX_VALUE;
+ for (Integer pos : preLayoutPositions) {
+ if (pos < minPos) {
+ minPos = pos;
+ }
+ }
+ for (int i = 1; i < preLayoutPositions.size(); i++) {
+ assertNotNull("next position should exist " + lm.getLog(),
+ preLayoutPositions.contains(minPos + i));
+ }
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ if (drawLatch != null) {
+ drawLatch.countDown();
+ }
+ }
+
+ @Override
+ void dispatchLayout() {
+ try {
+ super.dispatchLayout();
+ if (getLayoutManager() instanceof AnimationLayoutManager) {
+ ((AnimationLayoutManager) getLayoutManager()).onPostDispatchLayout();
+ }
+ } catch (Throwable t) {
+ postExceptionToInstrumentation(t);
+ }
+
+ }
+
+
+ }
+
+ abstract class AdapterOps {
+
+ final public void run(TestAdapter adapter) throws Throwable {
+ onRun(adapter);
+ }
+
+ abstract void onRun(TestAdapter testAdapter) throws Throwable;
+ }
+
+ static class CollectPositionResult {
+
+ // true if found in scrap
+ public RecyclerView.ViewHolder scrapResult;
+
+ public RecyclerView.ViewHolder adapterResult;
+
+ static CollectPositionResult fromScrap(RecyclerView.ViewHolder viewHolder) {
+ CollectPositionResult cpr = new CollectPositionResult();
+ cpr.scrapResult = viewHolder;
+ return cpr;
+ }
+
+ static CollectPositionResult fromAdapter(RecyclerView.ViewHolder viewHolder) {
+ CollectPositionResult cpr = new CollectPositionResult();
+ cpr.adapterResult = viewHolder;
+ return cpr;
+ }
+
+ @Override
+ public String toString() {
+ return "CollectPositionResult{" +
+ "scrapResult=" + scrapResult +
+ ", adapterResult=" + adapterResult +
+ '}';
+ }
+ }
+
+ static class PositionConstraint {
+
+ public static enum Type {
+ scrap,
+ adapter,
+ adapterScrap /*first pass adapter, second pass scrap*/
+ }
+
+ Type mType;
+
+ int mOldPos; // if VH
+
+ int mPreLayoutPos;
+
+ int mPostLayoutPos;
+
+ int mValidateCount = 0;
+
+ public static PositionConstraint scrap(int oldPos, int preLayoutPos, int postLayoutPos) {
+ PositionConstraint constraint = new PositionConstraint();
+ constraint.mType = Type.scrap;
+ constraint.mOldPos = oldPos;
+ constraint.mPreLayoutPos = preLayoutPos;
+ constraint.mPostLayoutPos = postLayoutPos;
+ return constraint;
+ }
+
+ public static PositionConstraint adapterScrap(int preLayoutPos, int position) {
+ PositionConstraint constraint = new PositionConstraint();
+ constraint.mType = Type.adapterScrap;
+ constraint.mOldPos = RecyclerView.NO_POSITION;
+ constraint.mPreLayoutPos = preLayoutPos;
+ constraint.mPostLayoutPos = position;// adapter pos does not change
+ return constraint;
+ }
+
+ public static PositionConstraint adapter(int position) {
+ PositionConstraint constraint = new PositionConstraint();
+ constraint.mType = Type.adapter;
+ constraint.mPreLayoutPos = RecyclerView.NO_POSITION;
+ constraint.mOldPos = RecyclerView.NO_POSITION;
+ constraint.mPostLayoutPos = position;// adapter pos does not change
+ return constraint;
+ }
+
+ public void assertValidate() {
+ int expectedValidate = 0;
+ if (mPreLayoutPos >= 0) {
+ expectedValidate ++;
+ }
+ if (mPostLayoutPos >= 0) {
+ expectedValidate ++;
+ }
+ assertEquals("should run all validates", expectedValidate, mValidateCount);
+ }
+
+ @Override
+ public String toString() {
+ return "Cons{" +
+ "t=" + mType.name() +
+ ", old=" + mOldPos +
+ ", pre=" + mPreLayoutPos +
+ ", post=" + mPostLayoutPos +
+ '}';
+ }
+
+ public void validate(RecyclerView.State state, CollectPositionResult result, String log) {
+ mValidateCount ++;
+ assertNotNull(this + ": result should not be null\n" + log, result);
+ RecyclerView.ViewHolder viewHolder;
+ if (mType == Type.scrap || (mType == Type.adapterScrap && !state.isPreLayout())) {
+ assertNotNull(this + ": result should come from scrap\n" + log, result.scrapResult);
+ viewHolder = result.scrapResult;
+ } else {
+ assertNotNull(this + ": result should come from adapter\n" + log,
+ result.adapterResult);
+ assertEquals(this + ": old position should be none when it came from adapter\n" + log,
+ RecyclerView.NO_POSITION, result.adapterResult.getOldPosition());
+ viewHolder = result.adapterResult;
+ }
+ if (state.isPreLayout()) {
+ assertEquals(this + ": pre-layout position should match\n" + log, mPreLayoutPos,
+ viewHolder.mPreLayoutPosition == -1 ? viewHolder.mPosition :
+ viewHolder.mPreLayoutPosition);
+ assertEquals(this + ": pre-layout getPosition should match\n" + log, mPreLayoutPos,
+ viewHolder.getLayoutPosition());
+ if (mType == Type.scrap) {
+ assertEquals(this + ": old position should match\n" + log, mOldPos,
+ result.scrapResult.getOldPosition());
+ }
+ } else if (mType == Type.adapter || mType == Type.adapterScrap || !result.scrapResult
+ .isRemoved()) {
+ assertEquals(this + ": post-layout position should match\n" + log + "\n\n"
+ + viewHolder, mPostLayoutPos, viewHolder.getLayoutPosition());
+ }
+ }
+ }
+
+ static class LoggingInfo extends RecyclerView.ItemAnimator.ItemHolderInfo {
+ final RecyclerView.ViewHolder viewHolder;
+ @RecyclerView.ItemAnimator.AdapterChanges
+ final int changeFlags;
+ final List<Object> payloads;
+
+ LoggingInfo(RecyclerView.ViewHolder viewHolder, int changeFlags, List<Object> payloads) {
+ this.viewHolder = viewHolder;
+ this.changeFlags = changeFlags;
+ if (payloads != null) {
+ this.payloads = new ArrayList<>();
+ this.payloads.addAll(payloads);
+ } else {
+ this.payloads = null;
+ }
+ setFrom(viewHolder);
+ }
+ }
+
+ static class AnimateChange extends AnimateLogBase {
+
+ final RecyclerView.ViewHolder newHolder;
+
+ public AnimateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,
+ LoggingInfo pre, LoggingInfo post) {
+ super(oldHolder, pre, post);
+ this.newHolder = newHolder;
+ }
+ }
+
+ static class AnimatePersistence extends AnimateLogBase {
+
+ public AnimatePersistence(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
+ LoggingInfo post) {
+ super(viewHolder, pre, post);
+ }
+ }
+
+ static class AnimateAppearance extends AnimateLogBase {
+ public AnimateAppearance(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
+ LoggingInfo post) {
+ super(viewHolder, pre, post);
+ }
+ }
+
+ static class AnimateDisappearance extends AnimateLogBase {
+ public AnimateDisappearance(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
+ LoggingInfo post) {
+ super(viewHolder, pre, post);
+ }
+ }
+ static class AnimateLogBase {
+
+ final RecyclerView.ViewHolder viewHolder;
+ final LoggingInfo preInfo;
+ final LoggingInfo postInfo;
+
+ public AnimateLogBase(RecyclerView.ViewHolder viewHolder, LoggingInfo pre,
+ LoggingInfo postInfo) {
+ this.viewHolder = viewHolder;
+ this.preInfo = pre;
+ this.postInfo = postInfo;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ AnimateLogBase that = (AnimateLogBase) o;
+
+ if (viewHolder != null ? !viewHolder.equals(that.viewHolder)
+ : that.viewHolder != null) {
+ return false;
+ }
+ if (preInfo != null ? !preInfo.equals(that.preInfo) : that.preInfo != null) {
+ return false;
+ }
+ return !(postInfo != null ? !postInfo.equals(that.postInfo) : that.postInfo != null);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = viewHolder != null ? viewHolder.hashCode() : 0;
+ result = 31 * result + (preInfo != null ? preInfo.hashCode() : 0);
+ result = 31 * result + (postInfo != null ? postInfo.hashCode() : 0);
+ return result;
+ }
+ }
+}
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 2659ef2..c5f3408 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -164,7 +164,7 @@
} catch (Exception e) {
throw e;
} catch (Throwable throwable) {
- throw new Exception(throwable);
+ throw new Exception(Log.getStackTraceString(throwable));
}
}
@@ -202,19 +202,23 @@
mRecyclerView = null;
}
- void waitForAnimations(int seconds) throws InterruptedException {
- final CountDownLatch latch = new CountDownLatch(2);
- boolean running = mRecyclerView.mItemAnimator
- .isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
- @Override
- public void onAnimationsFinished() {
- latch.countDown();
- }
- });
- if (running) {
- latch.countDown();
- latch.await(seconds, TimeUnit.SECONDS);
- }
+ void waitForAnimations(int seconds) throws Throwable {
+ final CountDownLatch latch = new CountDownLatch(1);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mRecyclerView.mItemAnimator
+ .isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
+ @Override
+ public void onAnimationsFinished() {
+ latch.countDown();
+ }
+ });
+ }
+ });
+
+ assertTrue("animations didn't finish on expected time of " + seconds + " seconds",
+ latch.await(seconds, TimeUnit.SECONDS));
}
public boolean requestFocus(final View view) {
@@ -548,6 +552,7 @@
int mAdapterIndex;
final String mText;
+ int mType = 0;
Item(int adapterIndex, String text) {
mAdapterIndex = adapterIndex;
@@ -584,6 +589,11 @@
}
@Override
+ public int getItemViewType(int position) {
+ return getItemAt(position).mType;
+ }
+
+ @Override
public void onViewAttachedToWindow(TestViewHolder holder) {
super.onViewAttachedToWindow(holder);
mAttachmentCounter.onViewAttached(holder);
@@ -713,6 +723,16 @@
});
}
+ public void changeAndNotifyWithPayload(final int start, final int count,
+ final Object payload) throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ notifyItemRangeChanged(start, count, payload);
+ }
+ });
+ }
+
public void changePositionsAndNotify(final int... positions) throws Throwable {
runTestOnUiThread(new Runnable() {
@Override
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ChildHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/ChildHelperTest.java
new file mode 100644
index 0000000..8163310
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/ChildHelperTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+
+package android.support.v7.widget;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.AndroidTestCase;
+import android.test.mock.MockContext;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class ChildHelperTest extends AndroidTestCase {
+ LoggingCallback mLoggingCallback;
+ ChildHelper mChildHelper;
+
+ @Before
+ public void prepare() throws Exception {
+ setUp();
+ setContext(InstrumentationRegistry.getContext());
+ mLoggingCallback = new LoggingCallback();
+ mChildHelper = new ChildHelper(mLoggingCallback);
+ }
+
+ private RecyclerView.ViewHolder vh() {
+ View view = new View(mContext);
+ RecyclerViewBasicTest.MockViewHolder mockViewHolder
+ = new RecyclerViewBasicTest.MockViewHolder(view);
+ RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(0 , 0);
+ lp.mViewHolder = mockViewHolder;
+ view.setLayoutParams(lp);
+ return mockViewHolder;
+ }
+
+ @Test
+ public void testAddChild() {
+ RecyclerView.ViewHolder vh = vh();
+ mChildHelper.addView(vh.itemView, false);
+ assertEquals(1, mLoggingCallback.getChildCount());
+ assertFalse(mChildHelper.isHidden(vh.itemView));
+ assertEquals(0, mLoggingCallback.mOnEnteredHiddenState.size());
+ }
+
+ @Test
+ public void testAddChildHidden() {
+ RecyclerView.ViewHolder vh = vh();
+ mChildHelper.addView(vh.itemView, true);
+ assertEquals(1, mLoggingCallback.getChildCount());
+ assertTrue(mChildHelper.isHidden(vh.itemView));
+ assertTrue(mLoggingCallback.mOnEnteredHiddenState.contains(vh.itemView));
+ }
+
+ @Test
+ public void testAddChildAndHide() {
+ RecyclerView.ViewHolder vh = vh();
+ mChildHelper.addView(vh.itemView, false);
+ mChildHelper.hide(vh.itemView);
+ assertTrue(mChildHelper.isHidden(vh.itemView));
+ mChildHelper.unhide(vh.itemView);
+ assertFalse(mChildHelper.isHidden(vh.itemView));
+ }
+
+ @Test
+ public void testFindHiddenNonRemoved() {
+ RecyclerView.ViewHolder vh = vh();
+ vh.mPosition = 12;
+ mChildHelper.addView(vh.itemView, true);
+ assertSame(vh.itemView,
+ mChildHelper.findHiddenNonRemovedView(12, RecyclerView.INVALID_TYPE));
+ }
+
+ @Test
+ public void testFindHiddenRemoved() {
+ RecyclerView.ViewHolder vh = vh();
+ vh.mPosition = 12;
+ vh.addFlags(RecyclerView.ViewHolder.FLAG_REMOVED);
+ mChildHelper.addView(vh.itemView, true);
+ assertNull(mChildHelper.findHiddenNonRemovedView(12, RecyclerView.INVALID_TYPE));
+ }
+
+ private static class LoggingCallback implements ChildHelper.Callback {
+ List<View> mViews = new ArrayList<>();
+ List<View> mDetached = new ArrayList<>();
+ List<View> mOnEnteredHiddenState = new ArrayList<>();
+ List<View> mOnExitedHiddenState = new ArrayList<>();
+ @Override
+ public int getChildCount() {
+ return mViews.size();
+ }
+
+ @Override
+ public void addView(View child, int index) {
+ mViews.add(index, child);
+ }
+
+ @Override
+ public int indexOfChild(View view) {
+ return mViews.indexOf(view);
+ }
+
+ private boolean validateIndex(int index) {
+ return index < getChildCount() && index >= 0;
+ }
+
+ @Override
+ public void removeViewAt(int index) {
+ if (validateIndex(index)) {
+ mViews.remove(index);
+ }
+ }
+
+ @Override
+ public View getChildAt(int offset) {
+ if (validateIndex(offset)) {
+ return mViews.remove(offset);
+ }
+ return null;
+ }
+
+ @Override
+ public void removeAllViews() {
+ mViews.clear();
+ }
+
+ @Override
+ public RecyclerView.ViewHolder getChildViewHolder(View view) {
+ return RecyclerView.getChildViewHolderInt(view);
+ }
+
+ @Override
+ public void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams) {
+ assertTrue(mDetached.remove(child));
+ addView(child, index);
+ }
+
+ @Override
+ public void detachViewFromParent(int offset) {
+ mDetached.add(getChildAt(offset));
+ }
+
+ @Override
+ public void onEnteredHiddenState(View child) {
+ mOnEnteredHiddenState.add(child);
+ }
+
+ @Override
+ public void onLeftHiddenState(View child) {
+ mOnExitedHiddenState.add(child);
+ }
+
+ public void clearHiddenStateLog() {
+ mOnExitedHiddenState.clear();
+ mOnEnteredHiddenState.clear();
+ }
+ }
+}
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 46833ca..5010be9 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
@@ -58,10 +58,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mAnimator = new DefaultItemAnimator();
- mAdapter = new Adapter(20);
- mDummyParent = getActivity().mContainer;
- mAnimator.setListener(new RecyclerView.ItemAnimator.ItemAnimatorListener() {
+ mAnimator = new DefaultItemAnimator() {
@Override
public void onRemoveFinished(RecyclerView.ViewHolder item) {
try {
@@ -93,7 +90,7 @@
}
@Override
- public void onChangeFinished(RecyclerView.ViewHolder item) {
+ public void onChangeFinished(RecyclerView.ViewHolder item, boolean oldItem) {
try {
assertTrue(mChangeFinished.add(item));
onFinished(item);
@@ -106,7 +103,9 @@
assertNotNull(mExpectedItems.remove(item));
mExpectedItemCount.release(1);
}
- });
+ };
+ mAdapter = new Adapter(20);
+ mDummyParent = getActivity().mContainer;
}
void checkForMainThreadException() throws Throwable {
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 ca7b0a4..6192c66 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
@@ -18,9 +18,9 @@
import android.content.Context;
import android.graphics.Rect;
-import android.os.Debug;
import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.test.UiThreadTest;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.View;
@@ -86,6 +86,27 @@
mGlm.waitForLayout(2);
}
+ @UiThreadTest
+ public void testScrollWithoutLayout() throws Throwable {
+ final RecyclerView recyclerView = setupBasic(new Config(3, 100));
+ mGlm.expectLayout(1);
+ setRecyclerView(recyclerView);
+ mGlm.setSpanCount(5);
+ recyclerView.scrollBy(0, 10);
+ }
+
+ public void testScrollWithoutLayoutAfterInvalidate() throws Throwable {
+ final RecyclerView recyclerView = setupBasic(new Config(3, 100));
+ waitForFirstLayout(recyclerView);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mGlm.setSpanCount(5);
+ recyclerView.scrollBy(0, 10);
+ }
+ });
+ }
+
public void testPredictiveSpanLookup1() throws Throwable {
predictiveSpanLookupTest(0, false);
}
@@ -291,7 +312,7 @@
return 3;
}
});
- rv.getItemAnimator().setSupportsChangeAnimations(true);
+ ((SimpleItemAnimator)rv.getItemAnimator()).setSupportsChangeAnimations(true);
waitForFirstLayout(rv);
View lastView = rv.getChildAt(rv.getChildCount() - 1);
final int lastPos = rv.getChildAdapterPosition(lastView);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/InfoStoreTrojan.java b/v7/recyclerview/tests/src/android/support/v7/widget/InfoStoreTrojan.java
new file mode 100644
index 0000000..b3fbae4
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/InfoStoreTrojan.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+/**
+ * Helper class for tests to check internals of ViewInfoStore
+ */
+public class InfoStoreTrojan {
+ static int sizeOfPreLayout(ViewInfoStore store) {
+ return sizeOf(store, ViewInfoStore.InfoRecord.FLAG_PRE);
+ }
+ static int sizeOfPostLayout(ViewInfoStore store) {
+ return sizeOf(store, ViewInfoStore.InfoRecord.FLAG_POST);
+ }
+ static int sizeOf(ViewInfoStore store, int flags) {
+ int cnt = 0;
+ final int size = store.mLayoutHolderMap.size();
+ for (int i = 0; i < size; i ++) {
+ ViewInfoStore.InfoRecord record = store.mLayoutHolderMap.valueAt(i);
+ if ((record.flags & flags) != 0) {
+ cnt ++;
+ }
+ }
+ return cnt;
+ }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java
new file mode 100644
index 0000000..5733e720
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java
@@ -0,0 +1,541 @@
+/*
+ * 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.
+ */
+package android.support.v7.widget;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_CHANGED;
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_MOVED;
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_REMOVED;
+
+/**
+ * Includes tests for the new RecyclerView animations API (v2).
+ */
+public class ItemAnimatorV2ApiTest extends BaseRecyclerViewAnimationsTest {
+ @Override
+ protected RecyclerView.ItemAnimator createItemAnimator() {
+ return mAnimator;
+ }
+
+ public void testChangeMovedOutside() throws Throwable {
+ setupBasic(10);
+ final RecyclerView.ViewHolder target = mRecyclerView.findViewHolderForAdapterPosition(9);
+ mLayoutManager.expectLayouts(2);
+ mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+ mTestAdapter.changeAndNotify(9, 1);
+ mLayoutManager.waitForLayout(2);
+ // changed item shold not be laid out and should just receive disappear
+ LoggingInfo pre = mAnimator.preLayoutInfoMap.get(target);
+ assertNotNull("test sanity", pre);
+ assertNull("test sanity", mAnimator.postLayoutInfoMap.get(target));
+ assertTrue(mAnimator.animateChangeList.isEmpty());
+ assertEquals(1, mAnimator.animateDisappearanceList.size());
+ assertEquals(new AnimateDisappearance(target, pre, null),
+ mAnimator.animateDisappearanceList.get(0));
+ // This is kind of problematic because layout manager will never layout the updated
+ // version of this view since it went out of bounds and it won't show up in scrap.
+ // I don't think we can do much better since other option is to bind a fresh view
+ }
+
+ public void testSimpleAdd() throws Throwable {
+ setupBasic(10);
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.addAndNotify(2, 1);
+ mLayoutManager.waitForLayout(2);
+ RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+ assertEquals(1, mAnimator.animateAppearanceList.size());
+ AnimateAppearance log = mAnimator.animateAppearanceList.get(0);
+ assertSame(vh, log.viewHolder);
+ assertNull(log.preInfo);
+ assertEquals(0, log.postInfo.changeFlags);
+ // the first two should not receive anything
+ for (int i = 0; i < 2; i++) {
+ RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+ assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+ }
+ for (int i = 3; i < mTestAdapter.getItemCount(); i++) {
+ RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+ assertEquals(FLAG_MOVED, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+ }
+ checkForMainThreadException();
+ }
+
+ public void testSimpleRemove() throws Throwable {
+ setupBasic(10);
+ RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.deleteAndNotify(2, 1);
+ mLayoutManager.waitForLayout(2);
+ checkForMainThreadException();
+ assertEquals(1, mAnimator.animateDisappearanceList.size());
+ AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
+ assertSame(vh, log.viewHolder);
+ assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+ assertEquals(FLAG_REMOVED, log.preInfo.changeFlags);
+ // the first two should not receive anything
+ for (int i = 0; i < 2; i++) {
+ RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+ assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+ }
+ for (int i = 3; i < mTestAdapter.getItemCount(); i++) {
+ RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+ assertEquals(FLAG_MOVED, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+ }
+ checkForMainThreadException();
+ }
+
+ public void testSimpleUpdate() throws Throwable {
+ setupBasic(10);
+ RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.changeAndNotify(2, 1);
+ mLayoutManager.waitForLayout(2);
+ assertEquals(1, mAnimator.animateChangeList.size());
+ AnimateChange log = mAnimator.animateChangeList.get(0);
+ assertSame(vh, log.viewHolder);
+ assertSame(vh, log.newHolder);
+ assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+ assertTrue(mAnimator.postLayoutInfoMap.containsKey(vh));
+ assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+ assertEquals(0, log.postInfo.changeFlags);
+ //others should not receive anything
+ for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+ if (i == 2) {
+ continue;
+ }
+ RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+ assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+ }
+ checkForMainThreadException();
+ }
+
+ public void testUpdateWithDuplicateViewHolder() throws Throwable {
+ setupBasic(10);
+ final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+ mAnimator.canReUseCallback = new CanReUseCallback() {
+ @Override
+ public boolean canReUse(RecyclerView.ViewHolder viewHolder) {
+ assertSame(viewHolder, vh);
+ return false;
+ }
+ };
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.changeAndNotify(2, 1);
+ mLayoutManager.waitForLayout(2);
+ final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+ assertNotSame(vh, newVh);
+ assertEquals(1, mAnimator.animateChangeList.size());
+ AnimateChange log = mAnimator.animateChangeList.get(0);
+ assertSame(vh, log.viewHolder);
+ assertSame(newVh, log.newHolder);
+ assertNull(vh.itemView.getParent());
+ assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+ assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+ assertTrue(mAnimator.postLayoutInfoMap.containsKey(newVh));
+ assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+ assertEquals(0, log.postInfo.changeFlags);
+ //others should not receive anything
+ for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+ if (i == 2) {
+ continue;
+ }
+ RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+ assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+ }
+ checkForMainThreadException();
+ }
+
+ public void testUpdateWithOneDuplicateAndOneInPlace() throws Throwable {
+ setupBasic(10);
+ final RecyclerView.ViewHolder replaced = mRecyclerView.findViewHolderForAdapterPosition(2);
+ final RecyclerView.ViewHolder reused = mRecyclerView.findViewHolderForAdapterPosition(3);
+ mAnimator.canReUseCallback = new CanReUseCallback() {
+ @Override
+ public boolean canReUse(RecyclerView.ViewHolder viewHolder) {
+ if (viewHolder == replaced) {
+ return false;
+ } else if (viewHolder == reused) {
+ return true;
+ }
+ fail("unpexpected view");
+ return false;
+ }
+ };
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.changeAndNotify(2, 2);
+ mLayoutManager.waitForLayout(2);
+ final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+
+ assertNotSame(replaced, newVh);
+ assertSame(reused, mRecyclerView.findViewHolderForAdapterPosition(3));
+
+ assertEquals(2, mAnimator.animateChangeList.size());
+ AnimateChange logReplaced = null, logReused = null;
+ for (AnimateChange change : mAnimator.animateChangeList) {
+ if (change.newHolder == change.viewHolder) {
+ logReused = change;
+ } else {
+ logReplaced = change;
+ }
+ }
+ assertNotNull(logReplaced);
+ assertNotNull(logReused);
+ assertSame(replaced, logReplaced.viewHolder);
+ assertSame(newVh, logReplaced.newHolder);
+ assertSame(reused, logReused.viewHolder);
+ assertSame(reused, logReused.newHolder);
+
+ assertTrue(mAnimator.preLayoutInfoMap.containsKey(replaced));
+ assertTrue(mAnimator.preLayoutInfoMap.containsKey(reused));
+
+ assertTrue(mAnimator.postLayoutInfoMap.containsKey(newVh));
+ assertTrue(mAnimator.postLayoutInfoMap.containsKey(reused));
+ assertFalse(mAnimator.postLayoutInfoMap.containsKey(replaced));
+
+ assertEquals(FLAG_CHANGED, logReplaced.preInfo.changeFlags);
+ assertEquals(FLAG_CHANGED, logReused.preInfo.changeFlags);
+
+ assertEquals(0, logReplaced.postInfo.changeFlags);
+ assertEquals(0, logReused.postInfo.changeFlags);
+ //others should not receive anything
+ for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+ if (i == 2 || i == 3) {
+ continue;
+ }
+ RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+ assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+ }
+ checkForMainThreadException();
+ }
+
+ public void testChangeToDisappear() throws Throwable {
+ setupBasic(10);
+ RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(9);
+ mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.changeAndNotify(9, 1);
+ mLayoutManager.waitForLayout(2);
+ assertEquals(1, mAnimator.animateDisappearanceList.size());
+ AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
+ assertSame(vh, log.viewHolder);
+ assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+ assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+ assertEquals(0, mAnimator.animateChangeList.size());
+ assertEquals(0, mAnimator.animateAppearanceList.size());
+ assertEquals(9, mAnimator.animatePersistenceList.size());
+ checkForMainThreadException();
+ }
+
+ public void testUpdatePayload() throws Throwable {
+ setupBasic(10);
+ RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+ mLayoutManager.expectLayouts(2);
+ Object payload = new Object();
+ mTestAdapter.changeAndNotifyWithPayload(2, 1, payload);
+ mLayoutManager.waitForLayout(2);
+ assertEquals(1, mAnimator.animateChangeList.size());
+ AnimateChange log = mAnimator.animateChangeList.get(0);
+ assertSame(vh, log.viewHolder);
+ assertSame(vh, log.newHolder);
+ assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+ assertTrue(mAnimator.postLayoutInfoMap.containsKey(vh));
+ assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+ assertEquals(0, log.postInfo.changeFlags);
+ assertNotNull(log.preInfo.payloads);
+ assertTrue(log.preInfo.payloads.contains(payload));
+ //others should not receive anything
+ for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+ if (i == 2) {
+ continue;
+ }
+ RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+ assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+ }
+ checkForMainThreadException();
+ }
+
+ public void testNotifyDataSetChanged() throws Throwable {
+ TestAdapter adapter = new TestAdapter(10);
+ adapter.setHasStableIds(true);
+ setupBasic(10, 0, 10, adapter);
+ mLayoutManager.expectLayouts(1);
+ mTestAdapter.dispatchDataSetChanged();
+ mLayoutManager.waitForLayout(2);
+ assertEquals(10, mAnimator.animateChangeList.size());
+ for (AnimateChange change : mAnimator.animateChangeList) {
+ assertNotNull(change.preInfo);
+ assertNotNull(change.postInfo);
+ assertSame(change.preInfo.viewHolder, change.postInfo.viewHolder);
+ }
+ assertEquals(0, mAnimator.animatePersistenceList.size());
+ assertEquals(0, mAnimator.animateAppearanceList.size());
+ assertEquals(0, mAnimator.animateDisappearanceList.size());
+ }
+
+ public void testNotifyDataSetChangedWithoutStableIds() throws Throwable {
+ TestAdapter adapter = new TestAdapter(10);
+ adapter.setHasStableIds(false);
+ setupBasic(10, 0, 10, adapter);
+ mLayoutManager.expectLayouts(1);
+ mTestAdapter.dispatchDataSetChanged();
+ mLayoutManager.waitForLayout(2);
+ assertEquals(0, mAnimator.animateChangeList.size());
+ assertEquals(0, mAnimator.animatePersistenceList.size());
+ assertEquals(0, mAnimator.animateAppearanceList.size());
+ assertEquals(0, mAnimator.animateDisappearanceList.size());
+ }
+
+ public void testNotifyDataSetChangedWithAppearing() throws Throwable {
+ notifyDataSetChangedWithAppearing(false);
+ }
+
+ public void testNotifyDataSetChangedWithAppearingNotifyBoth() throws Throwable {
+ notifyDataSetChangedWithAppearing(true);
+ }
+
+ public void notifyDataSetChangedWithAppearing(final boolean notifyBoth) throws Throwable {
+ final TestAdapter adapter = new TestAdapter(10);
+ adapter.setHasStableIds(true);
+ setupBasic(10, 0, 10, adapter);
+ mLayoutManager.expectLayouts(1);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (notifyBoth) {
+ adapter.addAndNotify(2, 2);
+ } else {
+ adapter.mItems.add(2, new Item(2, "custom 1"));
+ adapter.mItems.add(3, new Item(3, "custom 2"));
+ }
+
+ adapter.notifyDataSetChanged();
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+ }
+ });
+ mLayoutManager.waitForLayout(2);
+ assertEquals(10, mAnimator.animateChangeList.size());
+ assertEquals(0, mAnimator.animatePersistenceList.size());
+ assertEquals(2, mAnimator.animateAppearanceList.size());
+ assertEquals(0, mAnimator.animateDisappearanceList.size());
+ }
+
+ public void testNotifyDataSetChangedWithDispappearing() throws Throwable {
+ notifyDataSetChangedWithDispappearing(false);
+ }
+
+ public void testNotifyDataSetChangedWithDispappearingNotifyBoth() throws Throwable {
+ notifyDataSetChangedWithDispappearing(true);
+ }
+
+ public void notifyDataSetChangedWithDispappearing(final boolean notifyBoth) throws Throwable {
+ final TestAdapter adapter = new TestAdapter(10);
+ adapter.setHasStableIds(true);
+ setupBasic(10, 0, 10, adapter);
+ mLayoutManager.expectLayouts(1);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (notifyBoth) {
+ adapter.deleteAndNotify(2, 2);
+ } else {
+ adapter.mItems.remove(2);
+ adapter.mItems.remove(2);
+ }
+ adapter.notifyDataSetChanged();
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+ }
+ });
+ mLayoutManager.waitForLayout(2);
+ assertEquals(8, mAnimator.animateChangeList.size());
+ assertEquals(0, mAnimator.animatePersistenceList.size());
+ assertEquals(0, mAnimator.animateAppearanceList.size());
+ assertEquals(2, mAnimator.animateDisappearanceList.size());
+ }
+
+ public void testNotifyUpdateWithChangedAdapterType() throws Throwable {
+ final AtomicInteger itemType = new AtomicInteger(1);
+ final TestAdapter adapter = new TestAdapter(10) {
+ @Override
+ public int getItemViewType(int position) {
+ return position == 2 ? itemType.get() : 20;
+ }
+ };
+ adapter.setHasStableIds(true);
+ setupBasic(10, 0, 10, adapter);
+ final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+
+ mAnimator.canReUseCallback = new CanReUseCallback() {
+ @Override
+ public boolean canReUse(RecyclerView.ViewHolder viewHolder) {
+ return viewHolder != vh;
+ }
+ };
+
+ mLayoutManager.expectLayouts(1);
+ itemType.set(3);
+ adapter.dispatchDataSetChanged();
+ mLayoutManager.waitForLayout(2);
+ final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+ // TODO we should be able to map old type to the new one but doing that change has some
+ // recycling side effects.
+ assertEquals(9, mAnimator.animateChangeList.size());
+ assertEquals(0, mAnimator.animatePersistenceList.size());
+ assertEquals(1, mAnimator.animateAppearanceList.size());
+ assertEquals(0, mAnimator.animateDisappearanceList.size());
+ assertNotSame(vh, newVh);
+ for (AnimateChange change : mAnimator.animateChangeList) {
+ if (change.viewHolder == vh) {
+ assertSame(change.newHolder, newVh);
+ assertSame(change.viewHolder, vh);
+ } else {
+ assertSame(change.newHolder, change.viewHolder);
+ }
+ }
+ }
+
+ LoggingV2Animator mAnimator = new LoggingV2Animator();
+
+ class LoggingV2Animator extends RecyclerView.ItemAnimator {
+
+ CanReUseCallback canReUseCallback = new CanReUseCallback() {
+ @Override
+ public boolean canReUse(RecyclerView.ViewHolder viewHolder) {
+ return true;
+ }
+ };
+ Map<RecyclerView.ViewHolder, LoggingInfo> preLayoutInfoMap = new HashMap<>();
+ Map<RecyclerView.ViewHolder, LoggingInfo> postLayoutInfoMap = new HashMap<>();
+
+ List<AnimateAppearance> animateAppearanceList = new ArrayList<>();
+ List<AnimateDisappearance> animateDisappearanceList = new ArrayList<>();
+ List<AnimatePersistence> animatePersistenceList = new ArrayList<>();
+ List<AnimateChange> animateChangeList = new ArrayList<>();
+
+ @Override
+ public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
+ return canReUseCallback.canReUse(viewHolder);
+ }
+
+ @NonNull
+ @Override
+ public ItemHolderInfo recordPreLayoutInformation(@NonNull RecyclerView.State state,
+ @NonNull RecyclerView.ViewHolder viewHolder,
+ @AdapterChanges int changeFlags, @NonNull List<Object> payloads) {
+ LoggingInfo loggingInfo = new LoggingInfo(viewHolder, changeFlags, payloads);
+ preLayoutInfoMap.put(viewHolder, loggingInfo);
+ return loggingInfo;
+ }
+
+ @NonNull
+ @Override
+ public ItemHolderInfo recordPostLayoutInformation(@NonNull RecyclerView.State state,
+ @NonNull RecyclerView.ViewHolder viewHolder) {
+ LoggingInfo loggingInfo = new LoggingInfo(viewHolder, 0, null);
+ postLayoutInfoMap.put(viewHolder, loggingInfo);
+ return loggingInfo;
+ }
+
+ @Override
+ public boolean animateDisappearance(@NonNull RecyclerView.ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preLayoutInfo,
+ @Nullable ItemHolderInfo postLayoutInfo) {
+ animateDisappearanceList.add(new AnimateDisappearance(viewHolder,
+ (LoggingInfo) preLayoutInfo, (LoggingInfo) postLayoutInfo));
+ assertSame(preLayoutInfoMap.get(viewHolder), preLayoutInfo);
+ assertSame(postLayoutInfoMap.get(viewHolder), postLayoutInfo);
+ dispatchAnimationFinished(viewHolder);
+
+ return false;
+ }
+
+ @Override
+ public boolean animateAppearance(@NonNull RecyclerView.ViewHolder viewHolder,
+ ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+ animateAppearanceList.add(
+ new AnimateAppearance(viewHolder, (LoggingInfo) preInfo, (LoggingInfo) postInfo));
+ assertSame(preLayoutInfoMap.get(viewHolder), preInfo);
+ assertSame(postLayoutInfoMap.get(viewHolder), postInfo);
+ dispatchAnimationFinished(viewHolder);
+ return false;
+ }
+
+ @Override
+ public boolean animatePersistence(@NonNull RecyclerView.ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+ animatePersistenceList.add(new AnimatePersistence(viewHolder, (LoggingInfo) preInfo,
+ (LoggingInfo) postInfo));
+ dispatchAnimationFinished(viewHolder);
+ assertSame(preLayoutInfoMap.get(viewHolder), preInfo);
+ assertSame(postLayoutInfoMap.get(viewHolder), postInfo);
+ return false;
+ }
+
+ @Override
+ public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder,
+ @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo,
+ @NonNull ItemHolderInfo postInfo) {
+ animateChangeList.add(new AnimateChange(oldHolder, newHolder, (LoggingInfo) preInfo,
+ (LoggingInfo) postInfo));
+ if (oldHolder != null) {
+ dispatchAnimationFinished(oldHolder);
+ assertSame(preLayoutInfoMap.get(oldHolder), preInfo);
+ }
+ if (newHolder != null && oldHolder != newHolder) {
+ dispatchAnimationFinished(newHolder);
+ assertSame(postLayoutInfoMap.get(newHolder), postInfo);
+ }
+
+ return false;
+ }
+
+ @Override
+ public void runPendingAnimations() {
+
+ }
+
+ @Override
+ public void endAnimation(RecyclerView.ViewHolder item) {
+ }
+
+ @Override
+ public void endAnimations() {
+
+ }
+
+ @Override
+ public boolean isRunning() {
+ return false;
+ }
+ }
+
+ interface CanReUseCallback {
+
+ boolean canReUse(RecyclerView.ViewHolder viewHolder);
+ }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java b/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java
index 04031d4..9bbdd4b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java
@@ -13,9 +13,16 @@
package android.support.v7.widget;
+import android.support.annotation.NonNull;
+
import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import android.support.v7.widget.BaseRecyclerViewAnimationsTest.AnimateDisappearance;
+import android.support.v7.widget.BaseRecyclerViewAnimationsTest.AnimateChange;
+import android.support.v7.widget.BaseRecyclerViewAnimationsTest.AnimatePersistence;
+import android.support.v7.widget.BaseRecyclerViewAnimationsTest.AnimateAppearance;
public class LoggingItemAnimator extends DefaultItemAnimator {
@@ -29,8 +36,58 @@
final ArrayList<RecyclerView.ViewHolder> mChangeNewVHs = new ArrayList<RecyclerView.ViewHolder>();
+ List<AnimateAppearance> mAnimateAppearanceList = new ArrayList<>();
+ List<AnimateDisappearance> mAnimateDisappearanceList = new ArrayList<>();
+ List<AnimatePersistence> mAnimatePersistenceList = new ArrayList<>();
+ List<AnimateChange> mAnimateChangeList = new ArrayList<>();
+
CountDownLatch mWaitForPendingAnimations;
+ public boolean contains(RecyclerView.ViewHolder viewHolder,
+ List<? extends BaseRecyclerViewAnimationsTest.AnimateLogBase> list) {
+ for (BaseRecyclerViewAnimationsTest.AnimateLogBase log : list) {
+ if (log.viewHolder == viewHolder) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean animateDisappearance(@NonNull RecyclerView.ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preLayoutInfo, ItemHolderInfo postLayoutInfo) {
+ mAnimateDisappearanceList
+ .add(new AnimateDisappearance(viewHolder, null, null));
+ return super.animateDisappearance(viewHolder, preLayoutInfo, postLayoutInfo);
+ }
+
+ @Override
+ public boolean animateAppearance(@NonNull RecyclerView.ViewHolder viewHolder,
+ ItemHolderInfo preLayoutInfo,
+ @NonNull ItemHolderInfo postLayoutInfo) {
+ mAnimateAppearanceList
+ .add(new AnimateAppearance(viewHolder, null, null));
+ return super.animateAppearance(viewHolder, preLayoutInfo, postLayoutInfo);
+ }
+
+ @Override
+ public boolean animatePersistence(@NonNull RecyclerView.ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preInfo,
+ @NonNull ItemHolderInfo postInfo) {
+ mAnimatePersistenceList
+ .add(new AnimatePersistence(viewHolder, null, null));
+ return super.animatePersistence(viewHolder, preInfo, postInfo);
+ }
+
+ @Override
+ public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder,
+ @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo,
+ @NonNull ItemHolderInfo postInfo) {
+ mAnimateChangeList
+ .add(new AnimateChange(oldHolder, newHolder, null, null));
+ return super.animateChange(oldHolder, newHolder, preInfo, postInfo);
+ }
+
@Override
public void runPendingAnimations() {
if (mWaitForPendingAnimations != null) {
@@ -84,5 +141,9 @@
mMoveVHs.clear();
mChangeOldVHs.clear();
mChangeNewVHs.clear();
+ mAnimateChangeList.clear();
+ mAnimatePersistenceList.clear();
+ mAnimateAppearanceList.clear();
+ mAnimateDisappearanceList.clear();
}
}
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
index 119ad80..0b9ef15 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
@@ -16,11 +16,9 @@
package android.support.v7.widget;
-import android.content.Context;
-import android.graphics.Canvas;
import android.graphics.Rect;
+import android.os.Debug;
import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -31,65 +29,315 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-public class RecyclerViewAnimationsTest extends BaseRecyclerViewInstrumentationTest {
+/**
+ * Tests for {@link SimpleItemAnimator} API.
+ */
+public class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest {
- private static final boolean DEBUG = false;
+ final List<TestViewHolder> recycledVHs = new ArrayList<>();
- private static final String TAG = "RecyclerViewAnimationsTest";
+ public void testDontLayoutReusedViewWithoutPredictive() throws Throwable {
+ reuseHiddenViewTest(new ReuseTestCallback() {
+ @Override
+ public void postSetup(List<TestViewHolder> recycledList,
+ final TestViewHolder target) throws Throwable {
+ LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+ .getItemAnimator();
+ itemAnimator.reset();
+ mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+ @Override
+ void beforePreLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager lm, RecyclerView.State state) {
+ fail("pre layout is not expected");
+ }
- AnimationLayoutManager mLayoutManager;
+ @Override
+ void beforePostLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager layoutManager,
+ RecyclerView.State state) {
+ mLayoutItemCount = 7;
+ View targetView = recycler
+ .getViewForPosition(target.getAdapterPosition());
+ assertSame(targetView, target.itemView);
+ super.beforePostLayout(recycler, layoutManager, state);
+ }
- TestAdapter mTestAdapter;
+ @Override
+ void afterPostLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager layoutManager,
+ RecyclerView.State state) {
+ super.afterPostLayout(recycler, layoutManager, state);
+ assertNull("test sanity. this view should not be re-laid out in post "
+ + "layout", target.itemView.getParent());
+ }
+ };
+ mLayoutManager.expectLayouts(1);
+ mLayoutManager.requestSimpleAnimationsInNextLayout();
+ requestLayoutOnUIThread(mRecyclerView);
+ mLayoutManager.waitForLayout(2);
+ checkForMainThreadException();
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+ // This is a LayoutManager problem if it asked for the view but didn't properly
+ // lay it out. It will move to disappearance
+ assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+ waitForAnimations(5);
+ assertTrue(recycledVHs.contains(target));
+ }
+ });
+ }
- public RecyclerViewAnimationsTest() {
- super(DEBUG);
+ public void testDontLayoutReusedViewWithPredictive() throws Throwable {
+ reuseHiddenViewTest(new ReuseTestCallback() {
+ @Override
+ public void postSetup(List<TestViewHolder> recycledList,
+ final TestViewHolder target) throws Throwable {
+ LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+ .getItemAnimator();
+ itemAnimator.reset();
+ mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+ @Override
+ void beforePreLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager lm, RecyclerView.State state) {
+ mLayoutItemCount = 9;
+ super.beforePreLayout(recycler, lm, state);
+ }
+
+ @Override
+ void beforePostLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager layoutManager,
+ RecyclerView.State state) {
+ mLayoutItemCount = 7;
+ super.beforePostLayout(recycler, layoutManager, state);
+ }
+
+ @Override
+ void afterPostLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager layoutManager,
+ RecyclerView.State state) {
+ super.afterPostLayout(recycler, layoutManager, state);
+ assertNull("test sanity. this view should not be re-laid out in post "
+ + "layout", target.itemView.getParent());
+ }
+ };
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.deleteAndNotify(1, 1);
+ mLayoutManager.waitForLayout(2);
+ checkForMainThreadException();
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+ // This is a LayoutManager problem if it asked for the view but didn't properly
+ // lay it out. It will move to disappearance.
+ assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+ waitForAnimations(5);
+ assertTrue(recycledVHs.contains(target));
+ }
+ });
+ }
+
+ public void testReuseHiddenViewWithoutPredictive() throws Throwable {
+ reuseHiddenViewTest(new ReuseTestCallback() {
+ @Override
+ public void postSetup(List<TestViewHolder> recycledList,
+ TestViewHolder target) throws Throwable {
+ LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+ .getItemAnimator();
+ itemAnimator.reset();
+ mLayoutManager.expectLayouts(1);
+ mLayoutManager.requestSimpleAnimationsInNextLayout();
+ mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+ requestLayoutOnUIThread(mRecyclerView);
+ mLayoutManager.waitForLayout(2);
+ waitForAnimations(5);
+ assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+ assertFalse(recycledVHs.contains(target));
+ }
+ });
+ }
+
+ public void testReuseHiddenViewWithoutAnimations() throws Throwable {
+ reuseHiddenViewTest(new ReuseTestCallback() {
+ @Override
+ public void postSetup(List<TestViewHolder> recycledList,
+ TestViewHolder target) throws Throwable {
+ LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+ .getItemAnimator();
+ itemAnimator.reset();
+ mLayoutManager.expectLayouts(1);
+ mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+ requestLayoutOnUIThread(mRecyclerView);
+ mLayoutManager.waitForLayout(2);
+ waitForAnimations(5);
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+ assertFalse(recycledVHs.contains(target));
+ }
+ });
+ }
+
+ public void testReuseHiddenViewWithPredictive() throws Throwable {
+ reuseHiddenViewTest(new ReuseTestCallback() {
+ @Override
+ public void postSetup(List<TestViewHolder> recycledList,
+ TestViewHolder target) throws Throwable {
+ // it should move to change scrap and then show up from there
+ LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+ .getItemAnimator();
+ itemAnimator.reset();
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.deleteAndNotify(2, 1);
+ mLayoutManager.waitForLayout(2);
+ waitForAnimations(5);
+ // This LM does not layout the additional item so it does predictive wrong.
+ // We should still handle it and animate persistence for this item
+ assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+ assertTrue(itemAnimator.mMoveVHs.contains(target));
+ assertFalse(recycledVHs.contains(target));
+ }
+ });
+ }
+
+ public void testReuseHiddenViewWithProperPredictive() throws Throwable {
+ reuseHiddenViewTest(new ReuseTestCallback() {
+ @Override
+ public void postSetup(List<TestViewHolder> recycledList,
+ TestViewHolder target) throws Throwable {
+ // it should move to change scrap and then show up from there
+ LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+ .getItemAnimator();
+ itemAnimator.reset();
+ mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+ @Override
+ void beforePreLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager lm, RecyclerView.State state) {
+ mLayoutItemCount = 9;
+ super.beforePreLayout(recycler, lm, state);
+ }
+
+ @Override
+ void afterPreLayout(RecyclerView.Recycler recycler,
+ AnimationLayoutManager layoutManager,
+ RecyclerView.State state) {
+ mLayoutItemCount = 8;
+ super.afterPreLayout(recycler, layoutManager, state);
+ }
+ };
+
+ mLayoutManager.expectLayouts(2);
+ mTestAdapter.deleteAndNotify(2, 1);
+ mLayoutManager.waitForLayout(2);
+ waitForAnimations(5);
+ // This LM implements predictive animations properly by requesting target view
+ // in pre-layout.
+ assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+ assertTrue(itemAnimator.mMoveVHs.contains(target));
+ assertFalse(recycledVHs.contains(target));
+ }
+ });
+ }
+
+ public void testDontReuseHiddenViewOnInvalidate() throws Throwable {
+ reuseHiddenViewTest(new ReuseTestCallback() {
+ @Override
+ public void postSetup(List<TestViewHolder> recycledList,
+ TestViewHolder target) throws Throwable {
+ // it should move to change scrap and then show up from there
+ LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+ .getItemAnimator();
+ itemAnimator.reset();
+ mLayoutManager.expectLayouts(1);
+ mTestAdapter.dispatchDataSetChanged();
+ mLayoutManager.waitForLayout(2);
+ waitForAnimations(5);
+ assertFalse(mRecyclerView.getItemAnimator().isRunning());
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+ assertTrue(recycledVHs.contains(target));
+ }
+ });
+ }
+
+ public void testDontReuseOnTypeChange() throws Throwable {
+ reuseHiddenViewTest(new ReuseTestCallback() {
+ @Override
+ public void postSetup(List<TestViewHolder> recycledList,
+ TestViewHolder target) throws Throwable {
+ // it should move to change scrap and then show up from there
+ LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+ .getItemAnimator();
+ itemAnimator.reset();
+ mLayoutManager.expectLayouts(1);
+ target.mBoundItem.mType += 2;
+ mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+ mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1);
+ requestLayoutOnUIThread(mRecyclerView);
+ mLayoutManager.waitForLayout(2);
+
+ assertTrue(itemAnimator.mChangeOldVHs.contains(target));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+ assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+ assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView));
+ assertFalse(recycledVHs.contains(target));
+ waitForAnimations(5);
+ assertTrue(recycledVHs.contains(target));
+ }
+ });
+ }
+
+ interface ReuseTestCallback {
+
+ void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable;
}
@Override
- protected void setUp() throws Exception {
- super.setUp();
+ protected RecyclerView.ItemAnimator createItemAnimator() {
+ return new LoggingItemAnimator();
}
- RecyclerView setupBasic(int itemCount) throws Throwable {
- return setupBasic(itemCount, 0, itemCount);
- }
-
- RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount)
- throws Throwable {
- return setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null);
- }
-
- RecyclerView setupBasic(int itemCount, int firstLayoutStartIndex, int firstLayoutItemCount,
- TestAdapter testAdapter)
- throws Throwable {
- final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
- recyclerView.setHasFixedSize(true);
- if (testAdapter == null) {
- mTestAdapter = new TestAdapter(itemCount);
- } else {
- mTestAdapter = testAdapter;
- }
- recyclerView.setAdapter(mTestAdapter);
- mLayoutManager = new AnimationLayoutManager();
- recyclerView.setLayoutManager(mLayoutManager);
- mLayoutManager.mOnLayoutCallbacks.mLayoutMin = firstLayoutStartIndex;
- mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = firstLayoutItemCount;
-
- mLayoutManager.expectLayouts(1);
- recyclerView.expectDraw(1);
- setRecyclerView(recyclerView);
+ public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable {
+ TestAdapter adapter = new TestAdapter(10) {
+ @Override
+ public void onViewRecycled(TestViewHolder holder) {
+ super.onViewRecycled(holder);
+ recycledVHs.add(holder);
+ }
+ };
+ setupBasic(10, 0, 10, adapter);
+ mRecyclerView.setItemViewCacheSize(0);
+ TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9);
+ mRecyclerView.getItemAnimator().setAddDuration(1000);
+ mRecyclerView.getItemAnimator().setRemoveDuration(1000);
+ mRecyclerView.getItemAnimator().setChangeDuration(1000);
+ mRecyclerView.getItemAnimator().setMoveDuration(1000);
+ mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
+ mLayoutManager.expectLayouts(2);
+ adapter.deleteAndNotify(2, 1);
mLayoutManager.waitForLayout(2);
- recyclerView.waitForDraw(1);
- mLayoutManager.mOnLayoutCallbacks.reset();
- getInstrumentation().waitForIdleSync();
- assertEquals("extra layouts should not happen", 1, mLayoutManager.getTotalLayoutCount());
- assertEquals("all expected children should be laid out", firstLayoutItemCount,
- mLayoutManager.getChildCount());
- return recyclerView;
+ // test sanity, make sure target is hidden now
+ assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView));
+ callback.postSetup(recycledVHs, target);
+ // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN
+ // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED
+ // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION
+
}
public void testDetachBeforeAnimations() throws Throwable {
@@ -133,7 +381,7 @@
mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
- RecyclerView.State state) {
+ RecyclerView.State state) {
if (view == targetChild[0]) {
outRect.set(10, 20, 30, 40);
} else {
@@ -287,7 +535,6 @@
mLayoutManager.waitForLayout(2);
-
}
public void testAddRemoveSamePass() throws Throwable {
@@ -379,7 +626,11 @@
assertTrue("added-removed view should be recycled", found);
}
- public void testChangeAnimations() throws Throwable {
+ public void testTmpRemoveMe() throws Throwable {
+ changeAnimTest(false, false, true, false);
+ }
+
+ public void testChangeAnimations() throws Throwable {
final boolean[] booleans = {true, false};
for (boolean supportsChange : booleans) {
for (boolean changeType : booleans) {
@@ -392,15 +643,16 @@
}
}
}
+
public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType,
- final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable {
+ final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable {
final int changedIndex = 3;
final int defaultType = 1;
final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType);
final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim +
", change view type:" + changeType +
", has stable ids:" + hasStableIds +
- ", force predictive:" + deleteSomeItems;
+ ", delete some items:" + deleteSomeItems;
TestAdapter testAdapter = new TestAdapter(10) {
@Override
public int getItemViewType(int position) {
@@ -428,7 +680,8 @@
};
testAdapter.setHasStableIds(hasStableIds);
setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
- mRecyclerView.getItemAnimator().setSupportsChangeAnimations(supportsChangeAnim);
+ ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
+ supportsChangeAnim);
final RecyclerView.ViewHolder toBeChangedVH =
mRecyclerView.findViewHolderForLayoutPosition(changedIndex);
@@ -439,13 +692,8 @@
RecyclerView.State state) {
RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
changedIndex);
- if (supportsChangeAnim) {
- assertTrue(logPrefix + " changed view holder should have correct flag"
- , vh.isChanged());
- } else {
- assertFalse(logPrefix + " changed view holder should have correct flag"
- , vh.isChanged());
- }
+ assertTrue(logPrefix + " changed view holder should have correct flag"
+ , vh.isUpdated());
}
@Override
@@ -453,7 +701,6 @@
AnimationLayoutManager layoutManager, RecyclerView.State state) {
RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
changedIndex);
- assertFalse(logPrefix + "VH should not be marked as changed", vh.isChanged());
if (supportsChangeAnim) {
assertNotSame(logPrefix + "a new VH should be given if change is supported",
toBeChangedVH, vh);
@@ -482,7 +729,7 @@
}
});
} else {
- mTestAdapter.notifyItemChanged(3);
+ mTestAdapter.changeAndNotify(3, 1);
}
mLayoutManager.waitForLayout(2);
@@ -492,7 +739,7 @@
if (list1.size() != list2.size()) {
return false;
}
- for (int i= 0; i < list1.size(); i++) {
+ for (int i = 0; i < list1.size(); i++) {
if (!list1.get(i).equals(list2.get(i))) {
return false;
}
@@ -501,8 +748,8 @@
}
private void testChangeWithPayload(final boolean supportsChangeAnim,
- Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind)
- throws Throwable {
+ Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind)
+ throws Throwable {
final List<Object> expectedPayloads = new ArrayList<Object>();
final int changedIndex = 3;
TestAdapter testAdapter = new TestAdapter(10) {
@@ -533,10 +780,11 @@
};
testAdapter.setHasStableIds(false);
setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
- mRecyclerView.getItemAnimator().setSupportsChangeAnimations(supportsChangeAnim);
+ ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
+ supportsChangeAnim);
int numTests = notifyPayloads.length;
- for (int i= 0; i < numTests; i++) {
+ for (int i = 0; i < numTests; i++) {
mLayoutManager.expectLayouts(1);
expectedPayloads.clear();
for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) {
@@ -552,45 +800,46 @@
}
});
mLayoutManager.waitForLayout(2);
+ checkForMainThreadException();
}
}
- public void testCrossFadingChangeAnimationWithPayload() throws Throwable {
+ public void testCrossFadingChangeAnimationWithPayload() throws Throwable {
// for crossfading change animation, will receive EMPTY payload in onBindViewHolder
testChangeWithPayload(true,
new Object[][]{
- new Object[]{"abc"},
- new Object[]{"abc", null, "cdf"},
- new Object[]{"abc", null},
- new Object[]{null, "abc"},
- new Object[]{"abc", "cdf"}
+ new Object[]{"abc"},
+ new Object[]{"abc", null, "cdf"},
+ new Object[]{"abc", null},
+ new Object[]{null, "abc"},
+ new Object[]{"abc", "cdf"}
},
new Object[][]{
- new Object[0],
- new Object[0],
- new Object[0],
- new Object[0],
- new Object[0]
+ new Object[0],
+ new Object[0],
+ new Object[0],
+ new Object[0],
+ new Object[0]
});
}
- public void testNoChangeAnimationWithPayload() throws Throwable {
+ public void testNoChangeAnimationWithPayload() throws Throwable {
// for Change Animation disabled, payload should match the payloads unless
// null payload is fired.
testChangeWithPayload(false,
new Object[][]{
- new Object[]{"abc"},
- new Object[]{"abc", null, "cdf"},
- new Object[]{"abc", null},
- new Object[]{null, "abc"},
- new Object[]{"abc", "cdf"}
+ new Object[]{"abc"},
+ new Object[]{"abc", null, "cdf"},
+ new Object[]{"abc", null},
+ new Object[]{null, "abc"},
+ new Object[]{"abc", "cdf"}
},
new Object[][]{
- new Object[]{"abc"},
- new Object[0],
- new Object[0],
- new Object[0],
- new Object[]{"abc", "cdf"}
+ new Object[]{"abc"},
+ new Object[0],
+ new Object[0],
+ new Object[0],
+ new Object[]{"abc", "cdf"}
});
}
@@ -626,7 +875,7 @@
});
// now keep adding children to trigger more children being created etc.
- for (int i = 0; i < 100; i ++) {
+ for (int i = 0; i < 100; i++) {
adapter.addAndNotify(15, 1);
Thread.sleep(50);
}
@@ -674,19 +923,19 @@
adapter.setHasStableIds(true);
initialSet.addAll(adapter.mItems);
positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() {
- @Override
- void onRun(TestAdapter testAdapter) throws Throwable {
- Item item5 = adapter.mItems.get(5);
- Item item6 = adapter.mItems.get(6);
- item5.mAdapterIndex = 6;
- item6.mAdapterIndex = 5;
- adapter.mItems.remove(5);
- adapter.mItems.add(6, item5);
- adapter.dispatchDataSetChanged();
- //hacky, we support only 1 layout pass
- mLayoutManager.layoutLatch.countDown();
- }
- }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
+ @Override
+ void onRun(TestAdapter testAdapter) throws Throwable {
+ Item item5 = adapter.mItems.get(5);
+ Item item6 = adapter.mItems.get(6);
+ item5.mAdapterIndex = 6;
+ item6.mAdapterIndex = 5;
+ adapter.mItems.remove(5);
+ adapter.mItems.add(6, item5);
+ adapter.dispatchDataSetChanged();
+ //hacky, we support only 1 layout pass
+ mLayoutManager.layoutLatch.countDown();
+ }
+ }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8),
PositionConstraint.scrap(9, -1, 9));
// now mix items.
@@ -738,7 +987,7 @@
itemViewTypeQueries.contains(i));
if (adapter.hasStableIds()) {
assertTrue("getItemId for existing item " + i
- + " should be called when adapter has stable ids",
+ + " should be called when adapter has stable ids",
itemIdQueries.contains(i));
}
}
@@ -779,13 +1028,17 @@
// try to trigger race conditions
int targetItemCount = mTestAdapter.getItemCount();
for (int i = 0; i < 100; i++) {
+ checkForMainThreadException();
mTestAdapter.addAndNotify(0, 1);
+ checkForMainThreadException();
mTestAdapter.addAndNotify(7, 1);
targetItemCount += 2;
}
+ checkForMainThreadException();
// wait until main thread runnables are consumed
while (targetItemCount != mTestAdapter.getItemCount()) {
Thread.sleep(100);
+ checkForMainThreadException();
}
mLayoutManager.waitForLayout(2);
}
@@ -990,10 +1243,6 @@
8, mRecyclerView.getChildCount());
}
- public TestRecyclerView getTestRecyclerView() {
- return (TestRecyclerView) mRecyclerView;
- }
-
public void testRemoveScrapInvalidate() throws Throwable {
setupBasic(10);
TestRecyclerView testRecyclerView = getTestRecyclerView();
@@ -1035,11 +1284,14 @@
runTestOnUiThread(new Runnable() {
@Override
public void run() {
- // [0,1,2,3,4]
- // delete 1
- mTestAdapter.notifyItemRangeRemoved(1, 1);
- // delete 3
- mTestAdapter.notifyItemRangeRemoved(2, 1);
+ try {
+ // delete 1
+ mTestAdapter.deleteAndNotify(1, 1);
+ // delete 3
+ mTestAdapter.deleteAndNotify(2, 1);
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
}
});
mLayoutManager.waitForLayout(2);
@@ -1092,35 +1344,35 @@
public void testAddDelete2() throws Throwable {
positionStatesTest(5, 0, 5, new AdapterOps() {
- // 0 1 2 3 4
- // 0 1 2 a b 3 4
- // 0 1 b 3 4
- // pre: 0 1 2 3 4
- // pre w/ adap: 0 1 2 b 3 4
- @Override
- void onRun(TestAdapter adapter) throws Throwable {
- adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
- }
- }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
+ // 0 1 2 3 4
+ // 0 1 2 a b 3 4
+ // 0 1 b 3 4
+ // pre: 0 1 2 3 4
+ // pre w/ adap: 0 1 2 b 3 4
+ @Override
+ void onRun(TestAdapter adapter) throws Throwable {
+ adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
+ }
+ }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
PositionConstraint.scrap(3, 3, 3)
);
}
public void testAddDelete1() throws Throwable {
positionStatesTest(5, 0, 5, new AdapterOps() {
- // 0 1 2 3 4
- // 0 1 2 a b 3 4
- // 0 2 a b 3 4
- // 0 c d 2 a b 3 4
- // 0 c d 2 a 4
- // c d 2 a 4
- // pre: 0 1 2 3 4
- @Override
- void onRun(TestAdapter adapter) throws Throwable {
- adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
- new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
- }
- }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
+ // 0 1 2 3 4
+ // 0 1 2 a b 3 4
+ // 0 2 a b 3 4
+ // 0 c d 2 a b 3 4
+ // 0 c d 2 a 4
+ // c d 2 a 4
+ // pre: 0 1 2 3 4
+ @Override
+ void onRun(TestAdapter adapter) throws Throwable {
+ adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
+ new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
+ }
+ }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1),
PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0),
PositionConstraint.adapter(1), PositionConstraint.adapter(3)
@@ -1129,12 +1381,12 @@
public void testAddSameIndexTwice() throws Throwable {
positionStatesTest(12, 2, 7, new AdapterOps() {
- @Override
- void onRun(TestAdapter adapter) throws Throwable {
- adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
- new int[]{11, 1});
- }
- }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
+ @Override
+ void onRun(TestAdapter adapter) throws Throwable {
+ adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
+ new int[]{11, 1});
+ }
+ }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7),
PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12),
PositionConstraint.scrap(8, 8, 13)
@@ -1143,12 +1395,12 @@
public void testDeleteTwice() throws Throwable {
positionStatesTest(12, 2, 7, new AdapterOps() {
- @Override
- void onRun(TestAdapter adapter) throws Throwable {
- adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
- new int[]{0, 1});// delete item ids 0,2,9,1
- }
- }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
+ @Override
+ void onRun(TestAdapter adapter) throws Throwable {
+ adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
+ new int[]{0, 1});// delete item ids 0,2,9,1
+ }
+ }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2),
PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5),
PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7)
@@ -1160,10 +1412,11 @@
int firstLayoutItemCount, AdapterOps adapterChanges,
final PositionConstraint... constraints) throws Throwable {
positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null,
- adapterChanges, constraints);
+ adapterChanges, constraints);
}
+
public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
- int firstLayoutItemCount,TestAdapter adapter, AdapterOps adapterChanges,
+ int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges,
final PositionConstraint... constraints) throws Throwable {
setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter);
mLayoutManager.expectLayouts(2);
@@ -1180,10 +1433,15 @@
}
Map<Integer, CollectPositionResult> positions
= collectPositions(lm.mRecyclerView, recycler, state, ids);
+ StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
+ for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
+ positionLog.append(entry.getKey()).append(":").append(entry.getValue())
+ .append("\n");
+ }
for (PositionConstraint constraint : constraints) {
if (constraint.mPreLayoutPos != -1) {
constraint.validate(state, positions.get(constraint.mPreLayoutPos),
- lm.getLog());
+ lm.getLog() + positionLog);
}
}
}
@@ -1199,10 +1457,15 @@
}
Map<Integer, CollectPositionResult> positions
= collectPositions(lm.mRecyclerView, recycler, state, ids);
+ StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
+ for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
+ positionLog.append(entry.getKey()).append(":")
+ .append(entry.getValue()).append("\n");
+ }
for (PositionConstraint constraint : constraints) {
if (constraint.mPostLayoutPos >= 0) {
constraint.validate(state, positions.get(constraint.mPostLayoutPos),
- lm.getLog());
+ lm.getLog() + positionLog);
}
}
}
@@ -1218,7 +1481,8 @@
public void testAddThenRecycleRemovedView() throws Throwable {
setupBasic(10);
final AtomicInteger step = new AtomicInteger(0);
- final List<RecyclerView.ViewHolder> animateRemoveList = new ArrayList<RecyclerView.ViewHolder>();
+ final List<RecyclerView.ViewHolder> animateRemoveList
+ = new ArrayList<RecyclerView.ViewHolder>();
DefaultItemAnimator animator = new DefaultItemAnimator() {
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
@@ -1264,530 +1528,4 @@
assertTrue("since LM force recycled a view, animate disappearance should not be called",
animateRemoveList.isEmpty());
}
-
- class AnimationLayoutManager extends TestLayoutManager {
-
- private int mTotalLayoutCount = 0;
- private String log;
-
- OnLayoutCallbacks mOnLayoutCallbacks = new OnLayoutCallbacks() {
- };
-
-
-
- @Override
- public boolean supportsPredictiveItemAnimations() {
- return true;
- }
-
- public String getLog() {
- return log;
- }
-
- private String prepareLog(RecyclerView.Recycler recycler, RecyclerView.State state, boolean done) {
- StringBuilder builder = new StringBuilder();
- builder.append("is pre layout:").append(state.isPreLayout()).append(", done:").append(done);
- builder.append("\nViewHolders:\n");
- for (RecyclerView.ViewHolder vh : ((TestRecyclerView)mRecyclerView).collectViewHolders()) {
- builder.append(vh).append("\n");
- }
- builder.append("scrap:\n");
- for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
- builder.append(vh).append("\n");
- }
-
- if (state.isPreLayout() && !done) {
- log = "\n" + builder.toString();
- } else {
- log += "\n" + builder.toString();
- }
- return log;
- }
-
- @Override
- public void expectLayouts(int count) {
- super.expectLayouts(count);
- mOnLayoutCallbacks.mLayoutCount = 0;
- }
-
- public void setOnLayoutCallbacks(OnLayoutCallbacks onLayoutCallbacks) {
- mOnLayoutCallbacks = onLayoutCallbacks;
- }
-
- @Override
- public final void onLayoutChildren(RecyclerView.Recycler recycler,
- RecyclerView.State state) {
- try {
- mTotalLayoutCount++;
- prepareLog(recycler, state, false);
- if (state.isPreLayout()) {
- validateOldPositions(recycler, state);
- } else {
- validateClearedOldPositions(recycler, state);
- }
- mOnLayoutCallbacks.onLayoutChildren(recycler, this, state);
- prepareLog(recycler, state, true);
- } finally {
- layoutLatch.countDown();
- }
- }
-
- private void validateClearedOldPositions(RecyclerView.Recycler recycler,
- RecyclerView.State state) {
- if (getTestRecyclerView() == null) {
- return;
- }
- for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
- assertEquals("there should NOT be an old position in post layout",
- RecyclerView.NO_POSITION, viewHolder.mOldPosition);
- assertEquals("there should NOT be a pre layout position in post layout",
- RecyclerView.NO_POSITION, viewHolder.mPreLayoutPosition);
- }
- }
-
- private void validateOldPositions(RecyclerView.Recycler recycler,
- RecyclerView.State state) {
- if (getTestRecyclerView() == null) {
- return;
- }
- for (RecyclerView.ViewHolder viewHolder : getTestRecyclerView().collectViewHolders()) {
- if (!viewHolder.isRemoved() && !viewHolder.isInvalid()) {
- assertTrue("there should be an old position in pre-layout",
- viewHolder.mOldPosition != RecyclerView.NO_POSITION);
- }
- }
- }
-
- public int getTotalLayoutCount() {
- return mTotalLayoutCount;
- }
-
- @Override
- public boolean canScrollVertically() {
- return true;
- }
-
- @Override
- public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
- RecyclerView.State state) {
- mOnLayoutCallbacks.onScroll(dy, recycler, state);
- return super.scrollVerticallyBy(dy, recycler, state);
- }
-
- public void onPostDispatchLayout() {
- mOnLayoutCallbacks.postDispatchLayout();
- }
-
- @Override
- public void waitForLayout(long timeout, TimeUnit timeUnit) throws Throwable {
- super.waitForLayout(timeout, timeUnit);
- checkForMainThreadException();
- }
- }
-
- abstract class OnLayoutCallbacks {
-
- int mLayoutMin = Integer.MIN_VALUE;
-
- int mLayoutItemCount = Integer.MAX_VALUE;
-
- int expectedPreLayoutItemCount = -1;
-
- int expectedPostLayoutItemCount = -1;
-
- int mDeletedViewCount;
-
- int mLayoutCount = 0;
-
- void setExpectedItemCounts(int preLayout, int postLayout) {
- expectedPreLayoutItemCount = preLayout;
- expectedPostLayoutItemCount = postLayout;
- }
-
- void reset() {
- mLayoutMin = Integer.MIN_VALUE;
- mLayoutItemCount = Integer.MAX_VALUE;
- expectedPreLayoutItemCount = -1;
- expectedPostLayoutItemCount = -1;
- mLayoutCount = 0;
- }
-
- void beforePreLayout(RecyclerView.Recycler recycler,
- AnimationLayoutManager lm, RecyclerView.State state) {
- mDeletedViewCount = 0;
- for (int i = 0; i < lm.getChildCount(); i++) {
- View v = lm.getChildAt(i);
- if (lm.getLp(v).isItemRemoved()) {
- mDeletedViewCount++;
- }
- }
- }
-
- void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
- RecyclerView.State state) {
- if (DEBUG) {
- Log.d(TAG, "item count " + state.getItemCount());
- }
- lm.detachAndScrapAttachedViews(recycler);
- final int start = mLayoutMin == Integer.MIN_VALUE ? 0 : mLayoutMin;
- final int count = mLayoutItemCount
- == Integer.MAX_VALUE ? state.getItemCount() : mLayoutItemCount;
- lm.layoutRange(recycler, start, start + count);
- assertEquals("correct # of children should be laid out",
- count, lm.getChildCount());
- lm.assertVisibleItemPositions();
- }
-
- private void assertNoPreLayoutPosition(RecyclerView.Recycler recycler) {
- for (RecyclerView.ViewHolder vh : recycler.mAttachedScrap) {
- assertPreLayoutPosition(vh);
- }
- }
-
- private void assertNoPreLayoutPosition(RecyclerView.LayoutManager lm) {
- for (int i = 0; i < lm.getChildCount(); i ++) {
- final RecyclerView.ViewHolder vh = mRecyclerView
- .getChildViewHolder(lm.getChildAt(i));
- assertPreLayoutPosition(vh);
- }
- }
-
- private void assertPreLayoutPosition(RecyclerView.ViewHolder vh) {
- assertEquals("in post layout, there should not be a view holder w/ a pre "
- + "layout position", RecyclerView.NO_POSITION, vh.mPreLayoutPosition);
- assertEquals("in post layout, there should not be a view holder w/ an old "
- + "layout position", RecyclerView.NO_POSITION, vh.mOldPosition);
- }
-
- void onLayoutChildren(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
- RecyclerView.State state) {
-
- if (state.isPreLayout()) {
- if (expectedPreLayoutItemCount != -1) {
- assertEquals("on pre layout, state should return abstracted adapter size",
- expectedPreLayoutItemCount, state.getItemCount());
- }
- beforePreLayout(recycler, lm, state);
- } else {
- if (expectedPostLayoutItemCount != -1) {
- assertEquals("on post layout, state should return real adapter size",
- expectedPostLayoutItemCount, state.getItemCount());
- }
- beforePostLayout(recycler, lm, state);
- }
- if (!state.isPreLayout()) {
- assertNoPreLayoutPosition(recycler);
- }
- doLayout(recycler, lm, state);
- if (state.isPreLayout()) {
- afterPreLayout(recycler, lm, state);
- } else {
- afterPostLayout(recycler, lm, state);
- assertNoPreLayoutPosition(lm);
- }
- mLayoutCount++;
- }
-
- void afterPreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
- RecyclerView.State state) {
- }
-
- void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
- RecyclerView.State state) {
- }
-
- void afterPostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager layoutManager,
- RecyclerView.State state) {
- }
-
- void postDispatchLayout() {
- }
-
- public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
-
- }
- }
-
- class TestRecyclerView extends RecyclerView {
-
- CountDownLatch drawLatch;
-
- public TestRecyclerView(Context context) {
- super(context);
- }
-
- public TestRecyclerView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public TestRecyclerView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- void initAdapterManager() {
- super.initAdapterManager();
- mAdapterHelper.mOnItemProcessedCallback = new Runnable() {
- @Override
- public void run() {
- validatePostUpdateOp();
- }
- };
- }
-
- @Override
- boolean isAccessibilityEnabled() {
- return true;
- }
-
- public void expectDraw(int count) {
- drawLatch = new CountDownLatch(count);
- }
-
- public void waitForDraw(long timeout) throws Throwable {
- drawLatch.await(timeout * (DEBUG ? 100 : 1), TimeUnit.SECONDS);
- assertEquals("all expected draws should happen at the expected time frame",
- 0, drawLatch.getCount());
- }
-
- List<ViewHolder> collectViewHolders() {
- List<ViewHolder> holders = new ArrayList<ViewHolder>();
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- ViewHolder holder = getChildViewHolderInt(getChildAt(i));
- if (holder != null) {
- holders.add(holder);
- }
- }
- return holders;
- }
-
-
- private void validateViewHolderPositions() {
- final Set<Integer> existingOffsets = new HashSet<Integer>();
- int childCount = getChildCount();
- StringBuilder log = new StringBuilder();
- for (int i = 0; i < childCount; i++) {
- ViewHolder vh = getChildViewHolderInt(getChildAt(i));
- TestViewHolder tvh = (TestViewHolder) vh;
- log.append(tvh.mBoundItem).append(vh)
- .append(" hidden:")
- .append(mChildHelper.mHiddenViews.contains(vh.itemView))
- .append("\n");
- }
- for (int i = 0; i < childCount; i++) {
- ViewHolder vh = getChildViewHolderInt(getChildAt(i));
- if (vh.isInvalid()) {
- continue;
- }
- if (vh.getLayoutPosition() < 0) {
- LayoutManager lm = getLayoutManager();
- for (int j = 0; j < lm.getChildCount(); j ++) {
- assertNotSame("removed view holder should not be in LM's child list",
- vh.itemView, lm.getChildAt(j));
- }
- } else if (!mChildHelper.mHiddenViews.contains(vh.itemView)) {
- if (!existingOffsets.add(vh.getLayoutPosition())) {
- throw new IllegalStateException("view holder position conflict for "
- + "existing views " + vh + "\n" + log);
- }
- }
- }
- }
-
- void validatePostUpdateOp() {
- try {
- validateViewHolderPositions();
- if (super.mState.isPreLayout()) {
- validatePreLayoutSequence((AnimationLayoutManager) getLayoutManager());
- }
- validateAdapterPosition((AnimationLayoutManager) getLayoutManager());
- } catch (Throwable t) {
- postExceptionToInstrumentation(t);
- }
- }
-
-
-
- private void validateAdapterPosition(AnimationLayoutManager lm) {
- for (ViewHolder vh : collectViewHolders()) {
- if (!vh.isRemoved() && vh.mPreLayoutPosition >= 0) {
- assertEquals("adapter position calculations should match view holder "
- + "pre layout:" + mState.isPreLayout()
- + " positions\n" + vh + "\n" + lm.getLog(),
- mAdapterHelper.findPositionOffset(vh.mPreLayoutPosition), vh.mPosition);
- }
- }
- }
-
- // ensures pre layout positions are continuous block. This is not necessarily a case
- // but valid in test RV
- private void validatePreLayoutSequence(AnimationLayoutManager lm) {
- Set<Integer> preLayoutPositions = new HashSet<Integer>();
- for (ViewHolder vh : collectViewHolders()) {
- assertTrue("pre layout positions should be distinct " + lm.getLog(),
- preLayoutPositions.add(vh.mPreLayoutPosition));
- }
- int minPos = Integer.MAX_VALUE;
- for (Integer pos : preLayoutPositions) {
- if (pos < minPos) {
- minPos = pos;
- }
- }
- for (int i = 1; i < preLayoutPositions.size(); i++) {
- assertNotNull("next position should exist " + lm.getLog(),
- preLayoutPositions.contains(minPos + i));
- }
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- if (drawLatch != null) {
- drawLatch.countDown();
- }
- }
-
- @Override
- void dispatchLayout() {
- try {
- super.dispatchLayout();
- if (getLayoutManager() instanceof AnimationLayoutManager) {
- ((AnimationLayoutManager) getLayoutManager()).onPostDispatchLayout();
- }
- } catch (Throwable t) {
- postExceptionToInstrumentation(t);
- }
-
- }
-
-
- }
-
- abstract class AdapterOps {
-
- final public void run(TestAdapter adapter) throws Throwable {
- onRun(adapter);
- }
-
- abstract void onRun(TestAdapter testAdapter) throws Throwable;
- }
-
- static class CollectPositionResult {
-
- // true if found in scrap
- public RecyclerView.ViewHolder scrapResult;
-
- public RecyclerView.ViewHolder adapterResult;
-
- static CollectPositionResult fromScrap(RecyclerView.ViewHolder viewHolder) {
- CollectPositionResult cpr = new CollectPositionResult();
- cpr.scrapResult = viewHolder;
- return cpr;
- }
-
- static CollectPositionResult fromAdapter(RecyclerView.ViewHolder viewHolder) {
- CollectPositionResult cpr = new CollectPositionResult();
- cpr.adapterResult = viewHolder;
- return cpr;
- }
- }
-
- static class PositionConstraint {
-
- public static enum Type {
- scrap,
- adapter,
- adapterScrap /*first pass adapter, second pass scrap*/
- }
-
- Type mType;
-
- int mOldPos; // if VH
-
- int mPreLayoutPos;
-
- int mPostLayoutPos;
-
- int mValidateCount = 0;
-
- public static PositionConstraint scrap(int oldPos, int preLayoutPos, int postLayoutPos) {
- PositionConstraint constraint = new PositionConstraint();
- constraint.mType = Type.scrap;
- constraint.mOldPos = oldPos;
- constraint.mPreLayoutPos = preLayoutPos;
- constraint.mPostLayoutPos = postLayoutPos;
- return constraint;
- }
-
- public static PositionConstraint adapterScrap(int preLayoutPos, int position) {
- PositionConstraint constraint = new PositionConstraint();
- constraint.mType = Type.adapterScrap;
- constraint.mOldPos = RecyclerView.NO_POSITION;
- constraint.mPreLayoutPos = preLayoutPos;
- constraint.mPostLayoutPos = position;// adapter pos does not change
- return constraint;
- }
-
- public static PositionConstraint adapter(int position) {
- PositionConstraint constraint = new PositionConstraint();
- constraint.mType = Type.adapter;
- constraint.mPreLayoutPos = RecyclerView.NO_POSITION;
- constraint.mOldPos = RecyclerView.NO_POSITION;
- constraint.mPostLayoutPos = position;// adapter pos does not change
- return constraint;
- }
-
- public void assertValidate() {
- int expectedValidate = 0;
- if (mPreLayoutPos >= 0) {
- expectedValidate ++;
- }
- if (mPostLayoutPos >= 0) {
- expectedValidate ++;
- }
- assertEquals("should run all validates", expectedValidate, mValidateCount);
- }
-
- @Override
- public String toString() {
- return "Cons{" +
- "t=" + mType.name() +
- ", old=" + mOldPos +
- ", pre=" + mPreLayoutPos +
- ", post=" + mPostLayoutPos +
- '}';
- }
-
- public void validate(RecyclerView.State state, CollectPositionResult result, String log) {
- mValidateCount ++;
- assertNotNull(this + ": result should not be null\n" + log, result);
- RecyclerView.ViewHolder viewHolder;
- if (mType == Type.scrap || (mType == Type.adapterScrap && !state.isPreLayout())) {
- assertNotNull(this + ": result should come from scrap\n" + log, result.scrapResult);
- viewHolder = result.scrapResult;
- } else {
- assertNotNull(this + ": result should come from adapter\n" + log,
- result.adapterResult);
- assertEquals(this + ": old position should be none when it came from adapter\n" + log,
- RecyclerView.NO_POSITION, result.adapterResult.getOldPosition());
- viewHolder = result.adapterResult;
- }
- if (state.isPreLayout()) {
- assertEquals(this + ": pre-layout position should match\n" + log, mPreLayoutPos,
- viewHolder.mPreLayoutPosition == -1 ? viewHolder.mPosition :
- viewHolder.mPreLayoutPosition);
- assertEquals(this + ": pre-layout getPosition should match\n" + log, mPreLayoutPos,
- viewHolder.getLayoutPosition());
- if (mType == Type.scrap) {
- assertEquals(this + ": old position should match\n" + log, mOldPos,
- result.scrapResult.getOldPosition());
- }
- } else if (mType == Type.adapter || mType == Type.adapterScrap || !result.scrapResult
- .isRemoved()) {
- assertEquals(this + ": post-layout position should match\n" + log + "\n\n"
- + viewHolder, mPostLayoutPos, viewHolder.getLayoutPosition());
- }
- }
- }
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index 366758a..6fb9592 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -28,7 +28,6 @@
import android.graphics.Rect;
import android.os.SystemClock;
import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.RecyclerView;
import android.test.TouchUtils;
import android.util.Log;
import android.view.Gravity;
@@ -62,7 +61,7 @@
private static final int FLAG_VERTICAL = 1 << 1;
private static final int FLAG_FLING = 1 << 2;
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final String TAG = "RecyclerViewLayoutTest";
@@ -174,9 +173,9 @@
}
@Test
- public void testFocusSearchFailFrozen() throws Throwable {
+ public void testFocusSearchFailFrozen() throws Throwable {
RecyclerView recyclerView = new RecyclerView(getActivity());
-
+ final CountDownLatch focusLatch = new CountDownLatch(1);
final AtomicInteger focusSearchCalled = new AtomicInteger(0);
TestLayoutManager tlm = new TestLayoutManager() {
@Override
@@ -196,9 +195,10 @@
}
@Override
- public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
- RecyclerView.State state) {
+ public View onFocusSearchFailed(View focused, int direction,
+ RecyclerView.Recycler recycler, RecyclerView.State state) {
focusSearchCalled.addAndGet(1);
+ focusLatch.countDown();
return null;
}
};
@@ -217,14 +217,13 @@
}
});
assertTrue(c.hasFocus());
-
freezeLayout(true);
sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
assertEquals("onFocusSearchFailed should not be called when layout is frozen",
0, focusSearchCalled.get());
-
freezeLayout(false);
sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertTrue(focusLatch.await(2, TimeUnit.SECONDS));
assertEquals(1, focusSearchCalled.get());
}
@@ -1214,6 +1213,7 @@
TestLayoutManager lm = new TestLayoutManager() {
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+ ViewInfoStore infoStore = mRecyclerView.mViewInfoStore;
if (test.get()) {
try {
detachAndScrapAttachedViews(recycler);
@@ -1225,25 +1225,26 @@
recycler);
}
}
- if (state.mOldChangedHolders != null) {
- for (int i = state.mOldChangedHolders.size() - 1; i >= 0; i--) {
+ if (infoStore.mOldChangedHolders != null) {
+ for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) {
if (useRecycler) {
recycler.recycleView(
- state.mOldChangedHolders.valueAt(i).itemView);
+ infoStore.mOldChangedHolders.valueAt(i).itemView);
} else {
removeAndRecycleView(
- state.mOldChangedHolders.valueAt(i).itemView, recycler);
+ infoStore.mOldChangedHolders.valueAt(i).itemView,
+ recycler);
}
}
}
assertEquals("no scrap should be left over", 0, recycler.getScrapCount());
assertEquals("pre layout map should be empty", 0,
- state.mPreLayoutHolderMap.size());
+ InfoStoreTrojan.sizeOfPreLayout(infoStore));
assertEquals("post layout map should be empty", 0,
- state.mPostLayoutHolderMap.size());
- if (state.mOldChangedHolders != null) {
+ InfoStoreTrojan.sizeOfPostLayout(infoStore));
+ if (infoStore.mOldChangedHolders != null) {
assertEquals("post old change map should be empty", 0,
- state.mOldChangedHolders.size());
+ infoStore.mOldChangedHolders.size());
}
} catch (Throwable t) {
postExceptionToInstrumentation(t);
@@ -1258,7 +1259,7 @@
RecyclerView recyclerView = new RecyclerView(getActivity());
recyclerView.setAdapter(testAdapter);
recyclerView.setLayoutManager(lm);
- recyclerView.getItemAnimator().setSupportsChangeAnimations(true);
+ ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true);
lm.expectLayouts(1);
setRecyclerView(recyclerView);
lm.waitForLayout(2);
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java b/v7/recyclerview/tests/src/android/support/v7/widget/ViewInfoStoreTest.java
similarity index 60%
copy from v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
copy to v7/recyclerview/tests/src/android/support/v7/widget/ViewInfoStoreTest.java
index 8eea38d..4c78e3d 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintInfo.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/ViewInfoStoreTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -13,18 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.support.v7.widget;
-package android.support.v7.internal.widget;
+public class ViewInfoStoreTest {
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-
-/**
- * @hide
- */
-public class TintInfo {
- public ColorStateList mTintList;
- public PorterDuff.Mode mTintMode;
- public boolean mHasTintMode;
- public boolean mHasTintList;
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
index dfa2974..c2fac6e 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
@@ -17,7 +17,6 @@
package android.support.v7.widget.helper;
import android.app.Instrumentation;
-import android.os.Debug;
import android.os.SystemClock;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java
index f722314..6565e6f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java
@@ -20,7 +20,9 @@
import android.support.v7.recyclerview.test.CustomLayoutManager;
import android.support.v7.recyclerview.test.R;
import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
import android.test.ActivityInstrumentationTestCase2;
import android.widget.LinearLayout;
@@ -40,6 +42,14 @@
});
}
+ public void testSavedStateAccess() throws ClassNotFoundException {
+ // this class should be accessible outside RecyclerView package
+ assertNotNull(RecyclerView.SavedState.class);
+ assertNotNull(LinearLayoutManager.SavedState.class);
+ assertNotNull(GridLayoutManager.SavedState.class);
+ assertNotNull(StaggeredGridLayoutManager.SavedState.class);
+ }
+
public void testInflation() throws Throwable {
setContentView(R.layout.inflation_test);
getInstrumentation().waitForIdleSync();
diff --git a/v8/renderscript/api/23.txt b/v8/renderscript/api/23.0.0.txt
similarity index 100%
rename from v8/renderscript/api/23.txt
rename to v8/renderscript/api/23.0.0.txt
diff --git a/v8/renderscript/api/23.txt b/v8/renderscript/api/23.1.0.txt
similarity index 100%
copy from v8/renderscript/api/23.txt
copy to v8/renderscript/api/23.1.0.txt