Merge "Set version to alpha 7." into oc-support-26.0-dev
diff --git a/app-toolkit/common/src/main/java/android/arch/core/internal/FastSafeIterableMap.java b/app-toolkit/common/src/main/java/android/arch/core/internal/FastSafeIterableMap.java
index f8739f6..dbd4d5f 100644
--- a/app-toolkit/common/src/main/java/android/arch/core/internal/FastSafeIterableMap.java
+++ b/app-toolkit/common/src/main/java/android/arch/core/internal/FastSafeIterableMap.java
@@ -51,6 +51,13 @@
return null;
}
+ @Override
+ public V remove(@NonNull K key) {
+ V removed = super.remove(key);
+ mHashMap.remove(key);
+ return removed;
+ }
+
/**
* Returns {@code true} if this map contains a mapping for the specified
* key.
diff --git a/app-toolkit/common/src/test/java/android/arch/core/internal/FastSafeIterableMapTest.java b/app-toolkit/common/src/test/java/android/arch/core/internal/FastSafeIterableMapTest.java
index a55b939..41b1497 100644
--- a/app-toolkit/common/src/test/java/android/arch/core/internal/FastSafeIterableMapTest.java
+++ b/app-toolkit/common/src/test/java/android/arch/core/internal/FastSafeIterableMapTest.java
@@ -20,9 +20,11 @@
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
-import org.hamcrest.MatcherAssert;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+@RunWith(JUnit4.class)
public class FastSafeIterableMapTest {
@Test
public void testCeil() {
@@ -42,8 +44,8 @@
map.putIfAbsent(10, 20);
map.putIfAbsent(20, 40);
map.putIfAbsent(30, 60);
- MatcherAssert.assertThat(map.putIfAbsent(5, 10), is((Integer) null));
- MatcherAssert.assertThat(map.putIfAbsent(10, 30), is(20));
+ assertThat(map.putIfAbsent(5, 10), is((Integer) null));
+ assertThat(map.putIfAbsent(10, 30), is(20));
}
@Test
@@ -52,10 +54,22 @@
map.putIfAbsent(10, 20);
map.putIfAbsent(20, 40);
map.putIfAbsent(30, 60);
- MatcherAssert.assertThat(map.contains(10), is(true));
- MatcherAssert.assertThat(map.contains(11), is(false));
+ assertThat(map.contains(10), is(true));
+ assertThat(map.contains(11), is(false));
+ assertThat(new FastSafeIterableMap<Integer, Integer>().contains(0), is(false));
+ }
- MatcherAssert.assertThat(new FastSafeIterableMap<Integer, Integer>().contains(0),
- is(false));
+
+ @Test
+ public void testRemove() {
+ FastSafeIterableMap<Integer, Integer> map = new FastSafeIterableMap<>();
+ map.putIfAbsent(10, 20);
+ map.putIfAbsent(20, 40);
+ assertThat(map.contains(10), is(true));
+ assertThat(map.contains(20), is(true));
+ assertThat(map.remove(10), is(20));
+ assertThat(map.contains(10), is(false));
+ assertThat(map.putIfAbsent(10, 30), nullValue());
+ assertThat(map.putIfAbsent(10, 40), is(30));
}
}
diff --git a/buildSrc/dependencies.gradle b/buildSrc/dependencies.gradle
index 53f0672..8a7d69a 100644
--- a/buildSrc/dependencies.gradle
+++ b/buildSrc/dependencies.gradle
@@ -19,7 +19,6 @@
// Testing dependencies
libs.mockito_core = 'org.mockito:mockito-core:2.7.6'
libs.dexmaker_mockito = 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0'
-libs.multidex = 'com.android.support:multidex:1.0.1'
libs.junit = 'junit:junit:4.12'
libs.test_runner = 'com.android.support.test:runner:0.6-alpha'
libs.espresso_core = 'com.android.support.test.espresso:espresso-core:2.3-alpha'
diff --git a/design/build.gradle b/design/build.gradle
index 0bc6809..23cbeb7 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -7,19 +7,12 @@
api project(':support-recyclerview-v7')
api project(':support-transition')
- androidTestImplementation (libs.test_runner) {
- exclude module: 'support-annotations'
- }
- androidTestImplementation (libs.espresso_core) {
- exclude module: 'support-annotations'
- }
- androidTestImplementation (libs.espresso_contrib) {
- exclude group: 'com.android.support'
- }
- androidTestImplementation libs.mockito_core
- androidTestImplementation libs.dexmaker_mockito
+ androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
+ androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation libs.espresso_contrib, { exclude group: 'com.android.support' }
+ androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
androidTestImplementation project(':support-testutils')
- androidTestImplementation libs.multidex
testImplementation libs.junit
testImplementation (libs.test_runner) {
@@ -32,7 +25,6 @@
minSdkVersion 14
// This disables the builds tools automatic vector -> PNG generation
generatedDensities = []
- multiDexEnabled true
}
sourceSets {
diff --git a/design/tests/AndroidManifest.xml b/design/tests/AndroidManifest.xml
index d5dbf91..c4673b3 100755
--- a/design/tests/AndroidManifest.xml
+++ b/design/tests/AndroidManifest.xml
@@ -19,7 +19,6 @@
<uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
<application
- android:name="android.support.multidex.MultiDexApplication"
android:supportsRtl="true"
android:theme="@style/Theme.Design">
diff --git a/fragment/java/android/support/v4/app/Fragment.java b/fragment/java/android/support/v4/app/Fragment.java
index 1df0f37..f8e3d47 100644
--- a/fragment/java/android/support/v4/app/Fragment.java
+++ b/fragment/java/android/support/v4/app/Fragment.java
@@ -340,6 +340,11 @@
// getLayoutInflater()
LayoutInflater mLayoutInflater;
+ // Keep track of whether or not this Fragment has run performCreate(). Retained instance
+ // fragments can have mRetaining set to true without going through creation, so we must
+ // track it separately.
+ boolean mIsCreated;
+
/**
* State information that has been retrieved from a fragment instance
* through {@link FragmentManager#saveFragmentInstanceState(Fragment)
@@ -2322,6 +2327,7 @@
mState = CREATED;
mCalled = false;
onCreate(savedInstanceState);
+ mIsCreated = true;
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onCreate()");
@@ -2583,6 +2589,7 @@
}
mState = INITIALIZING;
mCalled = false;
+ mIsCreated = false;
onDestroy();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
index 460d474..288fe57 100644
--- a/fragment/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/java/android/support/v4/app/FragmentManager.java
@@ -1372,7 +1372,7 @@
}
dispatchOnFragmentAttached(f, mHost.getContext(), false);
- if (!f.mRetaining) {
+ if (!f.mIsCreated) {
dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
diff --git a/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java b/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
index a312b9b..09f071e 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
@@ -1107,6 +1107,86 @@
}
}
+ /**
+ * When a retained instance fragment is saved while in the back stack, it should go
+ * through onCreate() when it is popped back.
+ */
+ @Test
+ @UiThreadTest
+ public void retainInstanceWithOnCreate() throws Throwable {
+ FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, null);
+ FragmentManager fm = fc.getSupportFragmentManager();
+
+ OnCreateFragment fragment1 = new OnCreateFragment();
+
+ fm.beginTransaction()
+ .add(fragment1, "1")
+ .commit();
+ fm.beginTransaction()
+ .remove(fragment1)
+ .addToBackStack(null)
+ .commit();
+
+ Pair<Parcelable, FragmentManagerNonConfig> savedState =
+ FragmentTestUtil.destroy(mActivityRule, fc);
+ Pair<Parcelable, FragmentManagerNonConfig> restartState =
+ Pair.create(savedState.first, null);
+
+ fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, restartState);
+
+ // Save again, but keep the state
+ savedState = FragmentTestUtil.destroy(mActivityRule, fc);
+
+ fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, savedState);
+
+ fm = fc.getSupportFragmentManager();
+
+ fm.popBackStackImmediate();
+ OnCreateFragment fragment2 = (OnCreateFragment) fm.findFragmentByTag("1");
+ assertTrue(fragment2.onCreateCalled);
+ fm.popBackStackImmediate();
+ }
+
+ /**
+ * A retained instance fragment should go through onCreate() once, even through save and
+ * restore.
+ */
+ @Test
+ @UiThreadTest
+ public void retainInstanceOneOnCreate() throws Throwable {
+ FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, null);
+ FragmentManager fm = fc.getSupportFragmentManager();
+
+ OnCreateFragment fragment = new OnCreateFragment();
+
+ fm.beginTransaction()
+ .add(fragment, "fragment")
+ .commit();
+ fm.executePendingTransactions();
+
+ fm.beginTransaction()
+ .remove(fragment)
+ .addToBackStack(null)
+ .commit();
+
+ assertTrue(fragment.onCreateCalled);
+ fragment.onCreateCalled = false;
+
+ Pair<Parcelable, FragmentManagerNonConfig> savedState =
+ FragmentTestUtil.destroy(mActivityRule, fc);
+
+ fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, savedState);
+ fm = fc.getSupportFragmentManager();
+
+ fm.popBackStackImmediate();
+ assertFalse(fragment.onCreateCalled);
+ }
+
private void assertAnimationsMatch(FragmentManager fm, int enter, int exit, int popEnter,
int popExit) {
FragmentManagerImpl fmImpl = (FragmentManagerImpl) fm;
@@ -1440,4 +1520,18 @@
}
}
}
+
+ public static class OnCreateFragment extends Fragment {
+ public boolean onCreateCalled;
+
+ public OnCreateFragment() {
+ setRetainInstance(true);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ onCreateCalled = true;
+ }
+ }
}
diff --git a/lifecycle/runtime/src/test/java/android/arch/lifecycle/LifecycleRegistryTest.java b/lifecycle/runtime/src/test/java/android/arch/lifecycle/LifecycleRegistryTest.java
index b3cf753..ef498ee 100644
--- a/lifecycle/runtime/src/test/java/android/arch/lifecycle/LifecycleRegistryTest.java
+++ b/lifecycle/runtime/src/test/java/android/arch/lifecycle/LifecycleRegistryTest.java
@@ -559,6 +559,16 @@
inOrder.verify(observer4).onResume();
}
+ @Test
+ public void sameObserverReAddition() {
+ TestObserver observer = mock(TestObserver.class);
+ mRegistry.addObserver(observer);
+ mRegistry.removeObserver(observer);
+ mRegistry.addObserver(observer);
+ dispatchEvent(ON_CREATE);
+ verify(observer).onCreate();
+ }
+
private void dispatchEvent(Lifecycle.Event event) {
when(mLifecycle.getCurrentState()).thenReturn(LifecycleRegistry.getStateAfter(event));
mRegistry.handleLifecycleEvent(event);
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/migration/Migration.java b/room/runtime/src/main/java/android/arch/persistence/room/migration/Migration.java
index 0023a2e..907e624 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/migration/Migration.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/migration/Migration.java
@@ -52,6 +52,9 @@
* Should run the necessary migrations.
* <p>
* This class cannot access any generated Dao in this method.
+ * <p>
+ * This method is already called inside a transaction and that transaction might actually be a
+ * composite transaction of all necessary {@code Migration}s.
*
* @param database The database instance
*/
diff --git a/v17/leanback/build.gradle b/v17/leanback/build.gradle
index 4fecc60..ea11627 100644
--- a/v17/leanback/build.gradle
+++ b/v17/leanback/build.gradle
@@ -8,21 +8,15 @@
api project(':support-fragment')
api project(':support-recyclerview-v7')
- androidTestImplementation (libs.test_runner) {
- exclude module: 'support-annotations'
- }
- androidTestImplementation (libs.espresso_core) {
- exclude module: 'support-annotations'
- }
- androidTestImplementation libs.mockito_core
- androidTestImplementation libs.dexmaker_mockito
- androidTestImplementation libs.multidex
+ androidTestImplementation libs.test_runner, { exclude module: 'support-annotations' }
+ androidTestImplementation libs.espresso_core, { exclude module: 'support-annotations' }
+ androidTestImplementation libs.mockito_core, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+ androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
}
android {
defaultConfig {
minSdkVersion 17
- multiDexEnabled true
}
sourceSets {
diff --git a/v17/leanback/res/layout/lb_playback_transport_controls_row.xml b/v17/leanback/res/layout/lb_playback_transport_controls_row.xml
index c8852e8..8b692f3 100644
--- a/v17/leanback/res/layout/lb_playback_transport_controls_row.xml
+++ b/v17/leanback/res/layout/lb_playback_transport_controls_row.xml
@@ -18,7 +18,7 @@
<!-- Note: clipChildren/clipToPadding false are needed to apply shadows to child
views with no padding of their own. Also to allow for negative margin on description. -->
-<android.support.v17.leanback.widget.PlaybackTransportRowView
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -68,9 +68,10 @@
android:layout_marginBottom="@dimen/lb_playback_transport_thumbs_bottom_margin" />
</FrameLayout>
- <LinearLayout
+ <android.support.v17.leanback.widget.PlaybackTransportRowView
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:id="@+id/transport_row"
android:orientation="vertical"
android:paddingStart="?attr/browsePaddingStart"
android:paddingEnd="?attr/browsePaddingEnd"
@@ -134,5 +135,5 @@
</RelativeLayout>
- </LinearLayout>
-</android.support.v17.leanback.widget.PlaybackTransportRowView>
+ </android.support.v17.leanback.widget.PlaybackTransportRowView>
+</LinearLayout>
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackTransportRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackTransportRowPresenter.java
index e6db33b..4505944 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackTransportRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackTransportRowPresenter.java
@@ -666,8 +666,8 @@
vh.mSecondaryControlsVh = (ControlBarPresenter.ViewHolder) mSecondaryControlsPresenter
.onCreateViewHolder(vh.mSecondaryControlsDock);
vh.mSecondaryControlsDock.addView(vh.mSecondaryControlsVh.view);
- ((PlaybackTransportRowView) vh.view).setOnUnhandledKeyListener(
- new PlaybackTransportRowView.OnUnhandledKeyListener() {
+ ((PlaybackTransportRowView) vh.view.findViewById(R.id.transport_row))
+ .setOnUnhandledKeyListener(new PlaybackTransportRowView.OnUnhandledKeyListener() {
@Override
public boolean onUnhandledKey(KeyEvent event) {
if (vh.getOnKeyListener() != null) {
diff --git a/v17/leanback/tests/AndroidManifest.xml b/v17/leanback/tests/AndroidManifest.xml
index d719485..b21246e 100644
--- a/v17/leanback/tests/AndroidManifest.xml
+++ b/v17/leanback/tests/AndroidManifest.xml
@@ -18,7 +18,6 @@
<uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
<application
- android:name="android.support.multidex.MultiDexApplication"
android:supportsRtl="true">
<activity android:name="android.support.v17.leanback.widget.GridActivity"
android:exported="true"/>
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/PlaybackGlueHostImplWithViewHolder.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/PlaybackGlueHostImplWithViewHolder.java
index d6a1f86..2cee649 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/PlaybackGlueHostImplWithViewHolder.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/PlaybackGlueHostImplWithViewHolder.java
@@ -56,12 +56,13 @@
if (mViewHolder == null && mPlaybackRowPresenter != null && mRow != null) {
mViewHolder = (PlaybackRowPresenter.ViewHolder)
mPlaybackRowPresenter.onCreateViewHolder(mRootView = new FrameLayout(mContext));
+ // Bind ViewHolder before measure/layout so child views will get proper size
+ mPlaybackRowPresenter.onBindViewHolder(mViewHolder, mRow);
mRootView.addView(mViewHolder.view, mLayoutWidth, mLayoutHeight);
mRootView.measure(
View.MeasureSpec.makeMeasureSpec(1920, View.MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
mRootView.layout(0, 0, mRootView.getMeasuredWidth(), mRootView.getMeasuredHeight());
- mPlaybackRowPresenter.onBindViewHolder(mViewHolder, mRow);
if (mViewHolder instanceof PlaybackSeekUi) {
((PlaybackSeekUi) mViewHolder).setPlaybackSeekUiClient(mChainedClient);
}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenterTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenterTest.java
index 54d27a3..db55725 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenterTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenterTest.java
@@ -37,6 +37,8 @@
import android.support.v17.leanback.widget.PlaybackSeekDataProvider.ResultCallback;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewParent;
import org.junit.Before;
import org.junit.Test;
@@ -65,7 +67,24 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- mGlue = new PlaybackTransportControlGlue(mContext, mImpl);
+ mGlue = new PlaybackTransportControlGlue(mContext, mImpl) {
+ @Override
+ protected void onCreatePrimaryActions(ArrayObjectAdapter
+ primaryActionsAdapter) {
+ super.onCreatePrimaryActions(primaryActionsAdapter);
+ primaryActionsAdapter.add(
+ new PlaybackControlsRow.ClosedCaptioningAction(mContext));
+ }
+
+ @Override
+ protected void onCreateSecondaryActions(ArrayObjectAdapter
+ secondaryActionsAdapter) {
+ secondaryActionsAdapter.add(
+ new PlaybackControlsRow.HighQualityAction(mContext));
+ secondaryActionsAdapter.add(
+ new PlaybackControlsRow.PictureInPictureAction(mContext));
+ }
+ };
mGlue.setHost(mHost);
}
@@ -195,6 +214,107 @@
assertSame(art, mViewHolder.mImageView.getDrawable());
}
+ static boolean isDescendant(View view, View descendant) {
+ while (descendant != view) {
+ ViewParent p = descendant.getParent();
+ if (!(p instanceof View)) {
+ return false;
+ }
+ descendant = (View) p;
+ }
+ return true;
+ }
+
+ @Test
+ public void navigateRightInPrimary() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mViewHolder.mControlsVh.mControlBar.getChildAt(0).requestFocus();
+ }
+ });
+ View view = mViewHolder.view.findFocus();
+ assertTrue(isDescendant(mViewHolder.mControlsVh.mControlBar.getChildAt(0), view));
+ assertTrue(isDescendant(mViewHolder.mControlsVh.mControlBar.getChildAt(1),
+ view.focusSearch(View.FOCUS_RIGHT)));
+ }
+
+ @Test
+ public void navigateRightInSecondary() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0).requestFocus();
+ }
+ });
+ View view = mViewHolder.view.findFocus();
+ assertTrue(isDescendant(mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0), view));
+ assertTrue(isDescendant(mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(1),
+ view.focusSearch(View.FOCUS_RIGHT)));
+ }
+
+ @Test
+ public void navigatePrimaryDownToProgress() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mViewHolder.mControlsVh.mControlBar.getChildAt(0).requestFocus();
+ }
+ });
+ View view = mViewHolder.view.findFocus();
+ assertTrue(isDescendant(mViewHolder.mControlsVh.mControlBar.getChildAt(0), view));
+ assertSame(mViewHolder.mProgressBar, view.focusSearch(View.FOCUS_DOWN));
+ }
+
+ @Test
+ public void navigateProgressUpToPrimary() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mViewHolder.mProgressBar.requestFocus();
+ }
+ });
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mViewHolder.mProgressBar.focusSearch(View.FOCUS_UP).requestFocus();
+ }
+ });
+ View view = mViewHolder.view.findFocus();
+ assertTrue(isDescendant(mViewHolder.mControlsVh.mControlBar.getChildAt(0), view));
+ }
+
+ @Test
+ public void navigateProgressDownToSecondary() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mViewHolder.mProgressBar.requestFocus();
+ }
+ });
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mViewHolder.mProgressBar.focusSearch(View.FOCUS_DOWN).requestFocus();
+ }
+ });
+ View view = mViewHolder.view.findFocus();
+ assertTrue(isDescendant(mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0), view));
+ }
+
+ @Test
+ public void navigateSecondaryUpToProgress() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0).requestFocus();
+ }
+ });
+ View view = mViewHolder.view.findFocus();
+ assertTrue(isDescendant(mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0), view));
+ assertSame(mViewHolder.mProgressBar, view.focusSearch(View.FOCUS_UP));
+ }
+
@Test
public void seekAndConfirm() {
when(mImpl.isPrepared()).thenReturn(true);