Merge changes Ic573b522,I1e0bceaa into pi-preview1-androidx-dev
* changes:
MediaSession2: Temporarily remove Javadoc references to hidden APIs
MediaSession2: Unhide MediaSession2 and MediaController2
diff --git a/car/res/layout/car_list_item_seekbar_content.xml b/car/res/layout/car_list_item_seekbar_content.xml
index eedbe73..6e3e33a 100644
--- a/car/res/layout/car_list_item_seekbar_content.xml
+++ b/car/res/layout/car_list_item_seekbar_content.xml
@@ -33,6 +33,8 @@
android:id="@+id/seek_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/car_padding_1"
+ android:layout_marginBottom="@dimen/car_padding_1"
android:orientation="vertical">
<TextView
android:id="@+id/text"
diff --git a/car/res/values/dimens.xml b/car/res/values/dimens.xml
index c310ec7..51810ad 100644
--- a/car/res/values/dimens.xml
+++ b/car/res/values/dimens.xml
@@ -144,7 +144,7 @@
<!-- Seekbar -->
<dimen name="car_seekbar_height">6dp</dimen>
- <dimen name="car_seekbar_thumb_size">20dp</dimen>
+ <dimen name="car_seekbar_thumb_size">24dp</dimen>
<dimen name="car_seekbar_thumb_stroke">1dp</dimen>
<!-- Scroll Bar Thumb -->
diff --git a/jetifier/jetifier/core/src/main/resources/default.generated.config b/jetifier/jetifier/core/src/main/resources/default.generated.config
index 57590dd..33ddfb7 100644
--- a/jetifier/jetifier/core/src/main/resources/default.generated.config
+++ b/jetifier/jetifier/core/src/main/resources/default.generated.config
@@ -2110,7 +2110,7 @@
"to": [
{
"groupId": "androidx.slice",
- "artifactId": "slices-core",
+ "artifactId": "slice-core",
"version": "1.0.0"
}
]
@@ -2124,7 +2124,7 @@
"to": [
{
"groupId": "androidx.slice",
- "artifactId": "slices-builders",
+ "artifactId": "slice-builders",
"version": "1.0.0"
}
]
@@ -2138,7 +2138,7 @@
"to": [
{
"groupId": "androidx.slice",
- "artifactId": "slices-view",
+ "artifactId": "slice-view",
"version": "1.0.0"
}
]
diff --git a/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java b/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
index a48af14..f565e8a 100644
--- a/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
+++ b/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
@@ -42,6 +42,8 @@
import androidx.media.test.R;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,6 +55,10 @@
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
@@ -73,6 +79,7 @@
private File mOutFile;
private Camera mCamera;
+ @Before
@Override
public void setUp() throws Exception {
super.setUp();
@@ -81,6 +88,7 @@
mOutFile = new File(mRecordedFilePath);
}
+ @After
@Override
public void tearDown() throws Exception {
super.tearDown();
@@ -1767,7 +1775,7 @@
@Test
@LargeTest
- public void testCallback() throws Throwable {
+ public void testMediaPlayer2Callback() throws Throwable {
final int mp4Duration = 8484;
if (!checkLoadResource(R.raw.testvideo)) {
@@ -1835,6 +1843,150 @@
mPlayer.reset();
}
+ @Test
+ @LargeTest
+ public void testPlayerStates() throws Throwable {
+ final int mp4Duration = 8484;
+
+ if (!checkLoadResource(R.raw.testvideo)) {
+ return; // skip;
+ }
+ mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface());
+
+ final Monitor prepareCompleted = new Monitor();
+ final Monitor playCompleted = new Monitor();
+ final Monitor pauseCompleted = new Monitor();
+
+ MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() {
+ @Override
+ public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) {
+ if (what == MediaPlayer2.CALL_COMPLETED_PREPARE) {
+ prepareCompleted.signal();
+ } else if (what == MediaPlayer2.CALL_COMPLETED_PLAY) {
+ playCompleted.signal();
+ } else if (what == MediaPlayer2.CALL_COMPLETED_PAUSE) {
+ pauseCompleted.signal();
+ }
+ }
+ };
+ synchronized (mEventCbLock) {
+ mEventCallbacks.add(ecb);
+ }
+
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_UNKNOWN, mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_IDLE, mPlayer.getPlayerState());
+ prepareCompleted.reset();
+ mPlayer.prepare();
+ prepareCompleted.waitForSignal();
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE,
+ mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_PAUSED, mPlayer.getPlayerState());
+
+ playCompleted.reset();
+ mPlayer.play();
+ playCompleted.waitForSignal();
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE,
+ mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_PLAYING, mPlayer.getPlayerState());
+
+ pauseCompleted.reset();
+ mPlayer.pause();
+ pauseCompleted.waitForSignal();
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE,
+ mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_PAUSED, mPlayer.getPlayerState());
+
+ mPlayer.reset();
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_UNKNOWN, mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_IDLE, mPlayer.getPlayerState());
+ }
+
+ @Test
+ @LargeTest
+ public void testPlayerEventCallback() throws Throwable {
+ final int mp4Duration = 8484;
+
+ if (!checkLoadResource(R.raw.testvideo)) {
+ return; // skip;
+ }
+
+ mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface());
+
+ final Monitor onPrepareCalled = new Monitor();
+ final Monitor onSeekCompleteCalled = new Monitor();
+ final Monitor onPlayerStateChangedCalled = new Monitor();
+ final AtomicInteger playerState = new AtomicInteger();
+ final Monitor onBufferingStateChangedCalled = new Monitor();
+ final AtomicInteger bufferingState = new AtomicInteger();
+ final Monitor onPlaybackSpeedChanged = new Monitor();
+ final AtomicReference<Float> playbackSpeed = new AtomicReference<>();
+
+ MediaPlayerBase.PlayerEventCallback callback = new MediaPlayerBase.PlayerEventCallback() {
+ // TODO: implement and add test case for onCurrentDataSourceChanged() callback.
+ @Override
+ public void onMediaPrepared(MediaPlayerBase mpb, DataSourceDesc dsd) {
+ onPrepareCalled.signal();
+ }
+
+ @Override
+ public void onPlayerStateChanged(MediaPlayerBase mpb, int state) {
+ playerState.set(state);
+ onPlayerStateChangedCalled.signal();
+ }
+
+ @Override
+ public void onBufferingStateChanged(MediaPlayerBase mpb, DataSourceDesc dsd,
+ int state) {
+ bufferingState.set(state);
+ onBufferingStateChangedCalled.signal();
+ }
+
+ @Override
+ public void onPlaybackSpeedChanged(MediaPlayerBase mpb, float speed) {
+ playbackSpeed.set(speed);
+ onPlaybackSpeedChanged.signal();
+ }
+
+ @Override
+ public void onSeekCompleted(MediaPlayerBase mpb, long position) {
+ onSeekCompleteCalled.signal();
+ }
+ };
+ ExecutorService executor = Executors.newFixedThreadPool(1);
+ mPlayer.registerPlayerEventCallback(executor, callback);
+
+ onPrepareCalled.reset();
+ onPlayerStateChangedCalled.reset();
+ onBufferingStateChangedCalled.reset();
+ mPlayer.prepare();
+ do {
+ assertTrue(onBufferingStateChangedCalled.waitForSignal(1000));
+ } while (bufferingState.get() != MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_STARVED);
+
+ assertTrue(onPrepareCalled.waitForSignal(1000));
+ do {
+ assertTrue(onPlayerStateChangedCalled.waitForSignal(1000));
+ } while (playerState.get() != MediaPlayerBase.PLAYER_STATE_PAUSED);
+ do {
+ assertTrue(onBufferingStateChangedCalled.waitForSignal(1000));
+ } while (bufferingState.get() != MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
+
+ onSeekCompleteCalled.reset();
+ mPlayer.seekTo(mp4Duration >> 1, MediaPlayer2.SEEK_PREVIOUS_SYNC);
+ onSeekCompleteCalled.waitForSignal();
+
+ onPlaybackSpeedChanged.reset();
+ mPlayer.setPlaybackSpeed(0.5f);
+ do {
+ assertTrue(onPlaybackSpeedChanged.waitForSignal(1000));
+ } while (Math.abs(playbackSpeed.get() - 0.5f) > FLOAT_TOLERANCE);
+
+ mPlayer.reset();
+
+ mPlayer.unregisterPlayerEventCallback(callback);
+ executor.shutdown();
+ }
+
public void testRecordAndPlay() throws Exception {
if (!hasMicrophone()) {
return;
diff --git a/media/src/androidTest/java/androidx/media/MediaPlayer2TestBase.java b/media/src/androidTest/java/androidx/media/MediaPlayer2TestBase.java
index 34c464b..215993a 100644
--- a/media/src/androidTest/java/androidx/media/MediaPlayer2TestBase.java
+++ b/media/src/androidTest/java/androidx/media/MediaPlayer2TestBase.java
@@ -30,6 +30,8 @@
import android.support.test.rule.ActivityTestRule;
import android.view.SurfaceHolder;
+import androidx.annotation.CallSuper;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -255,6 +257,7 @@
}
@Before
+ @CallSuper
public void setUp() throws Exception {
mActivity = mActivityRule.getActivity();
try {
@@ -277,6 +280,7 @@
}
@After
+ @CallSuper
public void tearDown() throws Exception {
if (mPlayer != null) {
mPlayer.close();
diff --git a/media/src/main/java/androidx/media/MediaPlayer2Impl.java b/media/src/main/java/androidx/media/MediaPlayer2Impl.java
index 59056a5..3b3e119 100644
--- a/media/src/main/java/androidx/media/MediaPlayer2Impl.java
+++ b/media/src/main/java/androidx/media/MediaPlayer2Impl.java
@@ -38,6 +38,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.view.Surface;
@@ -74,10 +75,40 @@
private static final int NEXT_SOURCE_STATE_PREPARING = 1;
private static final int NEXT_SOURCE_STATE_PREPARED = 2;
- // TODO: This class has too many locks. Use one single lock to protect internal variables.
- private MediaPlayer mPlayer;
- private int mPlayerState;
- private AudioAttributesCompat mAudioAttributes;
+ private static ArrayMap<Integer, Integer> sInfoEventMap;
+ private static ArrayMap<Integer, Integer> sErrorEventMap;
+
+ static {
+ sInfoEventMap = new ArrayMap<>();
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_UNKNOWN, MEDIA_INFO_UNKNOWN);
+ sInfoEventMap.put(2 /*MediaPlayer.MEDIA_INFO_STARTED_AS_NEXT*/, MEDIA_INFO_STARTED_AS_NEXT);
+ sInfoEventMap.put(
+ MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START, MEDIA_INFO_VIDEO_RENDERING_START);
+ sInfoEventMap.put(
+ MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING, MEDIA_INFO_VIDEO_TRACK_LAGGING);
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_BUFFERING_START, MEDIA_INFO_BUFFERING_START);
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_BUFFERING_END, MEDIA_INFO_BUFFERING_END);
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING, MEDIA_INFO_BAD_INTERLEAVING);
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_NOT_SEEKABLE, MEDIA_INFO_NOT_SEEKABLE);
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_METADATA_UPDATE, MEDIA_INFO_METADATA_UPDATE);
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_AUDIO_NOT_PLAYING, MEDIA_INFO_AUDIO_NOT_PLAYING);
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_VIDEO_NOT_PLAYING, MEDIA_INFO_VIDEO_NOT_PLAYING);
+ sInfoEventMap.put(
+ MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, MEDIA_INFO_UNSUPPORTED_SUBTITLE);
+ sInfoEventMap.put(MediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT, MEDIA_INFO_SUBTITLE_TIMED_OUT);
+
+ sErrorEventMap = new ArrayMap<>();
+ sErrorEventMap.put(MediaPlayer.MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNKNOWN);
+ sErrorEventMap.put(
+ MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK,
+ MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK);
+ sErrorEventMap.put(MediaPlayer.MEDIA_ERROR_IO, MEDIA_ERROR_IO);
+ sErrorEventMap.put(MediaPlayer.MEDIA_ERROR_MALFORMED, MEDIA_ERROR_MALFORMED);
+ sErrorEventMap.put(MediaPlayer.MEDIA_ERROR_UNSUPPORTED, MEDIA_ERROR_UNSUPPORTED);
+ sErrorEventMap.put(MediaPlayer.MEDIA_ERROR_TIMED_OUT, MEDIA_ERROR_TIMED_OUT);
+ }
+
+ private MediaPlayer mPlayer; // MediaPlayer is thread-safe.
private final Object mSrcLock = new Object();
//--- guarded by |mSrcLock| start
@@ -102,15 +133,18 @@
@GuardedBy("mTaskLock")
private Task mCurrentTask;
- private final Object mEventCbLock = new Object();
- @GuardedBy("mEventCbLock")
- private ArrayList<Pair<Executor, MediaPlayer2EventCallback>> mEventCallbackRecords =
+ private final Object mLock = new Object();
+ //--- guarded by |mLock| start
+ @PlayerState private int mPlayerState;
+ @BuffState private int mBufferingState;
+ private AudioAttributesCompat mAudioAttributes;
+ private ArrayList<Pair<Executor, MediaPlayer2EventCallback>> mMp2EventCallbackRecords =
new ArrayList<>();
-
- private final Object mDrmEventCbLock = new Object();
- @GuardedBy("mDrmEventCbLock")
+ private ArrayMap<PlayerEventCallback, Executor> mPlayerEventCallbackMap =
+ new ArrayMap<>();
private ArrayList<Pair<Executor, DrmEventCallback>> mDrmEventCallbackRecords =
new ArrayList<>();
+ //--- guarded by |mLock| end
/**
* Default constructor.
@@ -124,7 +158,8 @@
Looper looper = mHandlerThread.getLooper();
mTaskHandler = new Handler(looper);
mPlayer = new MediaPlayer();
- mPlayerState = MediaPlayerBase.PLAYER_STATE_IDLE;
+ mPlayerState = PLAYER_STATE_IDLE;
+ mBufferingState = BUFFERING_STATE_UNKNOWN;
setUpListeners();
}
@@ -170,7 +205,7 @@
@Override
void process() {
mPlayer.start();
- mPlayerState = PLAYER_STATE_PLAYING;
+ setPlayerState(PLAYER_STATE_PLAYING);
}
});
}
@@ -191,6 +226,7 @@
@Override
void process() throws IOException {
mPlayer.prepareAsync();
+ setBufferingState(BUFFERING_STATE_BUFFERING_AND_STARVED);
}
});
}
@@ -198,8 +234,7 @@
/**
* Pauses playback. Call play() to resume.
*
- * @throws IllegalStateException if the internal player engine has not been
- * initialized.
+ * @throws IllegalStateException if the internal player engine has not been initialized.
*/
@Override
public void pause() {
@@ -207,7 +242,7 @@
@Override
void process() {
mPlayer.pause();
- mPlayerState = PLAYER_STATE_PAUSED;
+ setPlayerState(PLAYER_STATE_PAUSED);
}
});
}
@@ -241,7 +276,7 @@
* Gets the duration of the file.
*
* @return the duration in milliseconds, if no duration is available
- * (for example, if streaming live content), -1 is returned.
+ * (for example, if streaming live content), -1 is returned.
*/
@Override
public long getDuration() {
@@ -265,7 +300,9 @@
@Override
public @PlayerState int getPlayerState() {
- return mPlayerState;
+ synchronized (mLock) {
+ return mPlayerState;
+ }
}
/**
@@ -275,8 +312,9 @@
*/
@Override
public @BuffState int getBufferingState() {
- // TODO: use cached state or call native function.
- return BUFFERING_STATE_UNKNOWN;
+ synchronized (mLock) {
+ return mBufferingState;
+ }
}
/**
@@ -292,15 +330,21 @@
addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) {
@Override
void process() {
- mAudioAttributes = attributes;
- mPlayer.setAudioAttributes((AudioAttributes) mAudioAttributes.unwrap());
+ AudioAttributes attr;
+ synchronized (mLock) {
+ mAudioAttributes = attributes;
+ attr = (AudioAttributes) mAudioAttributes.unwrap();
+ }
+ mPlayer.setAudioAttributes(attr);
}
});
}
@Override
public @NonNull AudioAttributesCompat getAudioAttributes() {
- return mAudioAttributes;
+ synchronized (mLock) {
+ return mAudioAttributes;
+ }
}
/**
@@ -437,7 +481,7 @@
addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_SPEED, false) {
@Override
void process() {
- mPlayer.setPlaybackParams(getPlaybackParams().setSpeed(speed));
+ setPlaybackParamsInternal(getPlaybackParams().setSpeed(speed));
}
});
}
@@ -508,8 +552,17 @@
*/
@Override
public void registerPlayerEventCallback(@NonNull Executor e,
- @NonNull PlayerEventCallback cb) {
- // TODO: implement this.
+ @NonNull PlayerEventCallback cb) {
+ if (cb == null) {
+ throw new IllegalArgumentException("Illegal null PlayerEventCallback");
+ }
+ if (e == null) {
+ throw new IllegalArgumentException(
+ "Illegal null Executor for the PlayerEventCallback");
+ }
+ synchronized (mLock) {
+ mPlayerEventCallbackMap.put(cb, e);
+ }
}
/**
@@ -518,7 +571,12 @@
*/
@Override
public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb) {
- // TODO: implement this.
+ if (cb == null) {
+ throw new IllegalArgumentException("Illegal null PlayerEventCallback");
+ }
+ synchronized (mLock) {
+ mPlayerEventCallbackMap.remove(cb);
+ }
}
@Override
@@ -526,18 +584,12 @@
addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) {
@Override
void process() {
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb
- : mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- cb.second.onCommandLabelReached(
- MediaPlayer2Impl.this, label);
- }
- });
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onCommandLabelReached(MediaPlayer2Impl.this, label);
}
- }
+ });
}
});
}
@@ -690,7 +742,6 @@
* non-zero speed is equivalent to calling play().
*
* @param params the playback params.
- *
* @throws IllegalStateException if the internal player engine has not been
* initialized or has been released.
* @throws IllegalArgumentException if params is not supported.
@@ -700,7 +751,7 @@
addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) {
@Override
void process() {
- mPlayer.setPlaybackParams(params);
+ setPlaybackParamsInternal(params);
}
});
}
@@ -722,7 +773,6 @@
* Sets A/V sync mode.
*
* @param params the A/V sync params to apply
- *
* @throws IllegalStateException if the internal player engine has not been
* initialized.
* @throws IllegalArgumentException if params are not supported.
@@ -741,9 +791,8 @@
* Gets the A/V sync mode.
*
* @return the A/V sync params
- *
* @throws IllegalStateException if the internal player engine has not been
- * initialized.
+ * initialized.
*/
@Override
@NonNull
@@ -805,8 +854,7 @@
* {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
*
* @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
- * is available, e.g. because the media player has not been initialized.
- *
+ * is available, e.g. because the media player has not been initialized.
* @see MediaTimestamp
*/
@Override
@@ -823,6 +871,8 @@
@Override
public void reset() {
mPlayer.reset();
+ setPlayerState(PLAYER_STATE_IDLE);
+ setBufferingState(BUFFERING_STATE_UNKNOWN);
/* FIXME: reset other internal variables. */
}
@@ -1092,11 +1142,11 @@
* In addition, the support for selecting an audio track at runtime is pretty limited
* in that an audio track can only be selected in the <em>Prepared</em> state.
* </p>
+ *
* @param index the index of the track to be selected. The valid range of the index
* is 0..total number of track - 1. The total number of tracks as well as the type of
* each individual track can be found by calling {@link #getTrackInfo()} method.
* @throws IllegalStateException if called in an invalid state.
- *
* @see MediaPlayer2#getTrackInfo
*/
@Override
@@ -1116,11 +1166,11 @@
* deselected. If the timed text track identified by index has not been
* selected before, it throws an exception.
* </p>
+ *
* @param index the index of the track to be deselected. The valid range of the index
* is 0..total number of tracks - 1. The total number of tracks as well as the type of
* each individual track can be found by calling {@link #getTrackInfo()} method.
* @throws IllegalStateException if called in an invalid state.
- *
* @see MediaPlayer2#getTrackInfo
*/
@Override
@@ -1142,7 +1192,7 @@
*/
@Override
public void setMediaPlayer2EventCallback(@NonNull Executor executor,
- @NonNull MediaPlayer2EventCallback eventCallback) {
+ @NonNull MediaPlayer2EventCallback eventCallback) {
if (eventCallback == null) {
throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
}
@@ -1150,8 +1200,8 @@
throw new IllegalArgumentException(
"Illegal null Executor for the MediaPlayer2EventCallback");
}
- synchronized (mEventCbLock) {
- mEventCallbackRecords.add(new Pair(executor, eventCallback));
+ synchronized (mLock) {
+ mMp2EventCallbackRecords.add(new Pair(executor, eventCallback));
}
}
@@ -1160,8 +1210,8 @@
*/
@Override
public void clearMediaPlayer2EventCallback() {
- synchronized (mEventCbLock) {
- mEventCallbackRecords.clear();
+ synchronized (mLock) {
+ mMp2EventCallbackRecords.clear();
}
}
@@ -1203,7 +1253,7 @@
throw new IllegalArgumentException(
"Illegal null Executor for the MediaPlayer2EventCallback");
}
- synchronized (mDrmEventCbLock) {
+ synchronized (mLock) {
mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
}
}
@@ -1213,7 +1263,7 @@
*/
@Override
public void clearDrmEventCallback() {
- synchronized (mDrmEventCbLock) {
+ synchronized (mLock) {
mDrmEventCallbackRecords.clear();
}
}
@@ -1257,15 +1307,14 @@
*
* @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
* from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
- *
- * @throws IllegalStateException if called before prepare(), or the DRM was
- * prepared already
- * @throws UnsupportedSchemeException if the crypto scheme is not supported
- * @throws ResourceBusyException if required DRM resources are in use
- * @throws ProvisioningNetworkErrorException if provisioning is required but failed due to a
- * network error
- * @throws ProvisioningServerErrorException if provisioning is required but failed due to
- * the request denied by the provisioning server
+ * @throws IllegalStateException if called before prepare(), or the DRM was
+ * prepared already
+ * @throws UnsupportedSchemeException if the crypto scheme is not supported
+ * @throws ResourceBusyException if required DRM resources are in use
+ * @throws ProvisioningNetworkErrorException if provisioning is required but failed due to a
+ * network error
+ * @throws ProvisioningServerErrorException if provisioning is required but failed due to
+ * the request denied by the provisioning server
*/
@Override
public void prepareDrm(@NonNull UUID uuid)
@@ -1410,6 +1459,8 @@
/**
* Read a DRM engine plugin String property value, given the property name string.
* <p>
+ *
+
* @param propertyName the property name
*
* Standard fields names are:
@@ -1431,6 +1482,7 @@
/**
* Set a DRM engine plugin String property value.
* <p>
+ *
* @param propertyName the property name
* @param value the property value
*
@@ -1449,23 +1501,108 @@
}
}
+ private void setPlaybackParamsInternal(final PlaybackParams params) {
+ PlaybackParams current = mPlayer.getPlaybackParams();
+ mPlayer.setPlaybackParams(params);
+ if (Math.abs(current.getSpeed() - params.getSpeed()) > 0.0001f) {
+ notifyPlayerEvent(new PlayerEventNotifier() {
+ @Override
+ public void notify(PlayerEventCallback cb) {
+ cb.onPlaybackSpeedChanged(MediaPlayer2Impl.this, params.getSpeed());
+ }
+ });
+ }
+ }
+
+ private void setPlayerState(@PlayerState final int state) {
+ synchronized (mLock) {
+ if (mPlayerState == state) {
+ return;
+ }
+ mPlayerState = state;
+ }
+ notifyPlayerEvent(new PlayerEventNotifier() {
+ @Override
+ public void notify(PlayerEventCallback cb) {
+ cb.onPlayerStateChanged(MediaPlayer2Impl.this, state);
+ }
+ });
+ }
+
+ private void setBufferingState(@BuffState final int state) {
+ synchronized (mLock) {
+ if (mBufferingState == state) {
+ return;
+ }
+ mBufferingState = state;
+ }
+ notifyPlayerEvent(new PlayerEventNotifier() {
+ @Override
+ public void notify(PlayerEventCallback cb) {
+ cb.onBufferingStateChanged(MediaPlayer2Impl.this, mCurrentDSD, state);
+ }
+ });
+ }
+
+ private void notifyMediaPlayer2Event(final Mp2EventNotifier notifier) {
+ List<Pair<Executor, MediaPlayer2EventCallback>> records;
+ synchronized (mLock) {
+ records = new ArrayList<>(mMp2EventCallbackRecords);
+ }
+ for (final Pair<Executor, MediaPlayer2EventCallback> record : records) {
+ record.first.execute(new Runnable() {
+ @Override
+ public void run() {
+ notifier.notify(record.second);
+ }
+ });
+ }
+ }
+
+ private void notifyPlayerEvent(final PlayerEventNotifier notifier) {
+ ArrayMap<PlayerEventCallback, Executor> map;
+ synchronized (mLock) {
+ map = new ArrayMap<>(mPlayerEventCallbackMap);
+ }
+ final int callbackCount = map.size();
+ for (int i = 0; i < callbackCount; i++) {
+ final Executor executor = map.valueAt(i);
+ final PlayerEventCallback cb = map.keyAt(i);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ notifier.notify(cb);
+ }
+ });
+ }
+ }
+
+ private interface Mp2EventNotifier {
+ void notify(MediaPlayer2EventCallback callback);
+ }
+
+ private interface PlayerEventNotifier {
+ void notify(PlayerEventCallback callback);
+ }
+
private void setUpListeners() {
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
- mPlayerState = PLAYER_STATE_PAUSED;
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- cb.second.onInfo(MediaPlayer2Impl.this, mCurrentDSD,
- MEDIA_INFO_PREPARED, 0);
- }
- });
+ setPlayerState(PLAYER_STATE_PAUSED);
+ setBufferingState(BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback callback) {
+ callback.onInfo(MediaPlayer2Impl.this, mCurrentDSD, MEDIA_INFO_PREPARED, 0);
}
- }
+ });
+ notifyPlayerEvent(new PlayerEventNotifier() {
+ @Override
+ public void notify(PlayerEventCallback cb) {
+ cb.onMediaPrepared(MediaPlayer2Impl.this, mCurrentDSD);
+ }
+ });
synchronized (mTaskLock) {
if (mCurrentTask != null
&& mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
@@ -1481,37 +1618,32 @@
mPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, final int width, final int height) {
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- cb.second.onVideoSizeChanged(MediaPlayer2Impl.this, mCurrentDSD,
- width, height);
- }
- });
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onVideoSizeChanged(MediaPlayer2Impl.this, mCurrentDSD, width, height);
}
- }
+ });
}
});
mPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
- switch(what) {
+ switch (what) {
case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- cb.second.onInfo(MediaPlayer2Impl.this, mCurrentDSD,
- MEDIA_INFO_VIDEO_RENDERING_START, 0);
- }
- });
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onInfo(MediaPlayer2Impl.this, mCurrentDSD,
+ MEDIA_INFO_VIDEO_RENDERING_START, 0);
}
- }
+ });
+ break;
+ case MediaPlayer.MEDIA_INFO_BUFFERING_START:
+ setBufferingState(BUFFERING_STATE_BUFFERING_AND_STARVED);
+ break;
+ case MediaPlayer.MEDIA_INFO_BUFFERING_END:
+ setBufferingState(BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
break;
}
return false;
@@ -1520,38 +1652,28 @@
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
- mPlayerState = PLAYER_STATE_PAUSED;
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- cb.second.onInfo(MediaPlayer2Impl.this, mCurrentDSD,
- MEDIA_INFO_PLAYBACK_COMPLETE, 0);
- }
- });
+ setPlayerState(PLAYER_STATE_PAUSED);
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onInfo(MediaPlayer2Impl.this, mCurrentDSD, MEDIA_INFO_PLAYBACK_COMPLETE,
+ 0);
}
- }
+ });
}
});
mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, final int what, final int extra) {
- mPlayerState = PLAYER_STATE_ERROR;
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- // TODO: translate what value to MP2's definition.
- cb.second.onError(MediaPlayer2Impl.this, mCurrentDSD,
- what, extra);
- }
- });
+ setPlayerState(PLAYER_STATE_ERROR);
+ setBufferingState(BUFFERING_STATE_UNKNOWN);
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ int w = sErrorEventMap.getOrDefault(what, MEDIA_ERROR_UNKNOWN);
+ cb.onError(MediaPlayer2Impl.this, mCurrentDSD, w, extra);
}
- }
+ });
return true;
}
});
@@ -1567,60 +1689,57 @@
processPendingTask_l();
}
}
+ final long seekPos = getCurrentPosition();
+ notifyPlayerEvent(new PlayerEventNotifier() {
+ @Override
+ public void notify(PlayerEventCallback cb) {
+ // TODO: The actual seeked position might be different from the
+ // requested position. Clarify which one is expected here.
+ cb.onSeekCompleted(MediaPlayer2Impl.this, seekPos);
+ }
+ });
}
});
mPlayer.setOnTimedMetaDataAvailableListener(
new MediaPlayer.OnTimedMetaDataAvailableListener() {
@Override
public void onTimedMetaDataAvailable(MediaPlayer mp, final TimedMetaData data) {
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- cb.second.onTimedMetaDataAvailable(MediaPlayer2Impl.this,
- mCurrentDSD, data);
- }
- });
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onTimedMetaDataAvailable(
+ MediaPlayer2Impl.this, mCurrentDSD, data);
}
- }
+ });
}
});
mPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, final int what, final int extra) {
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- // TODO: translate what value to MP2's definition.
- cb.second.onInfo(MediaPlayer2Impl.this, mCurrentDSD, what, extra);
- }
- });
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ int w = sInfoEventMap.getOrDefault(what, MEDIA_INFO_UNKNOWN);
+ cb.onInfo(MediaPlayer2Impl.this, mCurrentDSD, w, extra);
}
- }
+ });
return true;
}
});
mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, final int percent) {
- synchronized (mEventCbLock) {
- mBufferedPercentageCurrent.set(percent);
- for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- cb.second.onInfo(MediaPlayer2Impl.this, mCurrentDSD,
- MEDIA_INFO_BUFFERING_UPDATE, percent);
- }
- });
- }
+ if (percent >= 100) {
+ setBufferingState(BUFFERING_STATE_BUFFERING_COMPLETE);
}
+ mBufferedPercentageCurrent.set(percent);
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onInfo(MediaPlayer2Impl.this, mCurrentDSD,
+ MEDIA_INFO_BUFFERING_UPDATE, percent);
+ }
+ });
}
});
}
@@ -1737,9 +1856,9 @@
subset = Arrays.copyOfRange(pssh, i, i + dataLenSize);
int datalen = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN)
? ((subset[3] & 0xff) << 24) | ((subset[2] & 0xff) << 16)
- | ((subset[1] & 0xff) << 8) | (subset[0] & 0xff)
+ | ((subset[1] & 0xff) << 8) | (subset[0] & 0xff)
: ((subset[0] & 0xff) << 24) | ((subset[1] & 0xff) << 16)
- | ((subset[2] & 0xff) << 8) | (subset[3] & 0xff);
+ | ((subset[2] & 0xff) << 8) | (subset[3] & 0xff);
i += dataLenSize;
len -= dataLenSize;
@@ -1851,17 +1970,13 @@
if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) {
return;
}
- synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
- cb.first.execute(new Runnable() {
- @Override
- public void run() {
- cb.second.onCallCompleted(
- MediaPlayer2Impl.this, mDSD, mMediaCallType, status);
- }
- });
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onCallCompleted(
+ MediaPlayer2Impl.this, mDSD, mMediaCallType, status);
}
- }
+ });
}
};
}
diff --git a/recyclerview-selection/api/current.txt b/recyclerview-selection/api/current.txt
index 3d9bdf5..72e22ef 100644
--- a/recyclerview-selection/api/current.txt
+++ b/recyclerview-selection/api/current.txt
@@ -97,7 +97,7 @@
method public abstract boolean clearSelection();
method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K>);
method public abstract boolean deselect(K);
- method public abstract androidx.recyclerview.selection.Selection getSelection();
+ method public abstract androidx.recyclerview.selection.Selection<K> getSelection();
method public abstract boolean hasSelection();
method public abstract boolean isSelected(K);
method public abstract void onRestoreInstanceState(android.os.Bundle);
diff --git a/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java b/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
index 525c264..f7512ca 100644
--- a/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
+++ b/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
@@ -303,7 +303,7 @@
@Test
public void testProvisionalSelection() {
- Selection s = mTracker.getSelection();
+ Selection<String> s = mTracker.getSelection();
mSelection.assertNoSelection();
// Mimicking band selection case -- BandController notifies item callback by itself.
@@ -319,7 +319,7 @@
@Test
public void testProvisionalSelection_Replace() {
- Selection s = mTracker.getSelection();
+ Selection<String> s = mTracker.getSelection();
// Mimicking band selection case -- BandController notifies item callback by itself.
mListener.onItemStateChanged(mItems.get(1), true);
@@ -343,7 +343,7 @@
@Test
public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
- Selection s = mTracker.getSelection();
+ Selection<String> s = mTracker.getSelection();
// Mimicking band selection case -- BandController notifies item callback by itself.
mListener.onItemStateChanged(mItems.get(1), true);
@@ -365,7 +365,7 @@
@Test
public void testProvisionalSelection_Apply() {
- Selection s = mTracker.getSelection();
+ Selection<String> s = mTracker.getSelection();
// Mimicking band selection case -- BandController notifies item callback by itself.
mListener.onItemStateChanged(mItems.get(1), true);
@@ -383,7 +383,7 @@
public void testProvisionalSelection_Cancel() {
mTracker.select(mItems.get(1));
mTracker.select(mItems.get(2));
- Selection s = mTracker.getSelection();
+ Selection<String> s = mTracker.getSelection();
SparseBooleanArray provisional = new SparseBooleanArray();
provisional.append(3, true);
@@ -399,7 +399,7 @@
public void testProvisionalSelection_IntersectsAppliedSelection() {
mTracker.select(mItems.get(1));
mTracker.select(mItems.get(2));
- Selection s = mTracker.getSelection();
+ Selection<String> s = mTracker.getSelection();
// Mimicking band selection case -- BandController notifies item callback by itself.
mListener.onItemStateChanged(mItems.get(3), true);
diff --git a/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/SelectionTest.java b/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/SelectionTest.java
index eb2402b..b8c6583 100644
--- a/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/SelectionTest.java
+++ b/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/SelectionTest.java
@@ -41,11 +41,11 @@
"auth|id=@53di*/f3#d"
};
- private Selection mSelection;
+ private Selection<String> mSelection;
@Before
public void setUp() throws Exception {
- mSelection = new Selection();
+ mSelection = new Selection<>();
mSelection.add(mIds[0]);
mSelection.add(mIds[1]);
mSelection.add(mIds[2]);
@@ -96,14 +96,14 @@
@Test
public void testIsEmpty() {
- assertTrue(new Selection().isEmpty());
+ assertTrue(new Selection<>().isEmpty());
mSelection.clear();
assertTrue(mSelection.isEmpty());
}
@Test
public void testSize() {
- Selection other = new Selection();
+ Selection<String> other = new Selection<>();
for (int i = 0; i < mSelection.size(); i++) {
other.add(mIds[i]);
}
@@ -117,7 +117,7 @@
@Test
public void testEqualsOther() {
- Selection other = new Selection();
+ Selection<String> other = new Selection<>();
other.add(mIds[0]);
other.add(mIds[1]);
other.add(mIds[2]);
@@ -127,7 +127,7 @@
@Test
public void testEqualsCopy() {
- Selection other = new Selection();
+ Selection<String> other = new Selection<>();
other.copyFrom(mSelection);
assertEquals(mSelection, other);
assertEquals(mSelection.hashCode(), other.hashCode());
@@ -135,7 +135,7 @@
@Test
public void testNotEquals() {
- Selection other = new Selection();
+ Selection<String> other = new Selection<>();
other.add("foobar");
assertFalse(mSelection.equals(other));
}
diff --git a/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/SelectionProbe.java b/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/SelectionProbe.java
index e8ae607..8ac4baf 100644
--- a/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/SelectionProbe.java
+++ b/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/SelectionProbe.java
@@ -64,7 +64,7 @@
}
public void assertSelectionSize(int expected) {
- Selection selection = mMgr.getSelection();
+ Selection<String> selection = mMgr.getSelection();
assertEquals(selection.toString(), expected, selection.size());
mSelectionListener.assertSelectionSize(expected);
diff --git a/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java b/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
index 5491f99..283426f 100644
--- a/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
+++ b/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
@@ -121,7 +121,7 @@
* of the selection that will not reflect future changes
* to selection.
*/
- public abstract Selection getSelection();
+ public abstract Selection<K> getSelection();
/**
* Updates {@code dest} to reflect the current selection.
diff --git a/samples/SupportSliceDemos/build.gradle b/samples/SupportSliceDemos/build.gradle
index 4d518ff..8675869 100644
--- a/samples/SupportSliceDemos/build.gradle
+++ b/samples/SupportSliceDemos/build.gradle
@@ -21,9 +21,9 @@
}
dependencies {
- implementation(project(":slices-view"))
- implementation(project(":slices-builders"))
- implementation(project(":slices-core"))
+ implementation(project(":slice-view"))
+ implementation(project(":slice-builders"))
+ implementation(project(":slice-core"))
implementation("com.android.support:design:28.0.0-SNAPSHOT", { transitive = false })
implementation(project(":transition"))
implementation(project(":recyclerview"))
diff --git a/settings.gradle b/settings.gradle
index 61676b0..7ec91e5 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -74,9 +74,9 @@
includeProject(":recommendation", "recommendation")
includeProject(":recyclerview", "v7/recyclerview")
includeProject(":recyclerview-selection", "recyclerview-selection")
-includeProject(":slices-core", "slices/core")
-includeProject(":slices-view", "slices/view")
-includeProject(":slices-builders", "slices/builders")
+includeProject(":slice-core", "slices/core")
+includeProject(":slice-view", "slices/view")
+includeProject(":slice-builders", "slices/builders")
includeProject(":slidingpanelayout", "slidingpanelayout")
includeProject(":swiperefreshlayout", "swiperefreshlayout")
includeProject(":textclassifier", "textclassifier")
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index 907a0b4..73d0568 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -23,7 +23,7 @@
}
dependencies {
- implementation(project(":slices-core"))
+ implementation(project(":slice-core"))
implementation project(":annotation")
implementation project(path: ':core')
}
diff --git a/slices/view/build.gradle b/slices/view/build.gradle
index 71de3a7..38576c3 100644
--- a/slices/view/build.gradle
+++ b/slices/view/build.gradle
@@ -23,8 +23,8 @@
}
dependencies {
- implementation(project(":slices-core"))
- implementation(project(":slices-builders"))
+ implementation(project(":slice-core"))
+ implementation(project(":slice-builders"))
implementation(project(":recyclerview"))
api(ARCH_LIFECYCLE_LIVEDATA_CORE, libs.exclude_annotations_transitive)
diff --git a/slices/view/src/main/java/androidx/slice/widget/ListContent.java b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
index ee3c2e4..cde20da 100644
--- a/slices/view/src/main/java/androidx/slice/widget/ListContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
@@ -306,9 +306,12 @@
return null;
}
- private static boolean isValidHeader(SliceItem sliceItem) {
+ /**
+ * @return whether the provided slice item is a valid header.
+ */
+ public static boolean isValidHeader(SliceItem sliceItem) {
if (FORMAT_SLICE.equals(sliceItem.getFormat()) && !sliceItem.hasAnyHints(HINT_LIST_ITEM,
- HINT_ACTIONS, HINT_KEYWORDS)) {
+ HINT_ACTIONS, HINT_KEYWORDS, HINT_SEE_MORE)) {
// Minimum valid header is a slice with text
SliceItem item = SliceQuery.find(sliceItem, FORMAT_TEXT, (String) null, null);
return item != null;
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowView.java b/slices/view/src/main/java/androidx/slice/widget/RowView.java
index 6940cb0..a4a589a 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -17,7 +17,6 @@
package androidx.slice.widget;
import static android.app.slice.Slice.EXTRA_RANGE_VALUE;
-import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.app.slice.Slice.HINT_NO_TINT;
import static android.app.slice.Slice.HINT_PARTIAL;
import static android.app.slice.Slice.HINT_SHORTCUT;
@@ -220,7 +219,7 @@
SliceView.OnSliceActionListener observer) {
setSliceActionListener(observer);
mRowIndex = index;
- mIsHeader = !slice.hasHint(HINT_LIST_ITEM);
+ mIsHeader = ListContent.isValidHeader(slice);
mHeaderActions = null;
mRowContent = new RowContent(getContext(), slice, mIsHeader);
populateViews();
@@ -531,7 +530,7 @@
b.setTextColor(mTintColor);
}
mSeeMoreView = b;
- addView(mSeeMoreView);
+ mRootView.addView(mSeeMoreView);
}
@Override
@@ -578,7 +577,7 @@
removeView(mRangeBar);
}
if (mSeeMoreView != null) {
- removeView(mSeeMoreView);
+ mRootView.removeView(mSeeMoreView);
}
}
}
diff --git a/v7/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerTest.java
index 25aa00d..60eb6d2 100644
--- a/v7/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerTest.java
+++ b/v7/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerTest.java
@@ -1180,7 +1180,16 @@
adapter.addAndNotify(5 + (i % 3) * 3, 1);
Thread.sleep(25);
}
- smoothScrollToPosition(mLayoutManager.findLastVisibleItemPosition() + 20);
+
+ final AtomicInteger lastVisiblePosition = new AtomicInteger();
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ lastVisiblePosition.set(mLayoutManager.findLastVisibleItemPosition());
+ }
+ });
+
+ smoothScrollToPosition(lastVisiblePosition.get() + 20);
waitForAnimations(2);
getInstrumentation().waitForIdleSync();
assertEquals("Children count should add up", childCount.get(),