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

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

Issue 2570623003: [Chromecast] Turn CastContentWindow into an abstract interface. (Closed)
Patch Set: Fix browser test Created 3 years, 11 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
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chromecast.shell;
6
7 import android.app.Activity;
8 import android.content.BroadcastReceiver;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.content.IntentFilter;
12 import android.media.AudioManager;
13 import android.net.Uri;
14 import android.os.Build;
15 import android.os.Bundle;
16 import android.support.v4.content.LocalBroadcastManager;
17 import android.view.KeyEvent;
18 import android.view.MotionEvent;
19 import android.view.WindowManager;
20 import android.widget.Toast;
21
22 import org.chromium.base.Log;
23 import org.chromium.content.browser.ContentViewCore;
24 import org.chromium.ui.base.WindowAndroid;
25
26 /**
27 * Activity for managing the Cast shell.
28 */
29 public class CastShellActivity extends Activity {
30 private static final String TAG = "cr_CastShellActivity";
31 private static final boolean DEBUG = false;
32
33 private static final String ACTIVE_SHELL_URL_KEY = "activeUrl";
34
35 private CastWindowManager mCastWindowManager;
36 private AudioManager mAudioManager;
37 private BroadcastReceiver mBroadcastReceiver;
38 private boolean mReceivedUserLeave = false;
39
40 // Native window instance.
41 // TODO(byungchul, gunsch): CastShellActivity, CastWindowAndroid, and native CastWindowAndroid
42 // have a one-to-one relationship. Consider instantiating CastWindow here an d CastWindow having
43 // this native shell instance.
44 private long mNativeCastWindow;
45
46 /**
47 * Returns whether or not CastShellActivity should launch the browser startu p sequence.
48 * Intended to be overridden.
49 */
50 protected boolean shouldLaunchBrowser() {
51 return true;
52 }
53
54 /**
55 * Intended to be called from "onStop" to determine if this is a "legitimate " stop or not.
56 * When starting CastShellActivity from the TV in sleep mode, an extra onPau se/onStop will be
57 * fired.
58 * Details: http://stackoverflow.com/questions/25369909/
59 * We use onUserLeaveHint to determine if the onPause/onStop called because of user intent.
60 */
61 protected boolean isStopping() {
62 return mReceivedUserLeave;
63 }
64
65 @Override
66 protected void onCreate(final Bundle savedInstanceState) {
67 if (DEBUG) Log.d(TAG, "onCreate");
68 super.onCreate(savedInstanceState);
69 exitIfUrlMissing();
70
71 if (shouldLaunchBrowser()) {
72 if (!CastBrowserHelper.initializeBrowser(getApplicationContext())) {
73 Toast.makeText(this,
74 R.string.browser_process_initialization_failed,
75 Toast.LENGTH_SHORT).show();
76 finish();
77 }
78 }
79
80 // Whenever our app is visible, volume controls should modify the music stream.
81 // For more information read:
82 // http://developer.android.com/training/managing-audio/volume-playback. html
83 setVolumeControlStream(AudioManager.STREAM_MUSIC);
84
85 // Set flags to both exit sleep mode when this activity starts and
86 // avoid entering sleep mode while playing media. We cannot distinguish
87 // between video and audio so this applies to both.
88 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
89 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
90
91 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
92
93 setContentView(R.layout.cast_shell_activity);
94 mCastWindowManager = (CastWindowManager) findViewById(R.id.shell_contain er);
95 mCastWindowManager.setDelegate(new CastWindowManager.Delegate() {
96 @Override
97 public void onCreated() {
98 }
99
100 @Override
101 public void onClosed() {
102 mNativeCastWindow = 0;
103 mCastWindowManager.setDelegate(null);
104 finish();
105 }
106 });
107 mCastWindowManager.setWindow(new WindowAndroid(this));
108
109 registerBroadcastReceiver();
110
111 String url = getIntent().getDataString();
112 Log.d(TAG, "onCreate startupUrl: %s", url);
113 mNativeCastWindow = mCastWindowManager.launchCastWindow(url);
114 }
115
116 @Override
117 protected void onDestroy() {
118 if (DEBUG) Log.d(TAG, "onDestroy");
119
120 unregisterBroadcastReceiver();
121
122 if (mNativeCastWindow != 0) {
123 mCastWindowManager.stopCastWindow(mNativeCastWindow, false /* gracef ully */);
124 mNativeCastWindow = 0;
125 }
126
127 super.onDestroy();
128 }
129
130 @Override
131 protected void onNewIntent(Intent intent) {
132 if (DEBUG) Log.d(TAG, "onNewIntent");
133 // Only handle direct intents (e.g. "fling") if this activity is also ma naging
134 // the browser process.
135 if (!shouldLaunchBrowser()) return;
136
137 String url = intent.getDataString();
138 Log.d(TAG, "onNewIntent: %s", url);
139
140 // Reset broadcast intent uri and receiver.
141 setIntent(intent);
142 exitIfUrlMissing();
143 getActiveCastWindow().loadUrl(url);
144 }
145
146 @Override
147 protected void onStart() {
148 if (DEBUG) Log.d(TAG, "onStart");
149 super.onStart();
150 }
151
152 @Override
153 protected void onStop() {
154 if (DEBUG) Log.d(TAG, "onStop, window focus = %d", hasWindowFocus());
155
156 if (isStopping()) {
157 // As soon as the cast app is no longer in the foreground, we ought to immediately tear
158 // everything down.
159 finishGracefully();
160
161 // On pre-M devices, the device should be "unmuted" at the end of a Cast application
162 // session, signaled by the activity exiting. See b/19964892.
163 if (Build.VERSION.SDK_INT < 23) {
164 releaseStreamMuteIfNecessary();
165 }
166 }
167
168 super.onStop();
169 }
170
171 @Override
172 protected void onResume() {
173 if (DEBUG) Log.d(TAG, "onResume");
174 super.onResume();
175
176 // Inform ContentView that this activity is being shown.
177 ContentViewCore view = getActiveContentViewCore();
178 if (view != null) view.onShow();
179
180 // Request audio focus so any other audio playback doesn't continue in t he background.
181 if (mAudioManager.requestAudioFocus(
182 null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN)
183 != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
184 Log.e(TAG, "Failed to obtain audio focus");
185 }
186 }
187
188 @Override
189 protected void onPause() {
190 if (DEBUG) Log.d(TAG, "onPause");
191
192 // Release the audio focus. Note that releasing audio focus does not sto p audio playback,
193 // it just notifies the framework that this activity has stopped playing audio.
194 if (mAudioManager.abandonAudioFocus(null) != AudioManager.AUDIOFOCUS_REQ UEST_GRANTED) {
195 Log.e(TAG, "Failed to abandon audio focus");
196 }
197
198 ContentViewCore view = getActiveContentViewCore();
199 if (view != null) view.onHide();
200
201 super.onPause();
202 }
203
204 @Override
205 protected void onUserLeaveHint() {
206 if (DEBUG) Log.d(TAG, "onUserLeaveHint");
207 mReceivedUserLeave = true;
208 }
209
210 protected void finishGracefully() {
211 if (mNativeCastWindow != 0) {
212 mCastWindowManager.stopCastWindow(mNativeCastWindow, true /* gracefu lly */);
213 mNativeCastWindow = 0;
214 }
215 }
216
217 @SuppressWarnings("deprecation")
218 private void releaseStreamMuteIfNecessary() {
219 AudioManager audioManager = CastAudioManager.getAudioManager(this);
220 boolean isMuted = false;
221 try {
222 isMuted = (Boolean) audioManager.getClass().getMethod("isStreamMute" , int.class)
223 .invoke(audioManager, AudioManager.STREAM_MUSIC);
224 } catch (Exception e) {
225 Log.e(TAG, "Cannot call AudioManager.isStreamMute().", e);
226 }
227
228 if (isMuted) {
229 // Note: this is a no-op on fixed-volume devices.
230 audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false);
231 }
232 }
233
234 private void registerBroadcastReceiver() {
235 if (mBroadcastReceiver == null) {
236 mBroadcastReceiver = new BroadcastReceiver() {
237 @Override
238 public void onReceive(Context context, Intent intent) {
239 Log.d(TAG, "Received intent: action=%s", intent.getAction()) ;
240 if (CastWindowAndroid.ACTION_ENABLE_DEV_TOOLS.equals(intent. getAction())) {
241 mCastWindowManager.nativeEnableDevTools(true);
242 } else if (CastWindowAndroid.ACTION_DISABLE_DEV_TOOLS.equals (
243 intent.getAction())) {
244 mCastWindowManager.nativeEnableDevTools(false);
245 }
246 }
247 };
248 }
249
250 IntentFilter devtoolsBroadcastIntentFilter = new IntentFilter();
251 devtoolsBroadcastIntentFilter.addAction(CastWindowAndroid.ACTION_ENABLE_ DEV_TOOLS);
252 devtoolsBroadcastIntentFilter.addAction(CastWindowAndroid.ACTION_DISABLE _DEV_TOOLS);
253 LocalBroadcastManager.getInstance(this)
254 .registerReceiver(mBroadcastReceiver, devtoolsBroadcastIntentFil ter);
255 }
256
257 private void unregisterBroadcastReceiver() {
258 LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstan ce(this);
259 broadcastManager.unregisterReceiver(mBroadcastReceiver);
260 }
261
262 private void exitIfUrlMissing() {
263 Intent intent = getIntent();
264 if (intent != null && intent.getData() != null && !intent.getData().equa ls(Uri.EMPTY)) {
265 return;
266 }
267 // Log an exception so that the exit cause is obvious when reading the l ogs.
268 Log.e(TAG, "Activity will not start",
269 new IllegalArgumentException("Intent did not contain a valid url "));
270 System.exit(-1);
271 }
272
273 /**
274 * @return The currently visible {@link CastWindowAndroid} or null if one is not showing.
275 */
276 public CastWindowAndroid getActiveCastWindow() {
277 return mCastWindowManager.getActiveCastWindow();
278 }
279
280 /**
281 * @return The {@link ContentViewCore} owned by the currently visible {@link CastWindowAndroid},
282 * or null if one is not showing.
283 */
284 public ContentViewCore getActiveContentViewCore() {
285 CastWindowAndroid shell = getActiveCastWindow();
286 return shell != null ? shell.getContentViewCore() : null;
287 }
288
289 @Override
290 public boolean onKeyUp(int keyCode, KeyEvent event) {
291 if (keyCode != KeyEvent.KEYCODE_BACK) {
292 return super.onKeyUp(keyCode, event);
293 }
294
295 // Just finish this activity to go back to the previous activity or laun cher.
296 finishGracefully();
297 return true;
298 }
299
300 @Override
301 public boolean dispatchKeyEvent(KeyEvent event) {
302 int keyCode = event.getKeyCode();
303 if (keyCode == KeyEvent.KEYCODE_BACK) {
304 return super.dispatchKeyEvent(event);
305 }
306 return false;
307 }
308
309 @Override
310 public boolean dispatchGenericMotionEvent(MotionEvent ev) {
311 return false;
312 }
313
314 @Override
315 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
316 return false;
317 }
318
319 @Override
320 public boolean dispatchTouchEvent(MotionEvent ev) {
321 return false;
322 }
323
324 @Override
325 public boolean dispatchTrackballEvent(MotionEvent ev) {
326 return false;
327 }
328 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698