Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/media/remote/ExpandedControllerActivity.java

Issue 2904683002: [Cast, Android] The 2nd try to replace TransportXX classes in Cast UI (Closed)
Patch Set: Added the fix on top of the revert Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/android/java/res/values/colors.xml ('k') | third_party/android_media/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.media.remote; 5 package org.chromium.chrome.browser.media.remote;
6 6
7 import android.content.Context; 7 import android.content.Context;
8 import android.content.Intent; 8 import android.content.Intent;
9 import android.graphics.Bitmap; 9 import android.graphics.Bitmap;
10 import android.graphics.Color; 10 import android.graphics.Color;
11 import android.os.Bundle; 11 import android.os.Bundle;
12 import android.os.Handler; 12 import android.os.Handler;
13 import android.support.v4.app.FragmentActivity; 13 import android.support.v4.app.FragmentActivity;
14 import android.support.v4.media.session.PlaybackStateCompat;
14 import android.text.TextUtils; 15 import android.text.TextUtils;
15 import android.view.KeyEvent; 16 import android.view.KeyEvent;
16 import android.view.View; 17 import android.view.View;
17 import android.view.ViewGroup; 18 import android.view.ViewGroup;
18 import android.view.Window; 19 import android.view.Window;
19 import android.view.WindowManager; 20 import android.view.WindowManager;
20 import android.widget.ImageView; 21 import android.widget.ImageView;
21 import android.widget.MediaController;
22 import android.widget.MediaController.MediaPlayerControl;
23 import android.widget.TextView; 22 import android.widget.TextView;
24 23
25 import com.google.android.gms.cast.CastMediaControlIntent; 24 import com.google.android.gms.cast.CastMediaControlIntent;
26 25
27 import org.chromium.chrome.R; 26 import org.chromium.chrome.R;
28 import org.chromium.chrome.browser.media.remote.RemoteVideoInfo.PlayerState; 27 import org.chromium.chrome.browser.media.remote.RemoteVideoInfo.PlayerState;
29 import org.chromium.chrome.browser.metrics.MediaNotificationUma; 28 import org.chromium.chrome.browser.metrics.MediaNotificationUma;
29 import org.chromium.third_party.android.media.MediaController;
30 30
31 /** 31 /**
32 * The activity that's opened by clicking the video flinging (casting) notificat ion. 32 * The activity that's opened by clicking the video flinging (casting) notificat ion.
33 * 33 *
34 * TODO(aberent): Refactor to merge some common logic with {@link CastNotificati onControl}. 34 * TODO(aberent): Refactor to merge some common logic with {@link CastNotificati onControl}.
35 */ 35 */
36 public class ExpandedControllerActivity 36 public class ExpandedControllerActivity
37 extends FragmentActivity implements MediaRouteController.UiListener { 37 extends FragmentActivity implements MediaRouteController.UiListener {
38 private static final int PROGRESS_UPDATE_PERIOD_IN_MS = 1000; 38 private static final int PROGRESS_UPDATE_PERIOD_IN_MS = 1000;
39 // The alpha value for the poster/placeholder image, an integer between 0 an d 256 (opaque). 39 // The alpha value for the poster/placeholder image, an integer between 0 an d 256 (opaque).
40 private static final int POSTER_IMAGE_ALPHA = 200; 40 private static final int POSTER_IMAGE_ALPHA = 200;
41 41
42 // Subclass of {@link android.widget.MediaController} that never hides itsel f.
43 class AlwaysShownMediaController extends MediaController {
44 public AlwaysShownMediaController(Context context) {
45 super(context);
46 }
47
48 @Override
49 public void show(int timeout) {
50 // Never auto-hide the controls.
51 super.show(0);
52 }
53
54 @Override
55 public boolean dispatchKeyEvent(KeyEvent event) {
56 int keyCode = event.getKeyCode();
57 // MediaController hides the controls when back or menu are pressed.
58 // Close the activity on back and ignore menu.
59 if (keyCode == KeyEvent.KEYCODE_BACK) {
60 finish();
61 return true;
62 } else if (keyCode == KeyEvent.KEYCODE_MENU) {
63 return true;
64 }
65 return super.dispatchKeyEvent(event);
66 }
67
68 @Override
69 public void hide() {
70 // Don't allow the controls to hide until explicitly asked to do so from the host
71 // activity.
72 }
73
74 /**
75 * Actually hides the controls which prevents some window leaks.
76 */
77 public void cleanup() {
78 super.hide();
79 }
80 };
81
82 private Handler mHandler; 42 private Handler mHandler;
83 private AlwaysShownMediaController mMediaController; 43 // We don't use the standard android.media.MediaController, but a custom one .
44 // See the class itself for details.
45 private MediaController mMediaController;
84 private FullscreenMediaRouteButton mMediaRouteButton; 46 private FullscreenMediaRouteButton mMediaRouteButton;
85 private MediaRouteController mMediaRouteController; 47 private MediaRouteController mMediaRouteController;
86 private RemoteVideoInfo mVideoInfo; 48 private RemoteVideoInfo mVideoInfo;
87 private String mScreenName; 49 private String mScreenName;
88 50
89 /** 51 /**
90 * Handle actions from on-screen media controls. 52 * Handle actions from on-screen media controls.
91 */ 53 */
92 private MediaPlayerControl mMediaPlayerControl = new MediaPlayerControl() { 54 private MediaController.Delegate mControllerDelegate = new MediaController.D elegate() {
93 @Override 55 @Override
94 public boolean canPause() { 56 public void play() {
95 return true; 57 if (mMediaRouteController == null) return;
96 } 58 mMediaRouteController.resume();
97 59 RecordCastAction.recordFullscreenControlsAction(
98 @Override 60 RecordCastAction.FULLSCREEN_CONTROLS_RESUME,
99 public boolean canSeekBackward() { 61 mMediaRouteController.getMediaStateListener() != null);
100 return getDuration() > 0 && getCurrentPosition() > 0;
101 }
102
103 @Override
104 public boolean canSeekForward() {
105 return getDuration() > 0 && getCurrentPosition() < getDuration();
106 }
107
108 @Override
109 public int getAudioSessionId() {
110 // TODO(avayvod): not sure 0 is a valid value to return.
111 return 0;
112 }
113
114 @Override
115 public int getBufferPercentage() {
116 int duration = getDuration();
117 if (duration == 0) return 0;
118 return (getCurrentPosition() * 100) / duration;
119 }
120
121 @Override
122 public int getCurrentPosition() {
123 if (mMediaRouteController == null) return 0;
124 return (int) mMediaRouteController.getPosition();
125 }
126
127 @Override
128 public int getDuration() {
129 if (mMediaRouteController == null) return 0;
130 return (int) mMediaRouteController.getDuration();
131 }
132
133 @Override
134 public boolean isPlaying() {
135 if (mMediaRouteController == null) return false;
136 return mMediaRouteController.isPlaying();
137 } 62 }
138 63
139 @Override 64 @Override
140 public void pause() { 65 public void pause() {
141 if (mMediaRouteController == null) return; 66 if (mMediaRouteController == null) return;
142 mMediaRouteController.pause(); 67 mMediaRouteController.pause();
143 RecordCastAction.recordFullscreenControlsAction( 68 RecordCastAction.recordFullscreenControlsAction(
144 RecordCastAction.FULLSCREEN_CONTROLS_PAUSE, 69 RecordCastAction.FULLSCREEN_CONTROLS_PAUSE,
145 mMediaRouteController.getMediaStateListener() != null); 70 mMediaRouteController.getMediaStateListener() != null);
146 } 71 }
147 72
148 @Override 73 @Override
149 public void start() { 74 public long getDuration() {
150 if (mMediaRouteController == null) return; 75 if (mMediaRouteController == null) return 0;
151 mMediaRouteController.resume(); 76 return mMediaRouteController.getDuration();
152 RecordCastAction.recordFullscreenControlsAction(
153 RecordCastAction.FULLSCREEN_CONTROLS_RESUME,
154 mMediaRouteController.getMediaStateListener() != null);
155 } 77 }
156 78
157 @Override 79 @Override
158 public void seekTo(int pos) { 80 public long getPosition() {
81 if (mMediaRouteController == null) return 0;
82 return mMediaRouteController.getPosition();
83 }
84
85 @Override
86 public void seekTo(long pos) {
159 if (mMediaRouteController == null) return; 87 if (mMediaRouteController == null) return;
160 mMediaRouteController.seekTo(pos); 88 mMediaRouteController.seekTo(pos);
161 RecordCastAction.recordFullscreenControlsAction( 89 RecordCastAction.recordFullscreenControlsAction(
162 RecordCastAction.FULLSCREEN_CONTROLS_SEEK, 90 RecordCastAction.FULLSCREEN_CONTROLS_SEEK,
163 mMediaRouteController.getMediaStateListener() != null); 91 mMediaRouteController.getMediaStateListener() != null);
164 } 92 }
165 };
166 93
167 private Runnable mControlsUpdater = new Runnable() {
168 @Override 94 @Override
169 public void run() { 95 public boolean isPlaying() {
170 mMediaController.show(); 96 if (mMediaRouteController == null) return false;
97 return mMediaRouteController.isPlaying();
98 }
99
100 @Override
101 public long getActionFlags() {
102 long flags =
103 PlaybackStateCompat.ACTION_REWIND | PlaybackStateCompat.ACTI ON_FAST_FORWARD;
104 if (mMediaRouteController != null && mMediaRouteController.isPlaying ()) {
105 flags |= PlaybackStateCompat.ACTION_PAUSE;
106 } else {
107 flags |= PlaybackStateCompat.ACTION_PLAY;
108 }
109 return flags;
171 } 110 }
172 }; 111 };
173 112
113 private Runnable mProgressUpdater = new Runnable() {
114 @Override
115 public void run() {
116 if (mMediaRouteController.isPlaying()) {
117 mMediaController.updateProgress();
118 mHandler.postDelayed(this, PROGRESS_UPDATE_PERIOD_IN_MS);
119 } else {
120 mHandler.removeCallbacks(this);
121 }
122 }
123 };
124
174 @Override 125 @Override
175 protected void onCreate(Bundle savedInstanceState) { 126 protected void onCreate(Bundle savedInstanceState) {
176 super.onCreate(savedInstanceState); 127 super.onCreate(savedInstanceState);
177 128
178 MediaNotificationUma.recordClickSource(getIntent()); 129 MediaNotificationUma.recordClickSource(getIntent());
179 130
180 mMediaRouteController = 131 mMediaRouteController =
181 RemoteMediaPlayerController.instance().getCurrentlyPlayingMediaR outeController(); 132 RemoteMediaPlayerController.instance().getCurrentlyPlayingMediaR outeController();
182 133
183 if (mMediaRouteController == null || mMediaRouteController.routeIsDefaul tRoute()) { 134 if (mMediaRouteController == null || mMediaRouteController.routeIsDefaul tRoute()) {
(...skipping 10 matching lines...) Expand all
194 // requestWindowFeature must be called before adding content. 145 // requestWindowFeature must be called before adding content.
195 setContentView(R.layout.expanded_cast_controller); 146 setContentView(R.layout.expanded_cast_controller);
196 mHandler = new Handler(); 147 mHandler = new Handler();
197 148
198 ViewGroup rootView = (ViewGroup) findViewById(android.R.id.content); 149 ViewGroup rootView = (ViewGroup) findViewById(android.R.id.content);
199 rootView.setBackgroundColor(Color.BLACK); 150 rootView.setBackgroundColor(Color.BLACK);
200 151
201 mMediaRouteController.addUiListener(this); 152 mMediaRouteController.addUiListener(this);
202 153
203 // Create and initialize the media control UI. 154 // Create and initialize the media control UI.
204 mMediaController = new AlwaysShownMediaController(this); 155 mMediaController = (MediaController) findViewById(R.id.cast_media_contro ller);
205 mMediaController.setEnabled(true); 156 mMediaController.setDelegate(mControllerDelegate);
206 mMediaController.setMediaPlayer(mMediaPlayerControl);
207 mMediaController.setAnchorView(rootView);
208 157
209 View button = getLayoutInflater().inflate(R.layout.cast_controller_media _route_button, 158 View button = getLayoutInflater().inflate(R.layout.cast_controller_media _route_button,
210 rootView, false); 159 rootView, false);
211 160
212 if (button instanceof FullscreenMediaRouteButton) { 161 if (button instanceof FullscreenMediaRouteButton) {
213 mMediaRouteButton = (FullscreenMediaRouteButton) button; 162 mMediaRouteButton = (FullscreenMediaRouteButton) button;
214 rootView.addView(mMediaRouteButton); 163 rootView.addView(mMediaRouteButton);
215 mMediaRouteButton.bringToFront(); 164 mMediaRouteButton.bringToFront();
216 mMediaRouteButton.initialize(mMediaRouteController); 165 mMediaRouteButton.initialize(mMediaRouteController);
217 } else { 166 } else {
218 mMediaRouteButton = null; 167 mMediaRouteButton = null;
219 } 168 }
220 169
221 // Initialize the video info. 170 // Initialize the video info.
222 mVideoInfo = new RemoteVideoInfo(null, 0, RemoteVideoInfo.PlayerState.ST OPPED, 0, null); 171 setVideoInfo(new RemoteVideoInfo(null, 0, RemoteVideoInfo.PlayerState.ST OPPED, 0, null));
172
173 mMediaController.refresh();
174
175 scheduleProgressUpdate();
223 } 176 }
224 177
225 @Override 178 @Override
226 protected void onResume() { 179 protected void onResume() {
227 super.onResume(); 180 super.onResume();
228
229 if (mVideoInfo.state == PlayerState.FINISHED) finish(); 181 if (mVideoInfo.state == PlayerState.FINISHED) finish();
230 if (mMediaRouteController == null) return; 182 if (mMediaRouteController == null) return;
231 183
232 // Lifetime of the media element is bound to that of the {@link MediaSta teListener} 184 // Lifetime of the media element is bound to that of the {@link MediaSta teListener}
233 // of the {@link MediaRouteController}. 185 // of the {@link MediaRouteController}.
234 RecordCastAction.recordFullscreenControlsShown( 186 RecordCastAction.recordFullscreenControlsShown(
235 mMediaRouteController.getMediaStateListener() != null); 187 mMediaRouteController.getMediaStateListener() != null);
236 188
237 mMediaRouteController.prepareMediaRoute(); 189 mMediaRouteController.prepareMediaRoute();
238 190
239 ImageView iv = (ImageView) findViewById(R.id.cast_background_image); 191 ImageView iv = (ImageView) findViewById(R.id.cast_background_image);
240 if (iv == null) return; 192 if (iv == null) return;
241 Bitmap posterBitmap = mMediaRouteController.getPoster(); 193 Bitmap posterBitmap = mMediaRouteController.getPoster();
242 if (posterBitmap != null) iv.setImageBitmap(posterBitmap); 194 if (posterBitmap != null) iv.setImageBitmap(posterBitmap);
243 iv.setImageAlpha(POSTER_IMAGE_ALPHA); 195 iv.setImageAlpha(POSTER_IMAGE_ALPHA);
244
245 // Can't show the media controller until attached to window.
246 scheduleControlsUpdate();
247 } 196 }
248 197
249 @Override 198 @Override
250 protected void onDestroy() { 199 protected void onDestroy() {
251 cleanup(); 200 cleanup();
252 super.onDestroy(); 201 super.onDestroy();
253 } 202 }
254 203
255 @Override 204 @Override
256 public boolean dispatchKeyEvent(KeyEvent event) { 205 public boolean dispatchKeyEvent(KeyEvent event) {
257 int keyCode = event.getKeyCode(); 206 int keyCode = event.getKeyCode();
258 if ((keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYC ODE_VOLUME_UP) 207 if ((keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYC ODE_VOLUME_UP)
259 || mVideoInfo.state == PlayerState.FINISHED) { 208 || mVideoInfo.state == PlayerState.FINISHED) {
260 return super.dispatchKeyEvent(event); 209 return super.dispatchKeyEvent(event);
261 } 210 }
262 211
263 return handleVolumeKeyEvent(mMediaRouteController, event); 212 return handleVolumeKeyEvent(mMediaRouteController, event);
264 } 213 }
265 214
266 private void cleanup() { 215 private void cleanup() {
267 if (mHandler != null) mHandler.removeCallbacks(mControlsUpdater); 216 if (mHandler != null) mHandler.removeCallbacks(mProgressUpdater);
268 if (mMediaRouteController != null) mMediaRouteController.removeUiListene r(this); 217 if (mMediaRouteController != null) mMediaRouteController.removeUiListene r(this);
269 mMediaRouteController = null; 218 mMediaRouteController = null;
270 mControlsUpdater = null; 219 mProgressUpdater = null;
271 mMediaController.cleanup();
272 mMediaController = null;
273 } 220 }
274 221
275 /** 222 /**
276 * Sets the remote's video information to display. 223 * Sets the remote's video information to display.
277 */ 224 */
278 private final void setVideoInfo(RemoteVideoInfo videoInfo) { 225 private final void setVideoInfo(RemoteVideoInfo videoInfo) {
279 if ((mVideoInfo == null) ? (videoInfo == null) : mVideoInfo.equals(video Info)) return; 226 if ((mVideoInfo == null) ? (videoInfo == null) : mVideoInfo.equals(video Info)) return;
280 227
281 mVideoInfo = videoInfo; 228 mVideoInfo = videoInfo;
282 updateUi(); 229 onVideoInfoChanged();
283 } 230 }
284 231
285 private void scheduleControlsUpdate() { 232 private void scheduleProgressUpdate() {
286 mHandler.removeCallbacks(mControlsUpdater); 233 mHandler.removeCallbacks(mProgressUpdater);
287 mHandler.post(mControlsUpdater); 234 if (mMediaRouteController.isPlaying()) {
235 mHandler.post(mProgressUpdater);
236 }
288 } 237 }
289 238
290 /** 239 /**
291 * Sets the name to display for the device. 240 * Sets the name to display for the device.
292 */ 241 */
293 private void setScreenName(String screenName) { 242 private void setScreenName(String screenName) {
294 if (TextUtils.equals(mScreenName, screenName)) return; 243 if (TextUtils.equals(mScreenName, screenName)) return;
295 244
296 mScreenName = screenName; 245 mScreenName = screenName;
246 onScreenNameChanged();
247 }
248
249 private void onVideoInfoChanged() {
297 updateUi(); 250 updateUi();
298 } 251 }
299 252
253 private void onScreenNameChanged() {
254 updateUi();
255 }
256
300 private void updateUi() { 257 private void updateUi() {
301 if (mMediaController == null || mMediaRouteController == null) return; 258 if (mMediaController == null || mMediaRouteController == null) return;
302 259
303 String deviceName = mMediaRouteController.getRouteName(); 260 String deviceName = mMediaRouteController.getRouteName();
304 String castText = ""; 261 String castText = "";
305 if (deviceName != null) { 262 if (deviceName != null) {
306 castText = getResources().getString(R.string.cast_casting_video, dev iceName); 263 castText = getResources().getString(R.string.cast_casting_video, dev iceName);
307 } 264 }
308 TextView castTextView = (TextView) findViewById(R.id.cast_screen_title); 265 TextView castTextView = (TextView) findViewById(R.id.cast_screen_title);
309 castTextView.setText(castText); 266 castTextView.setText(castText);
310 267
311 scheduleControlsUpdate(); 268 mMediaController.refresh();
312 } 269 }
313 270
314 @Override 271 @Override
315 public void onRouteSelected(String name, MediaRouteController mediaRouteCont roller) { 272 public void onRouteSelected(String name, MediaRouteController mediaRouteCont roller) {
316 setScreenName(name); 273 setScreenName(name);
317 } 274 }
318 275
319 @Override 276 @Override
320 public void onRouteUnselected(MediaRouteController mediaRouteController) { 277 public void onRouteUnselected(MediaRouteController mediaRouteController) {
321 finish(); 278 finish();
322 } 279 }
323 280
324 @Override 281 @Override
325 public void onPrepared(MediaRouteController mediaRouteController) { 282 public void onPrepared(MediaRouteController mediaRouteController) {
326 // No implementation. 283 // No implementation.
327 } 284 }
328 285
329 @Override 286 @Override
330 public void onError(int error, String message) { 287 public void onError(int error, String message) {
331 if (error == CastMediaControlIntent.ERROR_CODE_SESSION_START_FAILED) fin ish(); 288 if (error == CastMediaControlIntent.ERROR_CODE_SESSION_START_FAILED) fin ish();
332 } 289 }
333 290
334 @Override 291 @Override
335 public void onPlaybackStateChanged(PlayerState newState) { 292 public void onPlaybackStateChanged(PlayerState newState) {
336 RemoteVideoInfo videoInfo = new RemoteVideoInfo(mVideoInfo); 293 RemoteVideoInfo videoInfo = new RemoteVideoInfo(mVideoInfo);
337 videoInfo.state = newState; 294 videoInfo.state = newState;
338 setVideoInfo(videoInfo); 295 setVideoInfo(videoInfo);
339 296
340 scheduleControlsUpdate(); 297 scheduleProgressUpdate();
341 298
342 if (newState == PlayerState.FINISHED || newState == PlayerState.INVALIDA TED) { 299 if (newState == PlayerState.FINISHED || newState == PlayerState.INVALIDA TED) {
343 // If we are switching to a finished state, stop the notifications. 300 // If we are switching to a finished state, stop the notifications.
344 finish(); 301 finish();
345 } 302 }
346 } 303 }
347 304
348 @Override 305 @Override
349 public void onDurationUpdated(long durationMillis) { 306 public void onDurationUpdated(long durationMillis) {
350 RemoteVideoInfo videoInfo = new RemoteVideoInfo(mVideoInfo); 307 RemoteVideoInfo videoInfo = new RemoteVideoInfo(mVideoInfo);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 * @param context the Context to start this activity within. 355 * @param context the Context to start this activity within.
399 */ 356 */
400 public static void startActivity(Context context) { 357 public static void startActivity(Context context) {
401 if (context == null) return; 358 if (context == null) return;
402 359
403 Intent intent = new Intent(context, ExpandedControllerActivity.class); 360 Intent intent = new Intent(context, ExpandedControllerActivity.class);
404 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 361 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
405 context.startActivity(intent); 362 context.startActivity(intent);
406 } 363 }
407 } 364 }
OLDNEW
« no previous file with comments | « chrome/android/java/res/values/colors.xml ('k') | third_party/android_media/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698