Chromium Code Reviews| Index: chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java |
| diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2041c98346dc2708c0af4e387b3a4729769e1895 |
| --- /dev/null |
| +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java |
| @@ -0,0 +1,203 @@ |
| +// Copyright 2016 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.chromecast.shell; |
| + |
| +import android.content.BroadcastReceiver; |
| +import android.content.ComponentName; |
| +import android.content.Context; |
| +import android.content.Intent; |
| +import android.content.IntentFilter; |
| +import android.content.ServiceConnection; |
| +import android.net.Uri; |
| +import android.os.IBinder; |
| +import android.os.PatternMatcher; |
| +import android.support.v4.content.LocalBroadcastManager; |
| + |
| +import org.chromium.base.Log; |
| +import org.chromium.content_public.browser.WebContents; |
| + |
| +/** |
| + * A layer of indirection between CastContentWindowAndroid and CastWebContents(Activity|Service). |
| + * <p> |
| + * On builds with CAST_ANDROID_USE_SERVICE set to false, it will use CastWebContentsActivity, |
| + * otherwise, it will use CastWebContentsService. |
| + */ |
| +public class CastWebContentsComponent { |
| + /** |
| + * Callback interface for when the associated component is closed or the |
| + * WebContents is detached. |
| + */ |
| + public interface OnComponentClosedHandler { void onComponentClosed(); } |
| + |
| + /** |
| + * Callback interface for passing along keyDown events. This only applies |
| + * to CastWebContentsActivity, really. |
| + */ |
| + public interface OnKeyDownHandler { void onKeyDown(int keyCode); } |
| + |
| + interface Delegate { |
| + void start(Context context, WebContents webContents); |
| + void stop(Context context); |
| + } |
| + |
| + class ActivityDelegate implements Delegate { |
|
Simeon
2017/05/15 19:47:24
Does this need to be package-private?
thoren
2017/05/15 22:25:24
Nope. Went ahead and made it private.
|
| + private static final String TAG = CastWebContentsComponent.TAG + ".ActivityDelegate"; |
|
Simeon
2017/05/15 19:47:24
We don't want dots in tag names because the log el
thoren
2017/05/15 22:25:24
It was being printed, but I went ahead and changed
|
| + |
| + @Override |
| + public void start(Context context, WebContents webContents) { |
| + if (DEBUG) Log.d(TAG, "start"); |
| + |
| + Intent intent = new Intent(Intent.ACTION_VIEW, getInstanceUri(mInstanceId), context, |
| + CastWebContentsActivity.class); |
| + intent.putExtra(ACTION_EXTRA_WEB_CONTENTS, webContents); |
| + // FLAG_ACTIVITY_SINGLE_TOP will try to reuse existing activity. |
| + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK |
| + | Intent.FLAG_ACTIVITY_SINGLE_TOP); |
| + context.startActivity(intent); |
| + } |
| + |
| + @Override |
| + public void stop(Context context) { |
| + if (DEBUG) Log.d(TAG, "stop"); |
| + |
| + Intent intent = new Intent( |
| + CastWebContentsActivity.ACTION_STOP_ACTIVITY, getInstanceUri(mInstanceId)); |
| + LocalBroadcastManager.getInstance(context).sendBroadcastSync(intent); |
| + } |
| + } |
| + |
| + class ServiceDelegate implements Delegate { |
|
Simeon
2017/05/15 19:47:24
Does this need to be package-private?
thoren
2017/05/15 22:25:23
Done.
|
| + private static final String TAG = CastWebContentsComponent.TAG + ".ServiceDelegate"; |
| + |
| + private ServiceConnection mConnection = new ServiceConnection() { |
| + @Override |
| + public void onServiceConnected(ComponentName name, IBinder service) {} |
| + |
| + @Override |
| + public void onServiceDisconnected(ComponentName name) { |
| + if (DEBUG) Log.d(TAG, "onServiceDisconnected"); |
| + |
| + if (mComponentClosedHandler != null) mComponentClosedHandler.onComponentClosed(); |
| + } |
| + }; |
| + |
| + @Override |
| + public void start(Context context, WebContents webContents) { |
| + if (DEBUG) Log.d(TAG, "start"); |
| + |
| + Intent intent = new Intent(Intent.ACTION_VIEW, getInstanceUri(mInstanceId), context, |
| + CastWebContentsService.class); |
| + intent.putExtra(ACTION_EXTRA_WEB_CONTENTS, webContents); |
| + context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); |
| + } |
| + |
| + @Override |
| + public void stop(Context context) { |
| + if (DEBUG) Log.d(TAG, "stop"); |
| + |
| + context.unbindService(mConnection); |
| + } |
| + } |
| + |
| + class Receiver extends BroadcastReceiver { |
|
Simeon
2017/05/15 19:47:24
Does this need to be package-private?
thoren
2017/05/15 22:25:23
Done.
|
| + @Override |
| + public void onReceive(Context context, Intent intent) { |
| + if (intent.getAction().equals(ACTION_ACTIVITY_STOPPED)) { |
| + if (DEBUG) Log.d(TAG, "onReceive ACTION_ACTIVITY_STOPPED"); |
| + |
| + if (mComponentClosedHandler != null) mComponentClosedHandler.onComponentClosed(); |
| + } else if (intent.getAction().equals(ACTION_KEY_EVENT)) { |
| + if (DEBUG) Log.d(TAG, "onReceive ACTION_KEY_EVENT"); |
| + |
| + int keyCode = intent.getIntExtra(ACTION_EXTRA_KEY_CODE, 0); |
| + if (mKeyDownHandler != null) mKeyDownHandler.onKeyDown(keyCode); |
| + } |
| + } |
| + } |
| + |
| + private static final String TAG = "cr_CastWebComponent"; |
| + private static final boolean DEBUG = true; |
|
Simeon
2017/05/15 19:47:24
We might want to make this false in the final patc
thoren
2017/05/15 22:25:24
Not that useful. Done.
|
| + |
| + private static final String ACTION_DATA_SCHEME = "cast"; |
| + private static final String ACTION_DATA_AUTHORITY = "webcontents"; |
| + private static final String ACTION_EXTRA_WEB_CONTENTS = |
| + "com.google.android.apps.castshell.intent.extra.WEB_CONTENTS"; |
|
Simeon
2017/05/15 19:47:24
These are redeclared in CastWebContentsService and
thoren
2017/05/15 22:25:24
Done.
|
| + private static final String ACTION_EXTRA_KEY_CODE = |
| + "com.google.android.apps.castshell.intent.extra.KEY_CODE"; |
| + private static final String ACTION_KEY_EVENT = |
| + "com.google.android.apps.castshell.intent.action.KEY_EVENT"; |
| + private static final String ACTION_ACTIVITY_STOPPED = |
| + "com.google.android.apps.castshell.intent.action.ACTIVITY_STOPPED"; |
| + |
| + private Delegate mDelegate; |
| + private OnComponentClosedHandler mComponentClosedHandler; |
| + private OnKeyDownHandler mKeyDownHandler; |
| + private Receiver mReceiver; |
| + private String mInstanceId; |
| + |
| + public CastWebContentsComponent(String instanceId) { |
| + mInstanceId = instanceId; |
| + if (BuildConfig.CAST_ANDROID_USE_SERVICE) { |
| + mDelegate = new ServiceDelegate(); |
| + } else { |
| + mDelegate = new ActivityDelegate(); |
| + } |
| + } |
| + |
| + public void setOnComponentClosedHandler(OnComponentClosedHandler onComponentClosedHandler) { |
| + mComponentClosedHandler = onComponentClosedHandler; |
| + } |
| + |
| + public void setOnKeyDownHandler(OnKeyDownHandler onKeyDownHandler) { |
| + mKeyDownHandler = onKeyDownHandler; |
| + } |
| + |
| + public void start(Context context, WebContents webContents) { |
| + if (DEBUG) Log.d(TAG, "start"); |
| + |
| + Uri instanceUri = getInstanceUri(mInstanceId); |
| + mReceiver = new Receiver(); |
| + IntentFilter filter = new IntentFilter(); |
| + filter.addDataScheme(instanceUri.getScheme()); |
| + filter.addDataAuthority(instanceUri.getAuthority(), null); |
| + filter.addDataPath(instanceUri.getPath(), PatternMatcher.PATTERN_LITERAL); |
| + filter.addAction(ACTION_ACTIVITY_STOPPED); |
| + filter.addAction(ACTION_KEY_EVENT); |
| + LocalBroadcastManager.getInstance(context).registerReceiver(mReceiver, filter); |
| + |
| + mDelegate.start(context, webContents); |
| + } |
| + |
| + public void stop(Context context) { |
| + if (DEBUG) Log.d(TAG, "stop"); |
| + |
| + LocalBroadcastManager.getInstance(context).unregisterReceiver(mReceiver); |
| + mDelegate.stop(context); |
| + } |
| + |
| + public static void onComponentClosed(Context context, String instanceId) { |
| + if (DEBUG) Log.d(TAG, "onComponentClosed"); |
| + |
| + Intent intent = new Intent(ACTION_ACTIVITY_STOPPED, getInstanceUri(instanceId)); |
| + LocalBroadcastManager.getInstance(context).sendBroadcastSync(intent); |
| + } |
| + |
| + public static void onKeyDown(Context context, String instanceId, int keyCode) { |
| + if (DEBUG) Log.d(TAG, "onKeyDown"); |
| + |
| + Intent intent = new Intent(ACTION_KEY_EVENT, getInstanceUri(instanceId)); |
| + intent.putExtra(ACTION_EXTRA_KEY_CODE, keyCode); |
| + LocalBroadcastManager.getInstance(context).sendBroadcastSync(intent); |
| + } |
| + |
| + private static Uri getInstanceUri(String instanceId) { |
| + Uri instanceUri = new Uri.Builder() |
| + .scheme(ACTION_DATA_SCHEME) |
| + .authority(ACTION_DATA_AUTHORITY) |
| + .path(instanceId) |
| + .build(); |
| + return instanceUri; |
| + } |
| +} |