Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControl.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControl.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControl.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..04488c3c5a2babde7a4470009d77be682ad452f9 |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControl.java |
| @@ -0,0 +1,177 @@ |
| +// Copyright 2014 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.BroadcastReceiver; |
| +import android.content.Context; |
| +import android.content.Intent; |
| +import android.util.Log; |
| +import android.view.KeyEvent; |
| + |
| +import org.chromium.base.CommandLine; |
| +import org.chromium.base.VisibleForTesting; |
| +import org.chromium.chrome.ChromeSwitches; |
| +import org.chromium.chrome.browser.media.remote.RemoteVideoInfo.PlayerState; |
| + |
| +import java.util.Set; |
| + |
| +import javax.annotation.Nullable; |
| + |
| +/** |
| + * An abstract base class and factory for {@link TransportControl}s that are displayed on the lock |
| + * screen. |
| + */ |
| +public abstract class LockScreenTransportControl |
| + extends TransportControl implements MediaRouteController.UiListener { |
| + private static final String TAG = "LockScreenTransportControl"; |
| + |
| + private static LockScreenTransportControl sInstance; |
| + |
| + private MediaRouteController mMediaRouteController = null; |
| + |
| + private static final Object LOCK = new Object(); |
| + |
| + private static boolean sDebug; |
| + |
| + // Needed to get round findbugs complaints. |
|
Bernhard Bauer
2015/03/13 12:18:02
Nit: "around"
aberent
2015/03/13 19:04:35
Done. Actually both are correct English, and "get
|
| + private static void setSDebug() { |
| + sDebug = CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_CAST_DEBUG_LOGS); |
| + } |
| + |
| + public LockScreenTransportControl() { |
| + setSDebug(); |
| + } |
| + |
| + /** |
| + * {@link BroadcastReceiver} that receives the media button events from the lock screen and |
| + * forwards the messages on to the {@link TransportControl}'s listeners. |
| + * |
| + * Ideally this class should be private, but public is required to create as a |
| + * BroadcastReceiver. |
| + */ |
| + public static class MediaButtonIntentReceiver extends BroadcastReceiver { |
| + @Override |
| + public void onReceive(Context context, Intent intent) { |
| + if (sDebug) Log.d(TAG, "Received intent: " + intent); |
| + if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) { |
| + KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); |
| + LockScreenTransportControl control = LockScreenTransportControl.getIfExists(); |
| + if (control == null) { |
| + Log.w(TAG, "Event received when no LockScreenTransportControl exists"); |
| + return; |
| + } |
| + Set<Listener> listeners = control.getListeners(); |
| + |
| + // Ignore ACTION_DOWN. We'll get an ACTION_UP soon enough! |
| + if (event.getAction() == KeyEvent.ACTION_DOWN) return; |
| + |
| + switch (event.getKeyCode()) { |
| + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: |
| + for (Listener listener : listeners) { |
| + if (control.isPlaying()) { |
| + listener.onPause(); |
| + } else { |
| + listener.onPlay(); |
| + } |
| + } |
| + break; |
| + case KeyEvent.KEYCODE_MEDIA_STOP: |
| + for (Listener listener : listeners) |
| + listener.onStop(); |
| + break; |
| + default: |
| + Log.w(TAG, "Unrecognized event: " + event); |
| + } |
| + } |
| + } |
| + } |
| + |
| + |
| + /** |
| + * @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 LockScreenTransportControl getOrCreate(Context context, |
| + @Nullable MediaRouteController mediaRouteController) { |
| + Log.d(TAG, "getOrCreate called"); |
| + synchronized (LOCK) { |
| + if (sInstance == null) { |
| + |
| + // TODO(aberent) Once the Android L SDK is formally released we should disable the |
| + // lock screen for L onwards. On L the lock screen is replaced by lock screen |
| + // notifications. |
|
Bernhard Bauer
2015/03/13 12:18:02
Yes, we should. :)
aberent
2015/03/13 19:04:35
I have updated the comment to explain why we can't
|
| + if (!enabled()) { |
| + return null; |
| + } else if (android.os.Build.VERSION.SDK_INT < 16) { |
| + sInstance = new LockScreenTransportControlV14(context); |
| + } else if (android.os.Build.VERSION.SDK_INT < 18) { |
| + sInstance = new LockScreenTransportControlV16(context); |
| + } else { |
| + sInstance = new LockScreenTransportControlV18(context); |
| + } |
| + } |
| + sInstance.setVideoInfo( |
| + new RemoteVideoInfo(null, 0, RemoteVideoInfo.PlayerState.STOPPED, 0, null)); |
| + |
| + sInstance.mMediaRouteController = mediaRouteController; |
| + return sInstance; |
| + } |
| + } |
| + |
| + protected MediaRouteController getMediaRouteController() { |
| + return mMediaRouteController; |
| + } |
| + |
| + /** |
| + * TODO(aberent) From PlayMovies code. Either remove this and get V14/15 working or combine V14 |
| + * and V16 versions only and change getOrCreate to only support V16 or later. |
| + * |
| + * @return true if lock screen transport controls should be used on this device. |
| + */ |
| + private static boolean enabled() { |
| + // Lock screen controls don't work well prior to JB, see b/9101584 |
| + return android.os.Build.VERSION.SDK_INT >= 16; |
| + } |
| + |
| + /** |
| + * Internal function for callbacks that need to get the current lock screen statically, but |
| + * don't want to create a new one. |
| + * |
| + * @return the current lock screen, if any. |
| + */ |
| + @VisibleForTesting |
| + static LockScreenTransportControl getIfExists() { |
| + return sInstance; |
| + } |
| + |
| + @Override |
| + public void hide() { |
| + onLockScreenPlaybackStateChanged(null, PlayerState.STOPPED); |
| + mMediaRouteController.removeUiListener(this); |
| + } |
| + |
| + @Override |
| + public void show(PlayerState initialState) { |
| + mMediaRouteController.addUiListener(this); |
| + onLockScreenPlaybackStateChanged(null, initialState); |
| + } |
| + |
| + @Override |
| + public void setRouteController(MediaRouteController controller) { |
| + synchronized (LOCK) { |
| + if (sInstance != null) sInstance.mMediaRouteController = controller; |
| + } |
| + } |
| + |
| + @Override |
| + public void onPlaybackStateChanged(PlayerState oldState, PlayerState newState) { |
| + onLockScreenPlaybackStateChanged(oldState, newState); |
| + } |
| + |
| + protected abstract void onLockScreenPlaybackStateChanged(PlayerState oldState, |
| + PlayerState newState); |
| + |
| + protected abstract boolean isPlaying(); |
| +} |