Skip to content

Commit a6fc1e2

Browse files
committed
feat: Implements poster and playlist support on android
1 parent 7e95e96 commit a6fc1e2

11 files changed

+385
-61
lines changed

android/src/main/java/jp/manse/offlineVideo/OfflineVideoOwner.java android/src/main/java/jp/manse/BrightcovePlayerAccount.java

+60-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
package jp.manse.offlineVideo;
1+
package jp.manse;
22

33
import android.os.Handler;
44
import android.os.Looper;
55
import android.util.Log;
66

7+
import com.brightcove.player.edge.Catalog;
78
import com.brightcove.player.edge.OfflineCallback;
89
import com.brightcove.player.edge.OfflineCatalog;
10+
import com.brightcove.player.edge.PlaylistListener;
11+
import com.brightcove.player.model.Playlist;
912
import com.brightcove.player.model.Video;
1013
import com.brightcove.player.network.DownloadStatus;
1114
import com.facebook.react.bridge.NativeArray;
@@ -17,16 +20,23 @@
1720
import java.util.ArrayList;
1821
import java.util.List;
1922

20-
import jp.manse.DefaultEventEmitter;
23+
import jp.manse.util.DefaultEventEmitter;
2124

22-
public class OfflineVideoOwner implements OfflineVideoDownloadSession.OnOfflineVideoDownloadSessionListener {
25+
public class BrightcovePlayerAccount implements OfflineVideoDownloadSession.OnOfflineVideoDownloadSessionListener {
2326
final private static int FPS = 40;
2427
final private static String DEBUG_TAG = "brightcoveplayer";
2528
final private static String ERROR_CODE = "error";
2629
final private static String ERROR_MESSAGE_DUPLICATE_SESSION = "Offline video or download session already exists";
2730
final private static String ERROR_MESSAGE_DELETE = "Could not delete video";
31+
final private static String ERROR_MESSAGE_PLAYLIST = "Failed to load playlist";
2832
final private static String CALLBACK_KEY_VIDEO_TOKEN = "videoToken";
2933
final private static String CALLBACK_KEY_DOWNLOAD_PROGRESS = "downloadProgress";
34+
final private static String CALLBACK_KEY_ACCOUNT_ID = "accountId";
35+
final private static String CALLBACK_KEY_VIDEO_ID = "videoId";
36+
final private static String CALLBACK_KEY_REFERENCE_ID = "referenceId";
37+
final private static String CALLBACK_KEY_NAME = "name";
38+
final private static String CALLBACK_KEY_DESCRIPTION = "description";
39+
final private static String CALLBACK_KEY_DURATION = "duration";
3040

3141
private ReactApplicationContext context;
3242
public String accountId;
@@ -37,13 +47,15 @@ public class OfflineVideoOwner implements OfflineVideoDownloadSession.OnOfflineV
3747
private boolean getOfflineVideoStatusesRunning = false;
3848
private List<Promise> getOfflineVideoStatusesPendingPromises = new ArrayList<>();
3949
private List<Video> allDownloadedVideos;
50+
private Catalog catalog;
4051
private OfflineCatalog offlineCatalog;
4152

42-
public OfflineVideoOwner(final ReactApplicationContext context, final String accountId, final String policyKey) {
53+
public BrightcovePlayerAccount(final ReactApplicationContext context, final String accountId, final String policyKey) {
4354
this.context = context;
4455
this.accountId = accountId;
4556
this.policyKey = policyKey;
4657
handler = new Handler(Looper.myLooper());
58+
this.catalog = new Catalog(DefaultEventEmitter.sharedEventEmitter, accountId, policyKey);
4759
this.offlineCatalog = new OfflineCatalog(context, DefaultEventEmitter.sharedEventEmitter, accountId, policyKey);
4860
this.offlineCatalog.setMeteredDownloadAllowed(true);
4961
this.offlineCatalog.setMobileDownloadAllowed(true);
@@ -52,7 +64,7 @@ public OfflineVideoOwner(final ReactApplicationContext context, final String acc
5264
@Override
5365
public void onSuccess(List<Video> videos) {
5466
for (Video video : videos) {
55-
OfflineVideoDownloadSession session = new OfflineVideoDownloadSession(context, accountId, policyKey, OfflineVideoOwner.this);
67+
OfflineVideoDownloadSession session = new OfflineVideoDownloadSession(context, accountId, policyKey, BrightcovePlayerAccount.this);
5668
session.resumeDownload(video);
5769
offlineVideoDownloadSessions.add(session);
5870
}
@@ -148,6 +160,34 @@ public void onFailure(Throwable throwable) {
148160
}
149161
}
150162

163+
public void getPlaylistWithPlaylistId(String playlistId, final Promise promise) {
164+
catalog.findPlaylistByID(playlistId, new PlaylistListener() {
165+
@Override
166+
public void onPlaylist(Playlist playlist) {
167+
promise.resolve(collectNativePlaylist(accountId, playlist));
168+
}
169+
170+
@Override
171+
public void onError(String error) {
172+
promise.reject(ERROR_CODE, ERROR_MESSAGE_PLAYLIST);
173+
}
174+
});
175+
}
176+
177+
public void getPlaylistWithReferenceId(String referenceId, final Promise promise) {
178+
catalog.findPlaylistByReferenceID(referenceId, new PlaylistListener() {
179+
@Override
180+
public void onPlaylist(Playlist playlist) {
181+
promise.resolve(collectNativePlaylist(accountId, playlist));
182+
}
183+
184+
@Override
185+
public void onError(String error) {
186+
promise.reject(ERROR_CODE, ERROR_MESSAGE_PLAYLIST);
187+
}
188+
});
189+
}
190+
151191
private NativeArray collectNativeOfflineVideoStatuses() {
152192
WritableNativeArray statuses = new WritableNativeArray();
153193
for (Video video : this.allDownloadedVideos) {
@@ -174,6 +214,21 @@ private NativeArray collectNativeOfflineVideoStatuses() {
174214
return statuses;
175215
}
176216

217+
private NativeArray collectNativePlaylist(String accountId, Playlist playlist) {
218+
WritableNativeArray result = new WritableNativeArray();
219+
for (Video video : playlist.getVideos()) {
220+
WritableNativeMap map = new WritableNativeMap();
221+
map.putString(CALLBACK_KEY_ACCOUNT_ID, accountId);
222+
map.putString(CALLBACK_KEY_VIDEO_ID, video.getId());
223+
map.putString(CALLBACK_KEY_REFERENCE_ID, video.getReferenceId());
224+
map.putString(CALLBACK_KEY_NAME, video.getName());
225+
map.putString(CALLBACK_KEY_DESCRIPTION, video.getDescription());
226+
map.putInt(CALLBACK_KEY_DURATION, video.getDuration());
227+
result.pushMap(map);
228+
}
229+
return result;
230+
}
231+
177232
private boolean hasOfflineVideoDownloadSessionWithReferenceId(String referenceId) {
178233
for (OfflineVideoDownloadSession session : this.offlineVideoDownloadSessions) {
179234
if (referenceId.equals(session.referenceId)) return true;

android/src/main/java/jp/manse/BrightcovePlayerManager.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import android.support.annotation.Nullable;
44

55
import com.facebook.infer.annotation.Assertions;
6+
import com.facebook.react.bridge.ReactApplicationContext;
67
import com.facebook.react.bridge.ReadableArray;
78
import com.facebook.react.common.MapBuilder;
89
import com.facebook.react.uimanager.SimpleViewManager;
@@ -25,7 +26,12 @@ public class BrightcovePlayerManager extends SimpleViewManager<BrightcovePlayerV
2526
public static final String EVENT_CHANGE_DURATION = "change_duration";
2627
public static final String EVENT_UPDATE_BUFFER_PROGRESS = "update_buffer_progress";
2728

28-
private static ThemedReactContext context;
29+
private ReactApplicationContext applicationContext;
30+
31+
public BrightcovePlayerManager(ReactApplicationContext context) {
32+
super();
33+
this.applicationContext = context;
34+
}
2935

3036
@Override
3137
public String getName() {
@@ -34,8 +40,7 @@ public String getName() {
3440

3541
@Override
3642
public BrightcovePlayerView createViewInstance(ThemedReactContext ctx) {
37-
context = ctx;
38-
BrightcovePlayerView brightcovePlayerView = new BrightcovePlayerView(ctx);
43+
BrightcovePlayerView brightcovePlayerView = new BrightcovePlayerView(ctx, applicationContext);
3944
return brightcovePlayerView;
4045
}
4146

android/src/main/java/jp/manse/BrightcovePlayerPackage.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactAppli
1717
@Override
1818
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
1919
return Arrays.<ViewManager>asList(
20-
new BrightcovePlayerManager()
20+
new BrightcovePlayerManager(reactContext),
21+
new BrightcovePlayerPosterManager(reactContext)
2122
);
2223
}
2324
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package jp.manse;
2+
3+
import com.facebook.react.bridge.ReactApplicationContext;
4+
import com.facebook.react.uimanager.SimpleViewManager;
5+
import com.facebook.react.uimanager.ThemedReactContext;
6+
import com.facebook.react.uimanager.annotations.ReactProp;
7+
8+
9+
public class BrightcovePlayerPosterManager extends SimpleViewManager<BrightcovePlayerPosterView> {
10+
public static final String REACT_CLASS = "BrightcovePlayerPoster";
11+
12+
private static ThemedReactContext context;
13+
private ReactApplicationContext applicationContext;
14+
15+
public BrightcovePlayerPosterManager(ReactApplicationContext context) {
16+
this.applicationContext = context;
17+
}
18+
19+
20+
@Override
21+
public String getName() {
22+
return REACT_CLASS;
23+
}
24+
25+
@Override
26+
public BrightcovePlayerPosterView createViewInstance(ThemedReactContext ctx) {
27+
context = ctx;
28+
BrightcovePlayerPosterView brightcovePlayerPosterView = new BrightcovePlayerPosterView(ctx, applicationContext);
29+
return brightcovePlayerPosterView;
30+
}
31+
32+
@ReactProp(name = "policyKey")
33+
public void setPolicyKey(BrightcovePlayerPosterView view, String policyKey) {
34+
view.setPolicyKey(policyKey);
35+
}
36+
37+
@ReactProp(name = "accountId")
38+
public void setAccountId(BrightcovePlayerPosterView view, String accountId) {
39+
view.setAccountId(accountId);
40+
}
41+
42+
@ReactProp(name = "videoId")
43+
public void setVideoId(BrightcovePlayerPosterView view, String videoId) {
44+
view.setVideoId(videoId);
45+
}
46+
47+
@ReactProp(name = "referenceId")
48+
public void setReferenceId(BrightcovePlayerPosterView view, String referenceId) {
49+
view.setReferenceId(referenceId);
50+
}
51+
52+
@ReactProp(name = "videoToken")
53+
public void setVideoToken(BrightcovePlayerPosterView view, String videoToken) {
54+
view.setVideoToken(videoToken);
55+
}
56+
57+
@ReactProp(name = "resizeMode")
58+
public void setResizeMode(BrightcovePlayerPosterView view, String resizeMode) {
59+
view.setResizeMode(resizeMode);
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package jp.manse;
2+
3+
import android.graphics.Color;
4+
import android.view.ViewGroup;
5+
import android.widget.ImageView;
6+
import android.widget.RelativeLayout;
7+
8+
import com.brightcove.player.edge.Catalog;
9+
import com.brightcove.player.edge.OfflineCatalog;
10+
import com.brightcove.player.edge.VideoListener;
11+
import com.brightcove.player.model.Video;
12+
import com.facebook.react.bridge.LifecycleEventListener;
13+
import com.facebook.react.bridge.ReactApplicationContext;
14+
import com.facebook.react.uimanager.ThemedReactContext;
15+
16+
import jp.manse.util.DefaultEventEmitter;
17+
import jp.manse.util.ImageLoader;
18+
19+
public class BrightcovePlayerPosterView extends RelativeLayout implements LifecycleEventListener {
20+
private ThemedReactContext context;
21+
private ReactApplicationContext applicationContext;
22+
private ImageView imageView;
23+
private String policyKey;
24+
private String accountId;
25+
private String videoId;
26+
private String referenceId;
27+
private String videoToken;
28+
private Catalog catalog;
29+
private OfflineCatalog offlineCatalog;
30+
private ImageLoader imageLoader;
31+
32+
public BrightcovePlayerPosterView(ThemedReactContext context, ReactApplicationContext applicationContext) {
33+
super(context);
34+
this.context = context;
35+
this.applicationContext = applicationContext;
36+
this.applicationContext.addLifecycleEventListener(this);
37+
this.imageView = new ImageView(context);
38+
this.imageView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
39+
this.imageView.setBackgroundColor(Color.RED);
40+
this.imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
41+
this.addView(imageView);
42+
this.requestLayout();
43+
}
44+
45+
public void setPolicyKey(String policyKey) {
46+
this.policyKey = policyKey;
47+
this.loadPoster();
48+
}
49+
50+
public void setAccountId(String accountId) {
51+
this.accountId = accountId;
52+
this.loadPoster();
53+
}
54+
55+
public void setVideoId(String videoId) {
56+
this.videoId = videoId;
57+
this.referenceId = null;
58+
this.loadPoster();
59+
}
60+
61+
public void setReferenceId(String referenceId) {
62+
this.referenceId = referenceId;
63+
this.videoId = null;
64+
this.loadPoster();
65+
}
66+
67+
public void setVideoToken(String videoToken) {
68+
this.videoToken = videoToken;
69+
this.loadPoster();
70+
}
71+
72+
public void setResizeMode(String resizeMode) {
73+
if ("contain".equals(resizeMode)) {
74+
this.imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
75+
} else if ("fit".equals(resizeMode)) {
76+
this.imageView.setScaleType(ImageView.ScaleType.FIT_XY);
77+
} else {
78+
this.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
79+
}
80+
}
81+
82+
private void loadPoster() {
83+
if (this.videoToken != null && !this.videoToken.equals("")) {
84+
this.offlineCatalog = new OfflineCatalog(this.context, DefaultEventEmitter.sharedEventEmitter, this.accountId, this.policyKey);
85+
Video video = this.offlineCatalog.findOfflineVideoById(this.videoToken);
86+
loadImage(video);
87+
return;
88+
}
89+
VideoListener listener = new VideoListener() {
90+
@Override
91+
public void onVideo(Video video) {
92+
loadImage(video);
93+
}
94+
};
95+
this.catalog = new Catalog(DefaultEventEmitter.sharedEventEmitter, this.accountId, this.policyKey);
96+
if (this.videoId != null) {
97+
this.catalog.findVideoByID(this.videoId, listener);
98+
} else if (this.referenceId != null) {
99+
this.catalog.findVideoByReferenceID(this.referenceId, listener);
100+
}
101+
}
102+
103+
private void loadImage(Video video) {
104+
if (video == null) {
105+
this.imageView.setImageResource(android.R.color.transparent);
106+
return;
107+
}
108+
String url = video.getPosterImage().toString();
109+
if (url == null) {
110+
this.imageView.setImageResource(android.R.color.transparent);
111+
return;
112+
}
113+
if (this.imageLoader != null) {
114+
this.imageLoader.cancel(true);
115+
}
116+
this.imageLoader = new ImageLoader(this.imageView);
117+
this.imageLoader.execute(url);
118+
}
119+
120+
@Override
121+
public void onHostResume() {
122+
123+
}
124+
125+
@Override
126+
public void onHostPause() {
127+
128+
}
129+
130+
@Override
131+
public void onHostDestroy() {
132+
if (this.imageLoader != null) {
133+
this.imageLoader.cancel(true);
134+
}
135+
this.applicationContext.removeLifecycleEventListener(this);
136+
}
137+
}

0 commit comments

Comments
 (0)