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

Side by Side Diff: chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java

Issue 2874943002: [Chromecast] Add service for "displaying" cast web contents. (Closed)
Patch Set: [Chromecast] Add service for "displaying" cast web contents. 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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.chromecast.shell; 5 package org.chromium.chromecast.shell;
6 6
7 import android.app.Activity; 7 import android.app.Activity;
8 import android.content.BroadcastReceiver; 8 import android.content.BroadcastReceiver;
9 import android.content.Context; 9 import android.content.Context;
10 import android.content.Intent; 10 import android.content.Intent;
11 import android.content.IntentFilter; 11 import android.content.IntentFilter;
12 import android.graphics.Color; 12 import android.graphics.Color;
13 import android.media.AudioManager; 13 import android.media.AudioManager;
14 import android.net.Uri;
15 import android.os.Bundle; 14 import android.os.Bundle;
16 import android.os.Handler; 15 import android.os.Handler;
17 import android.os.PatternMatcher; 16 import android.os.PatternMatcher;
18 import android.support.v4.content.LocalBroadcastManager; 17 import android.support.v4.content.LocalBroadcastManager;
19 import android.view.KeyEvent; 18 import android.view.KeyEvent;
20 import android.view.MotionEvent; 19 import android.view.MotionEvent;
21 import android.view.WindowManager; 20 import android.view.WindowManager;
22 import android.widget.FrameLayout; 21 import android.widget.FrameLayout;
23 import android.widget.Toast; 22 import android.widget.Toast;
24 23
25 import org.chromium.base.Log; 24 import org.chromium.base.Log;
26 import org.chromium.base.annotations.JNINamespace; 25 import org.chromium.base.annotations.JNINamespace;
27 import org.chromium.content.browser.ActivityContentVideoViewEmbedder; 26 import org.chromium.content.browser.ActivityContentVideoViewEmbedder;
28 import org.chromium.content.browser.ContentVideoViewEmbedder; 27 import org.chromium.content.browser.ContentVideoViewEmbedder;
29 import org.chromium.content.browser.ContentView; 28 import org.chromium.content.browser.ContentView;
30 import org.chromium.content.browser.ContentViewCore; 29 import org.chromium.content.browser.ContentViewCore;
31 import org.chromium.content.browser.ContentViewRenderView; 30 import org.chromium.content.browser.ContentViewRenderView;
32 import org.chromium.content_public.browser.WebContents; 31 import org.chromium.content_public.browser.WebContents;
33 import org.chromium.ui.base.ViewAndroidDelegate; 32 import org.chromium.ui.base.ViewAndroidDelegate;
34 import org.chromium.ui.base.WindowAndroid; 33 import org.chromium.ui.base.WindowAndroid;
35 34
36 /** 35 /**
37 * Activity for displaying a WebContents in CastShell. 36 * Activity for displaying a WebContents in CastShell.
38 * 37 * <p>
39 * Typically, this class is controlled by CastContentWindowAndroid, which will 38 * Typically, this class is controlled by CastContentWindowAndroid, which will
40 * start a new instance of this activity. If the CastContentWindowAndroid is 39 * start a new instance of this activity. If the CastContentWindowAndroid is
41 * destroyed, CastWebContentsActivity should finish(). Similarily, if this 40 * destroyed, CastWebContentsActivity should finish(). Similarily, if this
42 * activity is destroyed, CastContentWindowAndroid should be notified by intent. 41 * activity is destroyed, CastContentWindowAndroid should be notified by intent.
43 */ 42 */
44 @JNINamespace("chromecast::shell") 43 @JNINamespace("chromecast::shell")
45 public class CastWebContentsActivity extends Activity { 44 public class CastWebContentsActivity extends Activity {
46 private static final String TAG = "cr_CastWebActivity"; 45 private static final String TAG = "cr_CastWebActivity";
47 private static final boolean DEBUG = true; 46 private static final boolean DEBUG = true;
48 47
49 private Handler mHandler; 48 private Handler mHandler;
50 private String mInstanceId; 49 private String mInstanceId;
51 private BroadcastReceiver mWindowDestroyedBroadcastReceiver; 50 private BroadcastReceiver mWindowDestroyedBroadcastReceiver;
52 private IntentFilter mWindowDestroyedIntentFilter; 51 private IntentFilter mWindowDestroyedIntentFilter;
53 private FrameLayout mCastWebContentsLayout; 52 private FrameLayout mCastWebContentsLayout;
54 private AudioManager mAudioManager; 53 private AudioManager mAudioManager;
55 private ContentViewRenderView mContentViewRenderView; 54 private ContentViewRenderView mContentViewRenderView;
56 private WindowAndroid mWindow; 55 private WindowAndroid mWindow;
57 private ContentViewCore mContentViewCore; 56 private ContentViewCore mContentViewCore;
58 private ContentView mContentView; 57 private ContentView mContentView;
59 private boolean mReceivedUserLeave = false; 58 private boolean mReceivedUserLeave = false;
60 59
61 private static final int TEARDOWN_GRACE_PERIOD_TIMEOUT_MILLIS = 300; 60 private static final int TEARDOWN_GRACE_PERIOD_TIMEOUT_MILLIS = 300;
62 public static final String ACTION_DATA_SCHEME = "cast";
63 public static final String ACTION_DATA_AUTHORITY = "webcontents";
64 61
65 public static final String ACTION_EXTRA_WEB_CONTENTS =
66 "com.google.android.apps.castshell.intent.extra.WEB_CONTENTS";
67 public static final String ACTION_EXTRA_KEY_CODE =
68 "com.google.android.apps.castshell.intent.extra.KEY_CODE";
69 public static final String ACTION_KEY_EVENT =
70 "com.google.android.apps.castshell.intent.action.KEY_EVENT";
71 public static final String ACTION_STOP_ACTIVITY = 62 public static final String ACTION_STOP_ACTIVITY =
72 "com.google.android.apps.castshell.intent.action.STOP_ACTIVITY"; 63 "com.google.android.apps.castshell.intent.action.STOP_ACTIVITY";
73 public static final String ACTION_ACTIVITY_STOPPED =
74 "com.google.android.apps.castshell.intent.action.ACTIVITY_STOPPED";
75 64
76 /* 65 /*
77 * Intended to be called from "onStop" to determine if this is a "legitimate " stop or not. 66 * Intended to be called from "onStop" to determine if this is a "legitimate " stop or not.
78 * When starting CastShellActivity from the TV in sleep mode, an extra onPau se/onStop will be 67 * When starting CastShellActivity from the TV in sleep mode, an extra onPau se/onStop will be
79 * fired. 68 * fired.
80 * Details: http://stackoverflow.com/questions/25369909/ 69 * Details: http://stackoverflow.com/questions/25369909/
81 * We use onUserLeaveHint to determine if the onPause/onStop called because of user intent. 70 * We use onUserLeaveHint to determine if the onPause/onStop called because of user intent.
82 */ 71 */
83 private boolean isStopping() { 72 private boolean isStopping() {
84 return mReceivedUserLeave; 73 return mReceivedUserLeave;
85 } 74 }
86 75
87 @Override 76 @Override
88 protected void onCreate(final Bundle savedInstanceState) { 77 protected void onCreate(final Bundle savedInstanceState) {
89 if (DEBUG) Log.d(TAG, "onCreate"); 78 if (DEBUG) Log.d(TAG, "onCreate");
90 super.onCreate(savedInstanceState); 79 super.onCreate(savedInstanceState);
91 80
92 mHandler = new Handler(); 81 mHandler = new Handler();
93 82
94 // TODO(derekjchow): Remove this call.
95 if (!CastBrowserHelper.initializeBrowser(getApplicationContext())) { 83 if (!CastBrowserHelper.initializeBrowser(getApplicationContext())) {
96 Toast.makeText(this, R.string.browser_process_initialization_failed, Toast.LENGTH_SHORT) 84 Toast.makeText(this, R.string.browser_process_initialization_failed, Toast.LENGTH_SHORT)
97 .show(); 85 .show();
98 finish(); 86 finish();
99 } 87 }
100 88
101 // Whenever our app is visible, volume controls should modify the music stream. 89 // Whenever our app is visible, volume controls should modify the music stream.
102 // For more information read: 90 // For more information read:
103 // http://developer.android.com/training/managing-audio/volume-playback. html 91 // http://developer.android.com/training/managing-audio/volume-playback. html
104 setVolumeControlStream(AudioManager.STREAM_MUSIC); 92 setVolumeControlStream(AudioManager.STREAM_MUSIC);
(...skipping 26 matching lines...) Expand all
131 FrameLayout.LayoutParams.MATCH_PARENT)); 119 FrameLayout.LayoutParams.MATCH_PARENT));
132 120
133 Intent intent = getIntent(); 121 Intent intent = getIntent();
134 handleIntent(intent); 122 handleIntent(intent);
135 } 123 }
136 124
137 protected void handleIntent(Intent intent) { 125 protected void handleIntent(Intent intent) {
138 intent.setExtrasClassLoader(WebContents.class.getClassLoader()); 126 intent.setExtrasClassLoader(WebContents.class.getClassLoader());
139 mInstanceId = intent.getData().getPath(); 127 mInstanceId = intent.getData().getPath();
140 128
141 final String instanceId = mInstanceId;
142 if (mWindowDestroyedBroadcastReceiver != null) { 129 if (mWindowDestroyedBroadcastReceiver != null) {
143 LocalBroadcastManager.getInstance(this).unregisterReceiver( 130 LocalBroadcastManager.getInstance(this).unregisterReceiver(
144 mWindowDestroyedBroadcastReceiver); 131 mWindowDestroyedBroadcastReceiver);
145 } 132 }
146 mWindowDestroyedBroadcastReceiver = new BroadcastReceiver() { 133 mWindowDestroyedBroadcastReceiver = new BroadcastReceiver() {
147 @Override 134 @Override
148 public void onReceive(Context context, Intent intent) { 135 public void onReceive(Context context, Intent intent) {
149 detachWebContentsIfAny(); 136 detachWebContentsIfAny();
150 maybeFinishLater(); 137 maybeFinishLater();
151 } 138 }
152 }; 139 };
153 mWindowDestroyedIntentFilter = new IntentFilter(); 140 mWindowDestroyedIntentFilter = new IntentFilter();
154 mWindowDestroyedIntentFilter.addDataScheme(intent.getData().getScheme()) ; 141 mWindowDestroyedIntentFilter.addDataScheme(intent.getData().getScheme()) ;
155 mWindowDestroyedIntentFilter.addDataAuthority(intent.getData().getAuthor ity(), null); 142 mWindowDestroyedIntentFilter.addDataAuthority(intent.getData().getAuthor ity(), null);
156 mWindowDestroyedIntentFilter.addDataPath(mInstanceId, PatternMatcher.PAT TERN_LITERAL); 143 mWindowDestroyedIntentFilter.addDataPath(mInstanceId, PatternMatcher.PAT TERN_LITERAL);
157 mWindowDestroyedIntentFilter.addAction(ACTION_STOP_ACTIVITY); 144 mWindowDestroyedIntentFilter.addAction(ACTION_STOP_ACTIVITY);
158 LocalBroadcastManager.getInstance(this).registerReceiver( 145 LocalBroadcastManager.getInstance(this).registerReceiver(
159 mWindowDestroyedBroadcastReceiver, mWindowDestroyedIntentFilter) ; 146 mWindowDestroyedBroadcastReceiver, mWindowDestroyedIntentFilter) ;
160 147
161 WebContents webContents = 148 WebContents webContents = (WebContents) intent.getParcelableExtra(
162 (WebContents) intent.getParcelableExtra(ACTION_EXTRA_WEB_CONTENT S); 149 CastWebContentsComponent.ACTION_EXTRA_WEB_CONTENTS);
163 if (webContents == null) { 150 if (webContents == null) {
164 Log.e(TAG, "Received null WebContents in intent."); 151 Log.e(TAG, "Received null WebContents in intent.");
165 maybeFinishLater(); 152 maybeFinishLater();
166 return; 153 return;
167 } 154 }
168 155
169 detachWebContentsIfAny(); 156 detachWebContentsIfAny();
170 showWebContents(webContents); 157 showWebContents(webContents);
171 } 158 }
172 159
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 releaseStreamMuteIfNecessary(); 195 releaseStreamMuteIfNecessary();
209 } 196 }
210 super.onStop(); 197 super.onStop();
211 } 198 }
212 199
213 @Override 200 @Override
214 protected void onResume() { 201 protected void onResume() {
215 if (DEBUG) Log.d(TAG, "onResume"); 202 if (DEBUG) Log.d(TAG, "onResume");
216 super.onResume(); 203 super.onResume();
217 204
218 if (mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, 205 if (mAudioManager.requestAudioFocus(
219 AudioManager.AUDIOFOCUS_GAIN) != AudioManager.AUDIOFOCUS_REQ UEST_GRANTED) { 206 null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAI N)
207 != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
220 Log.e(TAG, "Failed to obtain audio focus"); 208 Log.e(TAG, "Failed to obtain audio focus");
221 } 209 }
222 } 210 }
223 211
224 @Override 212 @Override
225 protected void onPause() { 213 protected void onPause() {
226 if (DEBUG) Log.d(TAG, "onPause"); 214 if (DEBUG) Log.d(TAG, "onPause");
227 super.onPause(); 215 super.onPause();
228 216
229 // Release the audio focus. Note that releasing audio focus does not sto p audio playback, 217 // Release the audio focus. Note that releasing audio focus does not sto p audio playback,
(...skipping 17 matching lines...) Expand all
247 235
248 // Similar condition for all single-click events. 236 // Similar condition for all single-click events.
249 if (action == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { 237 if (action == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
250 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER 238 if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
251 || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE 239 || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
252 || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY 240 || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY
253 || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE 241 || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE
254 || keyCode == KeyEvent.KEYCODE_MEDIA_STOP 242 || keyCode == KeyEvent.KEYCODE_MEDIA_STOP
255 || keyCode == KeyEvent.KEYCODE_MEDIA_NEXT 243 || keyCode == KeyEvent.KEYCODE_MEDIA_NEXT
256 || keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS) { 244 || keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS) {
257 Intent intent = new Intent(ACTION_KEY_EVENT, getInstanceUri()); 245 CastWebContentsComponent.onKeyDown(this, mInstanceId, keyCode);
258 intent.putExtra(ACTION_EXTRA_KEY_CODE, keyCode);
259 LocalBroadcastManager.getInstance(this).sendBroadcastSync(intent );
260 246
261 // Stop key should end the entire session. 247 // Stop key should end the entire session.
262 if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) { 248 if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
263 mReceivedUserLeave = true; 249 mReceivedUserLeave = true;
264 finish(); 250 finish();
265 } 251 }
266 252
267 return true; 253 return true;
268 } 254 }
269 } 255 }
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 // Set ContentVideoViewEmbedder to allow video playback. 321 // Set ContentVideoViewEmbedder to allow video playback.
336 nativeSetContentVideoViewEmbedder(webContents, new ActivityContentVideoV iewEmbedder(this)); 322 nativeSetContentVideoViewEmbedder(webContents, new ActivityContentVideoV iewEmbedder(this));
337 323
338 // TODO(derekjchow): productVersion 324 // TODO(derekjchow): productVersion
339 mContentViewCore = new ContentViewCore(this, ""); 325 mContentViewCore = new ContentViewCore(this, "");
340 mContentView = ContentView.createContentView(this, mContentViewCore); 326 mContentView = ContentView.createContentView(this, mContentViewCore);
341 mContentViewCore.initialize(ViewAndroidDelegate.createBasicDelegate(mCon tentView), 327 mContentViewCore.initialize(ViewAndroidDelegate.createBasicDelegate(mCon tentView),
342 mContentView, webContents, mWindow); 328 mContentView, webContents, mWindow);
343 // Enable display of current webContents. 329 // Enable display of current webContents.
344 if (getParent() != null) mContentViewCore.onShow(); 330 if (getParent() != null) mContentViewCore.onShow();
345 mCastWebContentsLayout.addView( 331 mCastWebContentsLayout.addView(mContentView,
346 mContentView, new FrameLayout.LayoutParams(FrameLayout.LayoutPar ams.MATCH_PARENT, 332 new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARE NT,
347 FrameLayout.LayoutPar ams.MATCH_PARENT)); 333 FrameLayout.LayoutParams.MATCH_PARENT));
348 mContentView.requestFocus(); 334 mContentView.requestFocus();
349 mContentViewRenderView.setCurrentContentViewCore(mContentViewCore); 335 mContentViewRenderView.setCurrentContentViewCore(mContentViewCore);
350 } 336 }
351 337
352 // Remove the currently displayed webContents. no-op if nothing is being dis played. 338 // Remove the currently displayed webContents. no-op if nothing is being dis played.
353 private void detachWebContentsIfAny() { 339 private void detachWebContentsIfAny() {
354 if (DEBUG) Log.d(TAG, "detachWebContentsIfAny"); 340 if (DEBUG) Log.d(TAG, "detachWebContentsIfAny");
355 if (mContentView != null) { 341 if (mContentView != null) {
356 mCastWebContentsLayout.removeView(mContentView); 342 mCastWebContentsLayout.removeView(mContentView);
357 mContentView = null; 343 mContentView = null;
358 mContentViewCore = null; 344 mContentViewCore = null;
359 345
360 // Inform CastContentWindowAndroid we're detaching. 346 CastWebContentsComponent.onComponentClosed(this, mInstanceId);
361 Intent intent = new Intent(ACTION_ACTIVITY_STOPPED, getInstanceUri() );
362 LocalBroadcastManager.getInstance(this).sendBroadcastSync(intent);
363 } 347 }
364 } 348 }
365 349
366 private Uri getInstanceUri() {
367 Uri instanceUri = new Uri.Builder()
368 .scheme(CastWebContentsActivity.ACTION_DATA_SCHEME)
369 .authority(CastWebContentsActivity.ACTION_DATA_AUTHORITY)
370 .path(mInstanceId)
371 .build();
372 return instanceUri;
373 }
374
375 private native void nativeSetContentVideoViewEmbedder( 350 private native void nativeSetContentVideoViewEmbedder(
376 WebContents webContents, ContentVideoViewEmbedder embedder); 351 WebContents webContents, ContentVideoViewEmbedder embedder);
377 } 352 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698