| Index: chrome/android/java/src/org/chromium/chrome/browser/media/remote/CastNotificationControl.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/CastNotificationControl.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/CastNotificationControl.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9864d7b4a7c49e0d91c2a2c06916b5eeba3eebe8
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/CastNotificationControl.java
|
| @@ -0,0 +1,211 @@
|
| +// Copyright 2016 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.remote;
|
| +
|
| +import android.content.Context;
|
| +import android.content.Intent;
|
| +import android.graphics.Bitmap;
|
| +import android.media.AudioManager;
|
| +
|
| +import org.chromium.base.VisibleForTesting;
|
| +import org.chromium.chrome.R;
|
| +import org.chromium.chrome.browser.media.remote.RemoteVideoInfo.PlayerState;
|
| +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.tab.Tab;
|
| +
|
| +import javax.annotation.Nullable;
|
| +
|
| +/**
|
| + * Notification control controls the cast notification and lock screen, using
|
| + * {@link MediaNotificationManager}
|
| + */
|
| +public class CastNotificationControl implements MediaRouteController.UiListener,
|
| + MediaNotificationListener, AudioManager.OnAudioFocusChangeListener {
|
| +
|
| + private static CastNotificationControl sInstance;
|
| +
|
| + private Bitmap mPosterBitmap;
|
| + protected MediaRouteController mMediaRouteController = null;
|
| + private MediaNotificationInfo.Builder mNotificationBuilder;
|
| + private Context mContext;
|
| + private PlayerState mState;
|
| + private String mTitle = "";
|
| + private AudioManager mAudioManager;
|
| +
|
| + private boolean mIsShowing = false;
|
| +
|
| + private static final Object LOCK = new Object();
|
| +
|
| +
|
| + private CastNotificationControl(Context context) {
|
| + mContext = context;
|
| + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
| + }
|
| + /**
|
| + * Get the unique NotificationControl, creating it if necessary.
|
| + * @param context The context of the activity
|
| + * @param mediaRouteController The current mediaRouteController, if any.
|
| + * @return a {@code LockScreenTransportControl} based on the platform's SDK API or null if the
|
| + * current platform's SDK API is not supported.
|
| + */
|
| + public static CastNotificationControl getOrCreate(Context context,
|
| + @Nullable MediaRouteController mediaRouteController) {
|
| + synchronized (LOCK) {
|
| + if (sInstance == null) {
|
| + sInstance = new CastNotificationControl(context);
|
| + }
|
| + sInstance.mMediaRouteController = mediaRouteController;
|
| + return sInstance;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @return the poster bitmap previously assigned with {@link #setPosterBitmap(Bitmap)}, or
|
| + * {@code null} if the poster bitmap has not yet been assigned.
|
| + */
|
| + public final Bitmap getPosterBitmap() {
|
| + return mPosterBitmap;
|
| + }
|
| +
|
| + /**
|
| + * Sets the poster bitmap to display on the TransportControl.
|
| + */
|
| + public final void setPosterBitmap(Bitmap posterBitmap) {
|
| + if (mPosterBitmap == posterBitmap
|
| + || (mPosterBitmap != null && mPosterBitmap.sameAs(posterBitmap))) {
|
| + return;
|
| + }
|
| + mPosterBitmap = posterBitmap;
|
| + if (mNotificationBuilder == null || mMediaRouteController == null) return;
|
| + mNotificationBuilder.setImage(mMediaRouteController.getPoster());
|
| + updateNotification();
|
| + }
|
| +
|
| + public void hide() {
|
| + mIsShowing = false;
|
| + MediaNotificationManager.hide(Tab.INVALID_TAB_ID, R.id.remote_notification);
|
| + mAudioManager.abandonAudioFocus(this);
|
| + mMediaRouteController.removeUiListener(this);
|
| + }
|
| +
|
| + public void show(PlayerState initialState) {
|
| + mMediaRouteController.addUiListener(this);
|
| + // TODO(aberent): investigate why this is necessary, and whether we are handling
|
| + // it correctly. Also add code to restore it when Chrome is resumed.
|
| + mAudioManager.requestAudioFocus(this, AudioManager.USE_DEFAULT_STREAM_TYPE,
|
| + AudioManager.AUDIOFOCUS_GAIN);
|
| + Intent contentIntent = new Intent(mContext, ExpandedControllerActivity.class);
|
| + mNotificationBuilder = new MediaNotificationInfo.Builder()
|
| + .setPaused(false)
|
| + .setPrivate(false)
|
| + .setIcon(R.drawable.ic_notification_media_route)
|
| + .setContentIntent(contentIntent)
|
| + .setImage(mMediaRouteController.getPoster())
|
| + .setId(R.id.remote_notification)
|
| + .setListener(this);
|
| + mState = initialState;
|
| + updateNotification();
|
| + mIsShowing = true;
|
| + }
|
| +
|
| + public void setRouteController(MediaRouteController controller) {
|
| + mMediaRouteController = controller;
|
| + }
|
| +
|
| + private void updateNotification() {
|
| + mNotificationBuilder.setTitle(mTitle);
|
| + if (mState == PlayerState.PAUSED || mState == PlayerState.PLAYING) {
|
| + mNotificationBuilder.setPaused(mState != PlayerState.PLAYING);
|
| + mNotificationBuilder.setActions(MediaNotificationInfo.ACTION_STOP
|
| + | MediaNotificationInfo.ACTION_PLAY_PAUSE);
|
| + MediaNotificationManager.show(mContext, mNotificationBuilder.build());
|
| + } else if (mState == PlayerState.LOADING) {
|
| + mNotificationBuilder.setActions(MediaNotificationInfo.ACTION_STOP);
|
| + MediaNotificationManager.show(mContext, mNotificationBuilder.build());
|
| + } else {
|
| + hide();
|
| + }
|
| + }
|
| +
|
| + // TODO(aberent) at the moment this is only called from a test, but it should be called if the
|
| + // poster changes.
|
| + public void onPosterBitmapChanged() {
|
| + if (mNotificationBuilder == null || mMediaRouteController == null) return;
|
| + mNotificationBuilder.setImage(mMediaRouteController.getPoster());
|
| + updateNotification();
|
| + }
|
| +
|
| + // MediaRouteController.UiListener implementation.
|
| + @Override
|
| + public void onPlaybackStateChanged(PlayerState oldState, PlayerState newState) {
|
| + mState = newState;
|
| + updateNotification();
|
| + }
|
| +
|
| + @Override
|
| + public void onRouteSelected(String name, MediaRouteController mediaRouteController) {
|
| + }
|
| +
|
| + @Override
|
| + public void onRouteUnselected(MediaRouteController mediaRouteController) {
|
| + hide();
|
| + }
|
| +
|
| + @Override
|
| + public void onPrepared(MediaRouteController mediaRouteController) {
|
| + }
|
| +
|
| + @Override
|
| + public void onError(int errorType, String message) {
|
| + }
|
| +
|
| + @Override
|
| + public void onDurationUpdated(long durationMillis) {
|
| + }
|
| +
|
| + @Override
|
| + public void onPositionChanged(long positionMillis) {
|
| + }
|
| +
|
| + @Override
|
| + public void onTitleChanged(String title) {
|
| + mTitle = (title == null) ? "" : title;
|
| + updateNotification();
|
| + }
|
| +
|
| + // MediaNotificationListener methods
|
| + @Override
|
| + public void onPlay(int actionSource) {
|
| + mMediaRouteController.resume();
|
| + }
|
| +
|
| + @Override
|
| + public void onPause(int actionSource) {
|
| + mMediaRouteController.pause();
|
| + }
|
| +
|
| + @Override
|
| + public void onStop(int actionSource) {
|
| + mMediaRouteController.release();
|
| + }
|
| +
|
| + // AudioManager.OnAudioFocusChangeListener methods
|
| + @Override
|
| + public void onAudioFocusChange(int focusChange) {
|
| + // Do nothing. The remote player should keep playing.
|
| + }
|
| +
|
| + @VisibleForTesting
|
| + static CastNotificationControl getForTests() {
|
| + return sInstance;
|
| + }
|
| +
|
| + @VisibleForTesting
|
| + boolean isShowingForTests() {
|
| + return mIsShowing;
|
| + }
|
| +}
|
|
|