Commit caa495bc authored by Zhiqiang Zhang's avatar Zhiqiang Zhang Committed by Commit Bot

[Android MR] Migrate MediaNotification for Cast/MediaFling

This CL migrates the MediaNotification into a separate CafNotificationController
class, to handle all the notification logic.

Bug: 711860
Change-Id: Ib01cd61f9e84a925a122a5f01161336d801caade
Reviewed-on: https://chromium-review.googlesource.com/1217752
Commit-Queue: Zhiqiang Zhang <zqzhang@chromium.org>
Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/master@{#590461}
parent 160e72c5
......@@ -217,6 +217,7 @@ public abstract class CafBaseMediaRouteProvider
public void onSessionStarted(CastSession session, String sessionId) {
Log.d(TAG, "onSessionStarted");
mSessionController.attachToCastSession(session);
sessionController().getNotificationController().onSessionStarted();
MediaSink sink = mPendingCreateRouteRequestInfo.sink;
MediaSource source = mPendingCreateRouteRequestInfo.source;
......@@ -261,17 +262,20 @@ public abstract class CafBaseMediaRouteProvider
///////////////////////////////////////////////////////
private void handleSessionEnd(String error) {
mSessionController.detachFromCastSession();
getAndroidMediaRouter().selectRoute(getAndroidMediaRouter().getDefaultRoute());
removeAllRoutesWithError(error);
if (mPendingCreateRouteRequestInfo == null) {
if (mPendingCreateRouteRequestInfo != null) {
// The Cast SDK notifies about session ending when a route is unselected, even when
// there's no current session. Because CastSessionController unselects the route to set
// the receiver app ID, this needs to be guarded by a pending request null check to make
// sure the listener is not unregistered during a session relaunch.
CastUtils.getCastContext().getSessionManager().removeSessionManagerListener(
this, CastSession.class);
return;
}
mSessionController.getNotificationController().onSessionEnded();
mSessionController.detachFromCastSession();
mSessionController.onSessionEnded();
getAndroidMediaRouter().selectRoute(getAndroidMediaRouter().getDefaultRoute());
removeAllRoutesWithError(error);
CastUtils.getCastContext().getSessionManager().removeSessionManagerListener(
this, CastSession.class);
}
public @NonNull MediaRouter getAndroidMediaRouter() {
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.media.router.caf;
import android.content.Intent;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.MediaStatus;
import com.google.android.gms.cast.framework.media.RemoteMediaClient;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.media.ui.MediaNotificationInfo;
import org.chromium.chrome.browser.media.ui.MediaNotificationListener;
import org.chromium.chrome.browser.media.ui.MediaNotificationManager;
import org.chromium.chrome.browser.metrics.MediaNotificationUma;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.content_public.common.MediaMetadata;
/** Controller for updating media notification for Casting and MediaFling. */
public class CafNotificationController implements MediaNotificationListener {
private MediaNotificationInfo.Builder mNotificationBuilder;
private final CastSessionController mSessionController;
public CafNotificationController(CastSessionController sessionController) {
mSessionController = sessionController;
}
/** Called when session started. */
public void onSessionStarted() {
Intent contentIntent =
Tab.createBringTabToFrontIntent(mSessionController.getRouteCreationInfo().tabId);
if (contentIntent != null) {
contentIntent.putExtra(MediaNotificationUma.INTENT_EXTRA_NAME,
MediaNotificationUma.Source.PRESENTATION);
}
mNotificationBuilder =
new MediaNotificationInfo.Builder()
.setPaused(false)
.setOrigin(mSessionController.getRouteCreationInfo().origin)
// TODO(zqzhang): the same session might have more than one tab id. Should
// we track the last foreground alive tab and update the notification with
// it?
.setTabId(mSessionController.getRouteCreationInfo().tabId)
.setPrivate(mSessionController.getRouteCreationInfo().isIncognito)
.setActions(MediaNotificationInfo.ACTION_STOP)
.setContentIntent(contentIntent)
.setNotificationSmallIcon(R.drawable.ic_notification_media_route)
.setDefaultNotificationLargeIcon(R.drawable.cast_playing_square)
.setId(R.id.presentation_notification)
.setListener(this);
updateNotificationMetadata();
MediaNotificationManager.show(mNotificationBuilder.build());
}
/** Called when session ended. */
public void onSessionEnded() {
MediaNotificationManager.clear(R.id.presentation_notification);
mNotificationBuilder = null;
}
/** Called when media status updated. */
public void onStatusUpdated() {
if (mNotificationBuilder == null) return;
if (!mSessionController.isConnected()) return;
MediaStatus mediaStatus = mSessionController.getRemoteMediaClient().getMediaStatus();
if (mediaStatus == null) return;
int playerState = mediaStatus.getPlayerState();
if (playerState == MediaStatus.PLAYER_STATE_PAUSED
|| playerState == MediaStatus.PLAYER_STATE_PLAYING) {
mNotificationBuilder.setPaused(playerState != MediaStatus.PLAYER_STATE_PLAYING);
mNotificationBuilder.setActions(
MediaNotificationInfo.ACTION_STOP | MediaNotificationInfo.ACTION_PLAY_PAUSE);
} else {
mNotificationBuilder.setActions(MediaNotificationInfo.ACTION_STOP);
}
MediaNotificationManager.show(mNotificationBuilder.build());
}
/** Called when media metadata updated. */
public void onMetadataUpdated() {
if (mNotificationBuilder == null) return;
updateNotificationMetadata();
MediaNotificationManager.show(mNotificationBuilder.build());
}
private void updateNotificationMetadata() {
MediaMetadata notificationMetadata = new MediaMetadata("", "", "");
mNotificationBuilder.setMetadata(notificationMetadata);
if (!mSessionController.isConnected()) return;
CastDevice castDevice = mSessionController.getSession().getCastDevice();
if (castDevice != null) notificationMetadata.setTitle(castDevice.getFriendlyName());
RemoteMediaClient remoteMediaClient = mSessionController.getRemoteMediaClient();
com.google.android.gms.cast.MediaInfo info = remoteMediaClient.getMediaInfo();
if (info == null) return;
com.google.android.gms.cast.MediaMetadata metadata = info.getMetadata();
if (metadata == null) return;
String title = metadata.getString(com.google.android.gms.cast.MediaMetadata.KEY_TITLE);
if (title != null) notificationMetadata.setTitle(title);
String artist = metadata.getString(com.google.android.gms.cast.MediaMetadata.KEY_ARTIST);
if (artist == null) {
artist = metadata.getString(com.google.android.gms.cast.MediaMetadata.KEY_ALBUM_ARTIST);
}
if (artist != null) notificationMetadata.setArtist(artist);
String album =
metadata.getString(com.google.android.gms.cast.MediaMetadata.KEY_ALBUM_TITLE);
if (album != null) notificationMetadata.setAlbum(album);
}
/////////////////////////////////////////////////////////////////////////////////////////////
// MediaNotificationListener implementation.
@Override
public void onPlay(int actionSource) {
if (!mSessionController.isConnected()) return;
mSessionController.getRemoteMediaClient().play();
}
@Override
public void onPause(int actionSource) {
if (!mSessionController.isConnected()) return;
mSessionController.getRemoteMediaClient().pause();
}
@Override
public void onStop(int actionSource) {
if (!mSessionController.isConnected()) return;
mSessionController.endSession();
}
@Override
public void onMediaSessionAction(int action) {}
}
......@@ -32,25 +32,27 @@ public class CastSessionController {
private CastSession mCastSession;
private final CafBaseMediaRouteProvider mProvider;
private MediaSink mSink;
private MediaSource mSource;
private List<String> mNamespaces = new ArrayList<String>();
private final CastListener mCastListener;
private final MediaRouter.Callback mMediaRouterCallbackForSessionLaunch;
private CreateRouteRequestInfo mRouteCreationInfo;
private final CafNotificationController mNotificationController;
private final RemoteMediaClient.Callback mRemoteMediaClientCallback;
public CastSessionController(CafBaseMediaRouteProvider provider) {
mProvider = provider;
mCastListener = new CastListener();
mMediaRouterCallbackForSessionLaunch = new MediaRouterCallbackForSessionLaunch();
mNotificationController = new CafNotificationController(this);
mRemoteMediaClientCallback = new RemoteMediaClientCallback();
}
public void requestSessionLaunch() {
CreateRouteRequestInfo request = mProvider.getPendingCreateRouteRequestInfo();
mSource = request.source;
mSink = request.sink;
CastUtils.getCastContext().setReceiverApplicationId(request.source.getApplicationId());
mRouteCreationInfo = mProvider.getPendingCreateRouteRequestInfo();
CastUtils.getCastContext().setReceiverApplicationId(
mRouteCreationInfo.source.getApplicationId());
if (request.routeInfo.isSelected()) {
if (mRouteCreationInfo.routeInfo.isSelected()) {
// If a route has just been selected, CAF might not be ready yet before setting the app
// ID. So unselect and select the route will let CAF be aware that the route has been
// selected thus it can start the session.
......@@ -59,19 +61,24 @@ public class CastSessionController {
// short time, the selection might be ignored by MediaRouter, so put the reselection in
// a callback.
mProvider.getAndroidMediaRouter().addCallback(
mSource.buildRouteSelector(), mMediaRouterCallbackForSessionLaunch);
mRouteCreationInfo.source.buildRouteSelector(),
mMediaRouterCallbackForSessionLaunch);
mProvider.getAndroidMediaRouter().unselect(MediaRouter.UNSELECT_REASON_UNKNOWN);
} else {
request.routeInfo.select();
mRouteCreationInfo.routeInfo.select();
}
}
public MediaSource getSource() {
return mSource;
return (mRouteCreationInfo != null) ? mRouteCreationInfo.source : null;
}
public MediaSink getSink() {
return mSink;
return (mRouteCreationInfo != null) ? mRouteCreationInfo.sink : null;
}
public CreateRouteRequestInfo getRouteCreationInfo() {
return mRouteCreationInfo;
}
public CastSession getSession() {
......@@ -82,6 +89,10 @@ public class CastSessionController {
return mCastSession.getRemoteMediaClient();
}
public CafNotificationController getNotificationController() {
return mNotificationController;
}
public void endSession() {
MediaRouter mediaRouter = mProvider.getAndroidMediaRouter();
mediaRouter.selectRoute(mediaRouter.getDefaultRoute());
......@@ -125,6 +136,7 @@ public class CastSessionController {
public void attachToCastSession(CastSession session) {
mCastSession = session;
mCastSession.addCastListener(mCastListener);
getRemoteMediaClient().registerCallback(mRemoteMediaClientCallback);
updateNamespaces();
}
......@@ -133,9 +145,14 @@ public class CastSessionController {
mNamespaces.clear();
mCastSession.removeCastListener(mCastListener);
getRemoteMediaClient().unregisterCallback(mRemoteMediaClientCallback);
mCastSession = null;
}
public void onSessionEnded() {
mRouteCreationInfo = null;
}
private class CastListener extends Cast.Listener {
@Override
public void onApplicationStatusChanged() {
......@@ -226,4 +243,16 @@ public class CastSessionController {
}
}
}
private class RemoteMediaClientCallback extends RemoteMediaClient.Callback {
@Override
public void onStatusUpdated() {
mNotificationController.onStatusUpdated();
}
@Override
public void onMetadataUpdated() {
mNotificationController.onMetadataUpdated();
}
}
}
......@@ -798,6 +798,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/media/router/caf/CafBaseMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CafMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CafMessageHandler.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CafNotificationController.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CreateRouteRequestInfo.java",
"java/src/org/chromium/chrome/browser/media/router/cast/BaseMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment