Merge "MediaBrowserServiceCompat: Make SubscriptionCallback.onError be called" into nyc-support-25.2-dev
diff --git a/api/current.txt b/api/current.txt
index 917fd00..bc0e500 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2259,6 +2259,7 @@
method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
method public android.graphics.drawable.Drawable getBadgeDrawable();
method public android.content.Intent getRecognizerIntent();
+ method public android.support.v17.leanback.app.RowsFragment getRowsFragment();
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);
@@ -2288,6 +2289,7 @@
method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
method public android.graphics.drawable.Drawable getBadgeDrawable();
method public android.content.Intent getRecognizerIntent();
+ method public android.support.v17.leanback.app.RowsSupportFragment getRowsSupportFragment();
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);
diff --git a/design/build.gradle b/design/build.gradle
index 37e6625..d5f83b8 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -73,6 +73,12 @@
aaptOptions {
additionalParameters "--no-version-vectors"
}
+
+ buildTypes {
+ debug {
+ pseudoLocalesEnabled true
+ }
+ }
}
android.libraryVariants.all { variant ->
diff --git a/design/res/values/password_visibility.xml b/design/res/values/password_visibility.xml
index 23faec3..1c85c1a 100644
--- a/design/res/values/password_visibility.xml
+++ b/design/res/values/password_visibility.xml
@@ -18,10 +18,10 @@
<resources>
<!-- Resources used in the password visibility anim, see @drawable/design_password_eye -->
- <string name="path_password_eye_mask_visible">M2,4.27 L2,4.27 L4.54,1.73 L4.54,1.73 L4.54,1 L23,1 L23,23 L1,23 L1,4.27 Z</string>
- <string name="path_password_eye_mask_strike_through">M2,4.27 L19.73,22 L22.27,19.46 L4.54,1.73 L4.54,1 L23,1 L23,23 L1,23 L1,4.27 Z</string>
- <string name="path_password_eye">M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z</string>
- <string name="path_password_strike_through">M3.27,4.27 L19.74,20.74</string>
+ <string name="path_password_eye_mask_visible" translatable="false">M2,4.27 L2,4.27 L4.54,1.73 L4.54,1.73 L4.54,1 L23,1 L23,23 L1,23 L1,4.27 Z</string>
+ <string name="path_password_eye_mask_strike_through" translatable="false">M2,4.27 L19.73,22 L22.27,19.46 L4.54,1.73 L4.54,1 L23,1 L23,23 L1,23 L1,4.27 Z</string>
+ <string name="path_password_eye" translatable="false">M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z</string>
+ <string name="path_password_strike_through" translatable="false">M3.27,4.27 L19.74,20.74</string>
<integer name="show_password_duration">200</integer>
<integer name="hide_password_duration">320</integer>
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutPseudoLocaleTest.java b/design/tests/src/android/support/design/widget/TextInputLayoutPseudoLocaleTest.java
new file mode 100755
index 0000000..7189f20
--- /dev/null
+++ b/design/tests/src/android/support/design/widget/TextInputLayoutPseudoLocaleTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.typeText;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.support.design.test.R;
+import android.support.test.filters.SmallTest;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.Locale;
+
+@SmallTest
+public class TextInputLayoutPseudoLocaleTest extends
+ BaseInstrumentationTestCase<TextInputLayoutActivity> {
+
+ private static final String ORIGINAL_LANGUAGE = Locale.getDefault().getLanguage();
+ private static final String ORIGINAL_COUNTRY = Locale.getDefault().getLanguage();
+
+ @BeforeClass
+ public static void setup() {
+ // Change language to pseudo locale.
+ setLocale("ar", "XB", getContext());
+ }
+
+ public TextInputLayoutPseudoLocaleTest() {
+ super(TextInputLayoutActivity.class);
+ }
+
+ private static void setLocale(String language, String country, Context context) {
+ context = context.getApplicationContext();
+ Resources resources = context.getResources();
+ Configuration configuration = resources.getConfiguration();
+ configuration.setLocale(new Locale(language, country));
+ resources.updateConfiguration(configuration, resources.getDisplayMetrics());
+ }
+
+ @Test
+ public void testSimpleEdit() {
+ // Type some text
+ onView(withId(R.id.textinput_edittext)).perform(typeText("123"));
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ setLocale(ORIGINAL_LANGUAGE, ORIGINAL_COUNTRY, getContext());
+ }
+}
diff --git a/media-compat/tests/src/android/support/v4/media/MediaItemTest.java b/media-compat/tests/src/android/support/v4/media/MediaItemTest.java
new file mode 100644
index 0000000..bd2565f
--- /dev/null
+++ b/media-compat/tests/src/android/support/v4/media/MediaItemTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v4.media;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.v4.media.MediaBrowserCompat.MediaItem;
+
+import org.junit.Test;
+
+/**
+ * Test {@link MediaBrowserCompat.MediaItem}.
+ */
+public class MediaItemTest {
+ private static final String DESCRIPTION = "test_description";
+ private static final String MEDIA_ID = "test_media_id";
+ private static final String TITLE = "test_title";
+ private static final String SUBTITLE = "test_subtitle";
+
+ @Test
+ @SmallTest
+ public void testBrowsableMediaItem() {
+ MediaDescriptionCompat description =
+ new MediaDescriptionCompat.Builder()
+ .setDescription(DESCRIPTION)
+ .setMediaId(MEDIA_ID)
+ .setTitle(TITLE)
+ .setSubtitle(SUBTITLE)
+ .build();
+ MediaItem mediaItem = new MediaItem(description, MediaItem.FLAG_BROWSABLE);
+
+ assertEquals(description.toString(), mediaItem.getDescription().toString());
+ assertEquals(MEDIA_ID, mediaItem.getMediaId());
+ assertEquals(MediaItem.FLAG_BROWSABLE, mediaItem.getFlags());
+ assertTrue(mediaItem.isBrowsable());
+ assertFalse(mediaItem.isPlayable());
+ assertEquals(0, mediaItem.describeContents());
+
+ // Test writeToParcel
+ Parcel p = Parcel.obtain();
+ mediaItem.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ assertEquals(mediaItem.getFlags(), p.readInt());
+ assertEquals(
+ description.toString(),
+ MediaDescriptionCompat.CREATOR.createFromParcel(p).toString());
+ p.recycle();
+ }
+
+ @Test
+ @SmallTest
+ public void testPlayableMediaItem() {
+ MediaDescriptionCompat description = new MediaDescriptionCompat.Builder()
+ .setDescription(DESCRIPTION)
+ .setMediaId(MEDIA_ID)
+ .setTitle(TITLE)
+ .setSubtitle(SUBTITLE)
+ .build();
+ MediaItem mediaItem = new MediaItem(description, MediaItem.FLAG_PLAYABLE);
+
+ assertEquals(description.toString(), mediaItem.getDescription().toString());
+ assertEquals(MEDIA_ID, mediaItem.getMediaId());
+ assertEquals(MediaItem.FLAG_PLAYABLE, mediaItem.getFlags());
+ assertFalse(mediaItem.isBrowsable());
+ assertTrue(mediaItem.isPlayable());
+ assertEquals(0, mediaItem.describeContents());
+
+ // Test writeToParcel
+ Parcel p = Parcel.obtain();
+ mediaItem.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ assertEquals(mediaItem.getFlags(), p.readInt());
+ assertEquals(
+ description.toString(),
+ MediaDescriptionCompat.CREATOR.createFromParcel(p).toString());
+ p.recycle();
+ }
+}
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/BrowseFragment.java b/samples/Support4Demos/src/com/example/android/supportv4/media/BrowseFragment.java
index 9fac4ab..d23ce05 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/BrowseFragment.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/BrowseFragment.java
@@ -38,7 +38,9 @@
import com.example.android.supportv4.R;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* A Fragment that lists all the various browsable queues available
@@ -66,6 +68,7 @@
private final List<MediaBrowserCompat.MediaItem> mMediaItems = new ArrayList<>();
private boolean mCanLoadNewPage;
+ private final Set<Integer> mSubscribedPages = new HashSet<Integer>();
private MediaBrowserCompat mMediaBrowser;
private BrowseAdapter mBrowserAdapter;
@@ -234,9 +237,15 @@
public void onStop() {
super.onStop();
mMediaBrowser.disconnect();
+ mSubscribedPages.clear();
}
private void loadPage(int page) {
+ Integer pageInteger = Integer.valueOf(page);
+ if (mSubscribedPages.contains(pageInteger)) {
+ return;
+ }
+ mSubscribedPages.add(pageInteger);
Bundle options = new Bundle();
options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, PAGE_SIZE);
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 d2b9bb1..d65937c 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
@@ -417,6 +417,16 @@
super.onDestroy();
}
+ /**
+ * Returns RowsFragment that shows result rows. RowsFragment is initialized after
+ * SearchFragment.onCreateView().
+ *
+ * @return RowsFragment that shows result rows.
+ */
+ public RowsFragment getRowsFragment() {
+ return mRowsFragment;
+ }
+
private void releaseRecognizer() {
if (null != mSpeechRecognizer) {
mSearchBar.setSpeechRecognizer(null);
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 b870d79..ae4c700 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
@@ -420,6 +420,16 @@
super.onDestroy();
}
+ /**
+ * Returns RowsSupportFragment that shows result rows. RowsSupportFragment is initialized after
+ * SearchSupportFragment.onCreateView().
+ *
+ * @return RowsSupportFragment that shows result rows.
+ */
+ public RowsSupportFragment getRowsSupportFragment() {
+ return mRowsSupportFragment;
+ }
+
private void releaseRecognizer() {
if (null != mSpeechRecognizer) {
mSearchBar.setSpeechRecognizer(null);
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
index 150a3fd..2da193b 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
@@ -492,37 +492,42 @@
}
void refreshRoute() {
+ final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
+ final boolean isRemote = !route.isDefaultOrBluetooth() && route.matchesSelector(mSelector);
+ final boolean isConnecting = isRemote && route.isConnecting();
+ boolean needsRefresh = false;
+ if (mRemoteActive != isRemote) {
+ mRemoteActive = isRemote;
+ needsRefresh = true;
+ }
+ if (mIsConnecting != isConnecting) {
+ mIsConnecting = isConnecting;
+ needsRefresh = true;
+ }
+
+ if (needsRefresh) {
+ updateContentDescription();
+ refreshDrawableState();
+ }
if (mAttachedToWindow) {
- final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
- final boolean isRemote = !route.isDefaultOrBluetooth()
- && route.matchesSelector(mSelector);
- final boolean isConnecting = isRemote && route.isConnecting();
-
- boolean needsRefresh = false;
- if (mRemoteActive != isRemote) {
- mRemoteActive = isRemote;
- needsRefresh = true;
- }
- if (mIsConnecting != isConnecting) {
- mIsConnecting = isConnecting;
- needsRefresh = true;
- }
-
- if (needsRefresh) {
- updateContentDescription();
- refreshDrawableState();
- if (mRemoteIndicator.getCurrent() instanceof AnimationDrawable) {
- AnimationDrawable curDrawable =
- (AnimationDrawable) mRemoteIndicator.getCurrent();
- if (!curDrawable.isRunning()) {
- curDrawable.start();
- }
- }
- }
-
setEnabled(mRouter.isRouteAvailable(mSelector,
MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
}
+ if (mRemoteIndicator.getCurrent() instanceof AnimationDrawable) {
+ AnimationDrawable curDrawable = (AnimationDrawable) mRemoteIndicator.getCurrent();
+ if (mAttachedToWindow) {
+ if ((needsRefresh || isConnecting) && !curDrawable.isRunning()) {
+ curDrawable.start();
+ }
+ } else if (isRemote && !isConnecting) {
+ // When the route is already connected before the view is attached, show the last
+ // frame of the connected animation immediately.
+ if (curDrawable.isRunning()) {
+ curDrawable.stop();
+ }
+ curDrawable.selectDrawable(curDrawable.getNumberOfFrames() - 1);
+ }
+ }
}
private void updateContentDescription() {