Merge changes from topic "ExoPlayer_in_MP" into sc-mainline-prod
* changes:
Change Espresso tests to migrate to ExoPlayer
Add ExoPlayer support for video playback
diff --git a/Android.bp b/Android.bp
index 62c38d5..e6bee09 100644
--- a/Android.bp
+++ b/Android.bp
@@ -37,6 +37,7 @@
"androidx.fragment_fragment",
"androidx.vectordrawable_vectordrawable-animated",
"androidx.exifinterface_exifinterface",
+ "exoplayer2.15.1",
],
libs: [
diff --git a/res/layout/item_video_preview.xml b/res/layout/item_video_preview.xml
index f1b5274..b888ac0 100644
--- a/res/layout/item_video_preview.xml
+++ b/res/layout/item_video_preview.xml
@@ -16,13 +16,23 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <VideoView
- android:id="@+id/preview_videoView"
+
+ <com.google.android.exoplayer2.ui.StyledPlayerView
+ android:id="@+id/preview_player_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ app:use_controller="false" />
+
+ <ImageView
+ android:id="@+id/preview_video_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
- android:contentDescription="@null"/>
+ android:scaleType="fitCenter"
+ android:contentDescription="@null" />
</FrameLayout>
diff --git a/src/com/android/providers/media/photopicker/ui/BaseViewHolder.java b/src/com/android/providers/media/photopicker/ui/BaseViewHolder.java
index e5f0af0..db8c0c1 100644
--- a/src/com/android/providers/media/photopicker/ui/BaseViewHolder.java
+++ b/src/com/android/providers/media/photopicker/ui/BaseViewHolder.java
@@ -44,28 +44,4 @@
}
public abstract void bind();
-
- /**
- * Called when view in this {@code RecyclerView.ViewHolder} has been recycled.
- * <p>
- * Optional method for BaseViewHolder subclasses to implement if they have additional actions to
- * take on {@link RecyclerView.Adapter#onViewRecycled}
- */
- public void onViewRecycled() {};
-
- /**
- * Called when a view in this {@code RecyclerView.ViewHolder} has been attached to a window.
- * <p>
- * Optional method for BaseViewHolder subclasses to implement if they have additional actions to
- * take on {@link RecyclerView.Adapter#onViewAttachedToWindow}
- */
- public void onViewAttachedToWindow() {};
-
- /**
- * Called when a view in this {@code RecyclerView.ViewHolder} has been detached from its window.
- * <p>
- * Optional method for BaseViewHolder subclasses to implement if they have additional actions to
- * take on {@link RecyclerView.Adapter#onViewDetachedFromWindow}
- */
- public void onViewDetachedFromWindow() {};
}
diff --git a/src/com/android/providers/media/photopicker/ui/ExoPlayerWrapper.java b/src/com/android/providers/media/photopicker/ui/ExoPlayerWrapper.java
new file mode 100644
index 0000000..9963cff
--- /dev/null
+++ b/src/com/android/providers/media/photopicker/ui/ExoPlayerWrapper.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.ui;
+
+import android.content.Context;
+import android.net.Uri;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.providers.media.R;
+
+import com.google.android.exoplayer2.DefaultLoadControl;
+import com.google.android.exoplayer2.DefaultRenderersFactory;
+import com.google.android.exoplayer2.ExoPlayer;
+import com.google.android.exoplayer2.LoadControl;
+import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.analytics.AnalyticsCollector;
+import com.google.android.exoplayer2.source.MediaParserExtractorAdapter;
+import com.google.android.exoplayer2.source.ProgressiveMediaSource;
+import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
+import com.google.android.exoplayer2.ui.StyledPlayerView;
+import com.google.android.exoplayer2.upstream.ContentDataSource;
+import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
+import com.google.android.exoplayer2.util.Clock;
+
+/**
+ * A helper class that assists in initialize/prepare/play/release of ExoPlayer. The class assumes
+ * that all its public methods are called from main thread only.
+ */
+class ExoPlayerWrapper {
+ // The minimum duration of media that the player will attempt to ensure is buffered at all
+ // times.
+ private static final int MIN_BUFFER_MS = 1000;
+ // The maximum duration of media that the player will attempt to buffer.
+ private static final int MAX_BUFFER_MS = 2000;
+ // The duration of media that must be buffered for playback to start or resume following a user
+ // action such as a seek.
+ private static final int BUFFER_FOR_PLAYBACK_MS = 1000;
+ // The default duration of media that must be buffered for playback to resume after a rebuffer.
+ private static final int BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = 1000;
+ private static final LoadControl sLoadControl = new DefaultLoadControl.Builder()
+ .setBufferDurationsMs(
+ MIN_BUFFER_MS,
+ MAX_BUFFER_MS,
+ BUFFER_FOR_PLAYBACK_MS,
+ BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS).build();
+
+ private final Context mContext;
+ private ExoPlayer mExoPlayer;
+ private boolean mIsPlayerReleased = true;
+
+ public ExoPlayerWrapper(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Prepares the {@link ExoPlayer} and attaches it to given {@code styledPlayerView} and starts
+ * playing.
+ * Note: The method tries to release the {@link ExoPlayer} before preparing the new one. As we
+ * don't have previous page's {@link StyledPlayerView}, we can't switch the player from previous
+ * {@link StyledPlayerView} to new one. Hence, we try to create a new {@link ExoPlayer} instead.
+ */
+ public void prepareAndPlay(StyledPlayerView styledPlayerView, ImageView imageView, Uri uri) {
+ // TODO(b/197083539): Explore options for not re-creating ExoPlayer everytime.
+ initializeExoPlayer(uri);
+
+ // TODO(b/197083539): Remove this if it drains battery.
+ styledPlayerView.setKeepScreenOn(true);
+ styledPlayerView.setPlayer(mExoPlayer);
+ styledPlayerView.setVisibility(View.VISIBLE);
+ // Hide ImageView when the player is ready.
+ mExoPlayer.addListener(new Player.Listener() {
+ @Override
+ public void onPlaybackStateChanged(int playbackState) {
+ if (playbackState == Player.STATE_READY ) {
+ imageView.setVisibility(View.GONE);
+ }
+ }
+ });
+
+ mExoPlayer.prepare();
+ mIsPlayerReleased = false;
+
+ mExoPlayer.setPlayWhenReady(true);
+ }
+
+ public void releaseIfNecessary() {
+ releaseIfNecessaryInternal();
+ }
+
+ private ExoPlayer createExoPlayer() {
+ // ProgressiveMediaFactory will be enough for video playback of videos on the device.
+ // This also reduces apk size.
+ ProgressiveMediaSource.Factory mediaSourceFactory = new ProgressiveMediaSource.Factory(
+ () -> new ContentDataSource(mContext), MediaParserExtractorAdapter.FACTORY);
+
+ return new ExoPlayer.Builder(mContext,
+ new DefaultRenderersFactory(mContext),
+ new DefaultTrackSelector(mContext),
+ mediaSourceFactory,
+ sLoadControl,
+ DefaultBandwidthMeter.getSingletonInstance(mContext),
+ new AnalyticsCollector(Clock.DEFAULT)).buildExoPlayer();
+ }
+
+ private void initializeExoPlayer(Uri uri) {
+ // Try releasing the ExoPlayer first.
+ releaseIfNecessaryInternal();
+
+ mExoPlayer = createExoPlayer();
+ // We always start from the beginning of the video, and we always repeat the video in a loop
+ mExoPlayer.setRepeatMode(Player.REPEAT_MODE_ONE);
+ // We only play one video in the player, hence we should always use setMediaItem instead of
+ // ExoPlayer#addMediaItem
+ mExoPlayer.setMediaItem(MediaItem.fromUri(uri));
+ }
+
+ private void releaseIfNecessaryInternal() {
+ // Release the player only when it's not already released. ExoPlayer doesn't crash if we try
+ // to release already released player, but ExoPlayer#release() may not be a no-op, hence we
+ // call release() only when it's not already released.
+ if (!mIsPlayerReleased) {
+ mExoPlayer.release();
+ mIsPlayerReleased = true;
+ }
+ }
+}
diff --git a/src/com/android/providers/media/photopicker/ui/ImageLoader.java b/src/com/android/providers/media/photopicker/ui/ImageLoader.java
index 3bdcd68..bfcfe34 100644
--- a/src/com/android/providers/media/photopicker/ui/ImageLoader.java
+++ b/src/com/android/providers/media/photopicker/ui/ImageLoader.java
@@ -23,6 +23,7 @@
import androidx.annotation.NonNull;
import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.signature.ObjectKey;
import com.android.providers.media.photopicker.data.model.Category;
@@ -86,9 +87,12 @@
if (item.isGif()) {
Glide.with(mContext)
.load(item.getContentUri())
+ .signature(new ObjectKey(
+ item.getContentUri().toString() + item.getGenerationModified()))
.into(imageView);
return;
}
+
// Preview as bitmap image for all other image types
Glide.with(mContext)
.asBitmap()
@@ -97,4 +101,17 @@
item.getContentUri().toString() + item.getGenerationModified()))
.into(imageView);
}
+
+ /**
+ * Loads the image from first frame of the given video item
+ */
+ public void loadImageFromVideoForPreview(@NonNull Item item, @NonNull ImageView imageView) {
+ Glide.with(mContext)
+ .asBitmap()
+ .load(item.getContentUri())
+ .apply(new RequestOptions().frame(1000))
+ .signature(new ObjectKey("Preview"
+ + item.getContentUri().toString() + item.getGenerationModified()))
+ .into(imageView);
+ }
}
diff --git a/src/com/android/providers/media/photopicker/ui/PlaybackHandler.java b/src/com/android/providers/media/photopicker/ui/PlaybackHandler.java
new file mode 100644
index 0000000..18a77ee
--- /dev/null
+++ b/src/com/android/providers/media/photopicker/ui/PlaybackHandler.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.ui;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Looper;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.providers.media.R;
+import com.android.providers.media.photopicker.data.model.Item;
+
+import com.google.android.exoplayer2.ui.StyledPlayerView;
+
+/**
+ * A class to handle page selected state to initiate video playback or release video player
+ * resources. All the public methods of this class must be called from main thread as ExoPlayer
+ * should be prepared/released from main thread.
+ */
+class PlaybackHandler {
+ private static final String TAG = "PlaybackHandler";
+ // Only main thread can call the methods in this class, hence we don't need to guard mVideoUri
+ // with lock while reading or writing to it.
+ private Uri mVideoUri = null;
+ private final ExoPlayerWrapper mExoPlayerWrapper;
+ private final ImageLoader mImageLoader;
+
+ PlaybackHandler(Context context, ImageLoader imageLoader) {
+ mExoPlayerWrapper = new ExoPlayerWrapper(context);
+ mImageLoader = imageLoader;
+ }
+
+ /**
+ * Handles video playback for the {@link ViewPager2} page when it's selected i.e., completely
+ * visible.
+ * <ul>
+ * <li> If the selected page is a video page, prepare and play the video associated with
+ * selected page
+ * <li> If the selected page is a video page and the same video is already playing, then no
+ * action will be taken.
+ * <li> If the selected page is non-video page, try releasing the ExoPlayer associated with
+ * previous page that was selected.
+ * </ul>
+ * @param view {@link RecyclerView.ViewHolder#itemView} of the selected page.
+ */
+ public void handleVideoPlayback(View view) {
+ assertMainThread();
+
+ final Object tag = view.getTag();
+ if (!(tag instanceof Item)) {
+ throw new IllegalStateException("Expected Item tag to be set to " + view);
+ }
+
+ final Item item = (Item) tag;
+ if (!item.isVideo()) {
+ // We only need to handle video playback. For everything else, try releasing ExoPlayer
+ // if there is a prepared ExoPlayer of the previous page.
+ mExoPlayerWrapper.releaseIfNecessary();
+ mVideoUri = null;
+ return;
+ }
+
+ final Uri videoUri = item.getContentUri();
+ if (mVideoUri != null && mVideoUri.equals(videoUri)) {
+ // Selected video is already handled. This must be a slight drag and drop, and we don't
+ // have to change state of the player.
+ Log.d(TAG, "Ignoring handlePageSelected of already selected page, with uri "
+ + videoUri);
+ return;
+ }
+
+ final StyledPlayerView styledPlayerView = view.findViewById(R.id.preview_player_view);
+ if (styledPlayerView == null) {
+ throw new IllegalStateException("Expected to find StyledPlayerView in " + view);
+ }
+ final ImageView imageView = view.findViewById(R.id.preview_video_image);
+
+ mVideoUri = videoUri;
+ mExoPlayerWrapper.prepareAndPlay(styledPlayerView, imageView, mVideoUri);
+ }
+
+ public void onBind(View itemView) {
+ final Item item = (Item) itemView.getTag();
+ // We set the ImageView with image from the video. ImageView is needed to improve the user
+ // experience while video player is not yet initialized or being prepared.
+ final ImageView imageView = itemView.findViewById(R.id.preview_video_image);
+ mImageLoader.loadImageFromVideoForPreview(item, imageView);
+
+ // Video playback needs granular page state events and hence video playback is initiated by
+ // ViewPagerWrapper and handled by PlaybackHandler#handleVideoPlayback
+ }
+
+ public void onViewAttachedToWindow(View itemView) {
+ final ImageView imageView = itemView.findViewById(R.id.preview_video_image);
+ final StyledPlayerView styledPlayerView = itemView.findViewById(R.id.preview_player_view);
+
+ imageView.setVisibility(View.VISIBLE);
+ styledPlayerView.setVisibility(View.GONE);
+ }
+
+ /**
+ * Releases ExoPlayer if there is any. Also resets the saved video uri.
+ */
+ public void releaseResources() {
+ assertMainThread();
+
+ mVideoUri = null;
+ mExoPlayerWrapper.releaseIfNecessary();
+ }
+
+ private void assertMainThread() {
+ if (Looper.getMainLooper().isCurrentThread()) return;
+
+ throw new IllegalStateException("PlaybackHandler methods are expected to be called from"
+ + " main thread. Current thread " + Looper.myLooper().getThread()
+ + ", Main thread" + Looper.getMainLooper().getThread());
+ }
+}
diff --git a/src/com/android/providers/media/photopicker/ui/PreviewAdapter.java b/src/com/android/providers/media/photopicker/ui/PreviewAdapter.java
index 7bdacf0..a39932b 100644
--- a/src/com/android/providers/media/photopicker/ui/PreviewAdapter.java
+++ b/src/com/android/providers/media/photopicker/ui/PreviewAdapter.java
@@ -16,6 +16,8 @@
package com.android.providers.media.photopicker.ui;
+import android.content.Context;
+import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
@@ -36,9 +38,11 @@
private List<Item> mItemList = new ArrayList<>();
private ImageLoader mImageLoader;
+ private final PlaybackHandler mPlaybackHandler;
- public PreviewAdapter(ImageLoader imageLoader) {
- mImageLoader = imageLoader;
+ public PreviewAdapter(Context context) {
+ mImageLoader = new ImageLoader(context);
+ mPlaybackHandler = new PlaybackHandler(context, mImageLoader);
}
@NonNull
@@ -52,28 +56,32 @@
}
@Override
- public void onBindViewHolder(@NonNull BaseViewHolder photoHolder, int position) {
+ public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
final Item item = getItem(position);
- photoHolder.itemView.setTag(item);
- photoHolder.bind();
+ holder.itemView.setTag(item);
+ holder.bind();
+
+ if (item.isVideo()) {
+ mPlaybackHandler.onBind(holder.itemView);
+ }
}
@Override
public void onViewAttachedToWindow(BaseViewHolder holder) {
super.onViewAttachedToWindow(holder);
- holder.onViewAttachedToWindow();
+
+ final Item item = (Item) holder.itemView.getTag();
+ if (item.isVideo()) {
+ mPlaybackHandler.onViewAttachedToWindow(holder.itemView);
+ }
}
- @Override
- public void onViewDetachedFromWindow(BaseViewHolder holder) {
- super.onViewDetachedFromWindow(holder);
- holder.onViewDetachedFromWindow();
+ public void handlePageSelected(View itemView) {
+ mPlaybackHandler.handleVideoPlayback(itemView);
}
- @Override
- public void onViewRecycled(BaseViewHolder holder) {
- super.onViewRecycled(holder);
- holder.onViewRecycled();
+ public void onStop() {
+ mPlaybackHandler.releaseResources();
}
@Override
diff --git a/src/com/android/providers/media/photopicker/ui/PreviewFragment.java b/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
index 2e8dd6a..6f1801f 100644
--- a/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/PreviewFragment.java
@@ -241,9 +241,23 @@
((PhotoPickerActivity) getActivity()).updateCommonLayouts(LayoutModeUtils.MODE_PREVIEW,
/* title */"");
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
if (mViewPager2Wrapper != null) {
- mViewPager2Wrapper.onResume();
+ mViewPager2Wrapper.onStop();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ if (mViewPager2Wrapper != null) {
+ mViewPager2Wrapper.onStart();
}
}
diff --git a/src/com/android/providers/media/photopicker/ui/PreviewVideoHolder.java b/src/com/android/providers/media/photopicker/ui/PreviewVideoHolder.java
index 366fdb5..8a9ca2e 100644
--- a/src/com/android/providers/media/photopicker/ui/PreviewVideoHolder.java
+++ b/src/com/android/providers/media/photopicker/ui/PreviewVideoHolder.java
@@ -17,11 +17,14 @@
package com.android.providers.media.photopicker.ui;
import android.content.Context;
+import android.view.View;
import android.view.ViewGroup;
-import android.widget.VideoView;
+import android.widget.ImageView;
import androidx.viewpager2.widget.ViewPager2;
+import com.google.android.exoplayer2.ui.StyledPlayerView;
+
import com.android.providers.media.R;
import com.android.providers.media.photopicker.data.model.Item;
@@ -29,40 +32,13 @@
* ViewHolder of a video item within the {@link ViewPager2}
*/
public class PreviewVideoHolder extends BaseViewHolder {
- private final VideoView mVideoView;
-
public PreviewVideoHolder(Context context, ViewGroup parent) {
super(context, parent, R.layout.item_video_preview);
- mVideoView = itemView.findViewById(R.id.preview_videoView);
}
@Override
public void bind() {
- final Item item = (Item) itemView.getTag();
- mVideoView.setVideoURI(item.getContentUri());
- }
-
- @Override
- public void onViewAttachedToWindow() {
- super.onViewAttachedToWindow();
- mVideoView.setOnPreparedListener(mp -> {
- mp.setLooping(true);
- // For simplicity, we will always start the video from the beginning.
- mp.seekTo(0);
- mp.start();
- });
- }
-
- @Override
- public void onViewDetachedFromWindow() {
- super.onViewDetachedFromWindow();
- mVideoView.pause();
- }
-
- @Override
- public void onViewRecycled() {
- super.onViewRecycled();
- // This will deallocate any MediaPlayer resources it has been holding
- mVideoView.stopPlayback();
+ // Video playback needs granular page state events and hence video playback is initiated by
+ // ViewPagerWrapper and handled by PlaybackHandler#handleVideoPlayback
}
}
diff --git a/src/com/android/providers/media/photopicker/ui/ViewPager2Wrapper.java b/src/com/android/providers/media/photopicker/ui/ViewPager2Wrapper.java
index 6e5a2b5..1678bbf 100644
--- a/src/com/android/providers/media/photopicker/ui/ViewPager2Wrapper.java
+++ b/src/com/android/providers/media/photopicker/ui/ViewPager2Wrapper.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.view.View;
+import androidx.viewpager2.widget.CompositePageTransformer;
import androidx.viewpager2.widget.MarginPageTransformer;
import androidx.viewpager2.widget.ViewPager2;
@@ -45,12 +46,15 @@
final Context context = mViewPager.getContext();
- mAdapter = new PreviewAdapter(new ImageLoader(context));
+ mAdapter = new PreviewAdapter(context);
mAdapter.updateItemList(selectedItems);
mViewPager.setAdapter(mAdapter);
- mViewPager.setPageTransformer(new MarginPageTransformer(
+ CompositePageTransformer compositePageTransformer = new CompositePageTransformer();
+ compositePageTransformer.addTransformer(new MarginPageTransformer(
context.getResources().getDimensionPixelSize(R.dimen.preview_viewpager_margin)));
+ compositePageTransformer.addTransformer(new PlayerPageTransformer());
+ mViewPager.setPageTransformer(compositePageTransformer);
}
/**
@@ -74,14 +78,31 @@
return mAdapter.getItem(position);
}
- public void onResume() {
- // This is necessary to ensure we call ViewHolder#bind() onResume()
- mAdapter.notifyDataSetChanged();
+ public void onStop() {
+ mAdapter.onStop();
+ }
+
+ public void onStart() {
+ // TODO(b/197083539): Restore the playback state here.
+ // This forces PageTransformer#transformPage call and assists in ExoPlayer initialization.
+ mViewPager.requestTransform();
}
public void onDestroy() {
for (ViewPager2.OnPageChangeCallback callback : mOnPageChangeCallbacks) {
mViewPager.unregisterOnPageChangeCallback(callback);
}
+ mOnPageChangeCallbacks.clear();
+ }
+
+ private class PlayerPageTransformer implements ViewPager2.PageTransformer {
+ @Override
+ public void transformPage(View view, float position) {
+ // We are only interested in position == 0.0. Only position=0.0 indicates that the page
+ // is selected.
+ if (position != 0) return;
+
+ mAdapter.handlePageSelected(view);
+ }
}
}
diff --git a/tests/Android.bp b/tests/Android.bp
index 87a353c..6277a2e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -139,6 +139,7 @@
"androidx.fragment_fragment",
"androidx.vectordrawable_vectordrawable-animated",
"androidx.exifinterface_exifinterface",
+ "exoplayer2.15.1"
],
certificate: "media",
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectLongPressTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectLongPressTest.java
index a59d02b..7ad186d 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectLongPressTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectLongPressTest.java
@@ -101,12 +101,9 @@
registerIdlingResourceAndWaitForIdle();
- // Since there is no video in the video file, we get an error.
- onView(withText(android.R.string.ok)).perform(click());
-
- // Verify videoView is displayed
+ // Verify video player is displayed
assertMultiSelectLongPressCommonLayoutMatches();
- onView(withId(R.id.preview_videoView)).check(matches(isDisplayed()));
+ onView(withId(R.id.preview_player_view)).check(matches(isDisplayed()));
// Verify no special format icon is previewed
onView(withId(PREVIEW_MOTION_PHOTO_ID)).check(doesNotExist());
onView(withId(PREVIEW_GIF_ID)).check(doesNotExist());
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectTest.java
index 84306a3..d45290d 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PreviewMultiSelectTest.java
@@ -69,7 +69,7 @@
@RunWith(AndroidJUnit4ClassRunner.class)
public class PreviewMultiSelectTest extends PhotoPickerBaseTest {
- private static final int VIDEO_VIEW_ID = R.id.preview_videoView;
+ private static final int PLAYER_VIEW_ID = R.id.preview_player_view;
@Rule
public ActivityScenarioRule<PhotoPickerTestActivity> mRule
@@ -211,11 +211,12 @@
assertSpecialFormatBadgeDoesNotExist();
swipeLeftAndWait();
- // Since there is no video in the video file, we get an error.
- onView(withText(android.R.string.ok)).perform(click());
// 3. Video item
assertMultiSelectPreviewCommonLayoutDisplayed();
- onView(ViewPagerMatcher(PREVIEW_VIEW_PAGER_ID, VIDEO_VIEW_ID))
+ // TODO(b/197083539): We don't check the video image to be visible or not because its
+ // visibility is time sensitive. Try waiting till player is ready and assert that video
+ // image is no more visible.
+ onView(ViewPagerMatcher(PREVIEW_VIEW_PAGER_ID, PLAYER_VIEW_ID))
.check(matches(isDisplayed()));
// Verify no special format icon is previewed
assertSpecialFormatBadgeDoesNotExist();
@@ -313,21 +314,19 @@
onView(withId(VIEW_SELECTED_BUTTON_ID)).perform(click());
registerIdlingResourceAndWaitForIdle();
- // Since there is no video in the video file, we get an error.
- onView(withText(android.R.string.ok)).perform(click());
assertMultiSelectPreviewCommonLayoutDisplayed();
// Verify that "View Selected" shows the video item, not the image item that was previewed
// earlier with preview on long press
- onView(ViewPagerMatcher(PREVIEW_VIEW_PAGER_ID, VIDEO_VIEW_ID))
+ onView(ViewPagerMatcher(PREVIEW_VIEW_PAGER_ID, PLAYER_VIEW_ID))
.check(matches(isDisplayed()));
// Swipe and verify we don't preview the image item
swipeLeftAndWait();
- onView(ViewPagerMatcher(PREVIEW_VIEW_PAGER_ID, VIDEO_VIEW_ID))
+ onView(ViewPagerMatcher(PREVIEW_VIEW_PAGER_ID, PLAYER_VIEW_ID))
.check(matches(isDisplayed()));
swipeRightAndWait();
- onView(ViewPagerMatcher(PREVIEW_VIEW_PAGER_ID, VIDEO_VIEW_ID))
+ onView(ViewPagerMatcher(PREVIEW_VIEW_PAGER_ID, PLAYER_VIEW_ID))
.check(matches(isDisplayed()));
}
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java b/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
index 8d847ef..8073cd2 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PreviewSingleSelectTest.java
@@ -115,12 +115,9 @@
registerIdlingResourceAndWaitForIdle();
- // Since there is no video in the video file, we get an error.
- onView(withText(android.R.string.ok)).perform(click());
-
- // Verify videoView is displayed
+ // Verify video player is displayed
assertSingleSelectCommonLayoutMatches();
- onView(withId(R.id.preview_videoView)).check(matches(isDisplayed()));
+ onView(withId(R.id.preview_player_view)).check(matches(isDisplayed()));
// Verify no special format icon is previewed
onView(withId(PREVIEW_MOTION_PHOTO_ID)).check(doesNotExist());
onView(withId(PREVIEW_GIF_ID)).check(doesNotExist());