OLD | NEW |
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.content.BroadcastReceiver; | |
8 import android.content.Context; | 7 import android.content.Context; |
9 import android.content.Intent; | |
10 import android.content.IntentFilter; | |
11 import android.net.Uri; | |
12 import android.os.PatternMatcher; | |
13 import android.support.v4.content.LocalBroadcastManager; | |
14 | 8 |
15 import org.chromium.base.ContextUtils; | 9 import org.chromium.base.ContextUtils; |
16 import org.chromium.base.Log; | 10 import org.chromium.base.Log; |
17 import org.chromium.base.annotations.CalledByNative; | 11 import org.chromium.base.annotations.CalledByNative; |
18 import org.chromium.base.annotations.JNINamespace; | 12 import org.chromium.base.annotations.JNINamespace; |
19 import org.chromium.content_public.browser.WebContents; | 13 import org.chromium.content_public.browser.WebContents; |
20 | 14 |
21 /** | 15 /** |
22 * The Java component of CastContentWindowAndroid. This class is responsible for | 16 * The Java component of CastContentWindowAndroid. This class is responsible for |
23 * starting, stopping and monitoring CastWebContentsActivity. | 17 * starting, stopping and monitoring CastWebContentsActivity. |
24 * | 18 * <p> |
25 * See chromecast/browser/cast_content_window_android.* for the native half. | 19 * See chromecast/browser/cast_content_window_android.* for the native half. |
26 */ | 20 */ |
27 @JNINamespace("chromecast::shell") | 21 @JNINamespace("chromecast::shell") |
28 public class CastContentWindowAndroid { | 22 public class CastContentWindowAndroid implements CastWebContentsComponent.OnComp
onentClosedHandler, |
| 23 CastWebContentsComponent.OnKeyD
ownHandler { |
29 private static final String TAG = "cr_CastContentWindowAndroid"; | 24 private static final String TAG = "cr_CastContentWindowAndroid"; |
30 private static final boolean DEBUG = true; | 25 private static final boolean DEBUG = true; |
31 | 26 |
32 // Note: CastContentWindowAndroid may outlive the native object. The native | 27 // Note: CastContentWindowAndroid may outlive the native object. The native |
33 // ref should be checked that it is not zero before it is used. | 28 // ref should be checked that it is not zero before it is used. |
34 private long mNativeCastContentWindowAndroid; | 29 private long mNativeCastContentWindowAndroid; |
35 private Context mContext; | 30 private Context mContext; |
36 private IntentFilter mActivityClosedIntentFilter; | |
37 private BroadcastReceiver mActivityClosedBroadcastReceiver; | |
38 private String mInstanceId; | 31 private String mInstanceId; |
| 32 private CastWebContentsComponent mComponent; |
39 | 33 |
40 private static int sInstanceId = 1; | 34 private static int sInstanceId = 1; |
41 | 35 |
42 @SuppressWarnings("unused") | 36 @SuppressWarnings("unused") |
43 @CalledByNative | 37 @CalledByNative |
44 private static CastContentWindowAndroid create(long nativeCastContentWindowA
ndroid) { | 38 private static CastContentWindowAndroid create(long nativeCastContentWindowA
ndroid) { |
45 return new CastContentWindowAndroid( | 39 return new CastContentWindowAndroid( |
46 nativeCastContentWindowAndroid, ContextUtils.getApplicationConte
xt()); | 40 nativeCastContentWindowAndroid, ContextUtils.getApplicationConte
xt()); |
47 } | 41 } |
48 | 42 |
49 private CastContentWindowAndroid(long nativeCastContentWindowAndroid, Contex
t context) { | 43 private CastContentWindowAndroid(long nativeCastContentWindowAndroid, final
Context context) { |
50 mNativeCastContentWindowAndroid = nativeCastContentWindowAndroid; | 44 mNativeCastContentWindowAndroid = nativeCastContentWindowAndroid; |
51 mContext = context; | 45 mContext = context; |
52 mInstanceId = Integer.toString(sInstanceId++); | 46 mInstanceId = Integer.toString(sInstanceId++); |
53 } | |
54 | 47 |
55 private Uri getInstanceUri() { | 48 mComponent = new CastWebContentsComponent(mInstanceId, this, this); |
56 Uri instanceUri = new Uri.Builder() | |
57 .scheme(CastWebContentsActivity.ACTION_DATA_SCHEME) | |
58 .authority(CastWebContentsActivity.ACTION_DATA_AUTHORITY) | |
59 .path(mInstanceId) | |
60 .build(); | |
61 return instanceUri; | |
62 } | 49 } |
63 | 50 |
64 @SuppressWarnings("unused") | 51 @SuppressWarnings("unused") |
65 @CalledByNative | 52 @CalledByNative |
66 private void showWebContents(WebContents webContents) { | 53 private void showWebContents(WebContents webContents) { |
67 if (DEBUG) Log.d(TAG, "showWebContents"); | 54 if (DEBUG) Log.d(TAG, "showWebContents"); |
68 | 55 |
69 Intent intent = new Intent( | 56 mComponent.start(mContext, webContents); |
70 Intent.ACTION_VIEW, getInstanceUri(), mContext, CastWebContentsA
ctivity.class); | |
71 | |
72 mActivityClosedBroadcastReceiver = new BroadcastReceiver() { | |
73 @Override | |
74 public void onReceive(Context context, Intent intent) { | |
75 if (intent.getAction() == CastWebContentsActivity.ACTION_ACTIVIT
Y_STOPPED) { | |
76 onActivityStopped(); | |
77 } else if (intent.getAction() == CastWebContentsActivity.ACTION_
KEY_EVENT) { | |
78 int keyCode = | |
79 intent.getIntExtra(CastWebContentsActivity.ACTION_EX
TRA_KEY_CODE, 0); | |
80 onKeyDown(keyCode); | |
81 } | |
82 } | |
83 }; | |
84 mActivityClosedIntentFilter = new IntentFilter(); | |
85 mActivityClosedIntentFilter.addDataScheme(intent.getData().getScheme()); | |
86 mActivityClosedIntentFilter.addDataAuthority(intent.getData().getAuthori
ty(), null); | |
87 mActivityClosedIntentFilter.addDataPath( | |
88 intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL); | |
89 mActivityClosedIntentFilter.addAction(CastWebContentsActivity.ACTION_ACT
IVITY_STOPPED); | |
90 mActivityClosedIntentFilter.addAction(CastWebContentsActivity.ACTION_KEY
_EVENT); | |
91 LocalBroadcastManager.getInstance(mContext).registerReceiver( | |
92 mActivityClosedBroadcastReceiver, mActivityClosedIntentFilter); | |
93 | |
94 intent.putExtra(CastWebContentsActivity.ACTION_EXTRA_WEB_CONTENTS, webCo
ntents); | |
95 // FLAG_ACTIVITY_SINGLE_TOP will try to reuse existing activity. | |
96 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MUL
TIPLE_TASK | |
97 | Intent.FLAG_ACTIVITY_SINGLE_TOP); | |
98 mContext.startActivity(intent); | |
99 } | 57 } |
100 | 58 |
101 @SuppressWarnings("unused") | 59 @SuppressWarnings("unused") |
102 @CalledByNative | 60 @CalledByNative |
103 private void onNativeDestroyed() { | 61 private void onNativeDestroyed() { |
104 assert mNativeCastContentWindowAndroid != 0; | 62 assert mNativeCastContentWindowAndroid != 0; |
105 mNativeCastContentWindowAndroid = 0; | 63 mNativeCastContentWindowAndroid = 0; |
106 | 64 |
107 // Note: there is a potential race condition when this function is calle
d after | 65 // Note: there is a potential race condition when this function is calle
d after |
108 // showWebContents. If the stop intent is received after the start inten
t but before | 66 // showWebContents. If the stop intent is received after the start inten
t but before |
109 // onCreate, the activity won't shutdown. | 67 // onCreate, the activity won't shutdown. |
110 // TODO(derekjchow): Add a unittest to check this behaviour. Also consid
er using | 68 // TODO(derekjchow): Add a unittest to check this behaviour. Also consid
er using |
111 // Instrumentation.startActivitySync to guarentee onCreate is run. | 69 // Instrumentation.startActivitySync to guarentee onCreate is run. |
112 | 70 |
113 if (DEBUG) Log.d(TAG, "onNativeDestroyed"); | 71 if (DEBUG) Log.d(TAG, "onNativeDestroyed"); |
114 Intent intent = new Intent(CastWebContentsActivity.ACTION_STOP_ACTIVITY,
getInstanceUri()); | 72 mComponent.stop(mContext); |
115 LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(intent); | |
116 } | 73 } |
117 | 74 |
118 private void onActivityStopped() { | 75 @Override |
119 if (DEBUG) Log.d(TAG, "onActivityStopped"); | 76 public void onKeyDown(int keyCode) { |
120 if (mNativeCastContentWindowAndroid != 0) { | |
121 nativeOnActivityStopped(mNativeCastContentWindowAndroid); | |
122 } | |
123 } | |
124 | |
125 private void onKeyDown(int keyCode) { | |
126 if (DEBUG) Log.d(TAG, "onKeyDown"); | 77 if (DEBUG) Log.d(TAG, "onKeyDown"); |
127 if (mNativeCastContentWindowAndroid != 0) { | 78 if (mNativeCastContentWindowAndroid != 0) { |
128 nativeOnKeyDown(mNativeCastContentWindowAndroid, keyCode); | 79 nativeOnKeyDown(mNativeCastContentWindowAndroid, keyCode); |
129 } | 80 } |
130 } | 81 } |
131 | 82 |
| 83 @Override |
| 84 public void onComponentClosed() { |
| 85 if (DEBUG) Log.d(TAG, "onComponentClosed"); |
| 86 if (mNativeCastContentWindowAndroid != 0) { |
| 87 nativeOnActivityStopped(mNativeCastContentWindowAndroid); |
| 88 } |
| 89 } |
| 90 |
132 private native void nativeOnActivityStopped(long nativeCastContentWindowAndr
oid); | 91 private native void nativeOnActivityStopped(long nativeCastContentWindowAndr
oid); |
| 92 |
133 private native void nativeOnKeyDown(long nativeCastContentWindowAndroid, int
keyCode); | 93 private native void nativeOnKeyDown(long nativeCastContentWindowAndroid, int
keyCode); |
134 } | 94 } |
OLD | NEW |