Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ protected void createContent(final Bundle savedInstanceState) {
getStarboardBridge().handleDeepLink(startDeepLink);
}

mShellManager = new ShellManager(this);
// Create a new FrameLayout to hold the Shell view.
FrameLayout shellContainer = new FrameLayout(this);
setContentView(shellContainer);
mShellManager = new ShellManager(this, shellContainer);
final boolean listenToActivityState = true;
mIntentRequestTracker = IntentRequestTracker.createFromActivity(this);
mWindowAndroid =
Expand Down
1 change: 1 addition & 0 deletions cobalt/shell/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ android_resources("cobalt_shell_java_resources") {
sources = [
"java/res/drawable-xhdpi/app_banner.png",
"java/res/layout/coat_error_dialog.xml",
"java/res/layout/shell_view.xml",
"java/res/mipmap-hdpi/ic_app.png",
"java/res/mipmap-mdpi/ic_app.png",
"java/res/mipmap-xhdpi/ic_app.png",
Expand Down
20 changes: 20 additions & 0 deletions cobalt/shell/android/java/res/layout/shell_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 The Cobalt Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<dev.cobalt.shell.Shell
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />
34 changes: 27 additions & 7 deletions cobalt/shell/android/java/src/dev/cobalt/shell/Shell.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
Expand All @@ -44,7 +45,8 @@
* Container for the various UI components that make up a shell window.
*/
@JNINamespace("content")
public class Shell {
/** Cobalt's own Java implementation of Shell. */
public class Shell extends FrameLayout {
/**
* Interface for notifying observers of WebContents readiness.
*/
Expand Down Expand Up @@ -80,11 +82,19 @@ public interface OnWebContentsReadyListener {
/**
* Constructor for inflating via XML.
*/
public Shell(Context context) {
public Shell(Context context, AttributeSet attrs) {
super(context, attrs);
Activity activity = (Activity) context;
mRootView = activity.findViewById(android.R.id.content);
}

/**
* Constructor for inflating via XML.
*/
public Shell(Context context) {
this(context, null);
}

public void setRootViewForTesting(ViewGroup view) {
mRootView = view;
}
Expand Down Expand Up @@ -126,7 +136,9 @@ public void initialize(long nativeShell, WindowAndroid window) {
* dependencies.
*/
public void close() {
if (mNativeShell == 0) return;
if (mNativeShell == 0) {
return;
}
ShellJni.get().closeShell(mNativeShell);
}

Expand Down Expand Up @@ -159,7 +171,9 @@ public boolean isLoading() {
* @param url The URL to be loaded by the shell.
*/
public void loadUrl(String url) {
if (url == null) return;
if (url == null) {
return;
}

if (TextUtils.equals(url, mWebContents.getLastCommittedUrl().getSpec())) {
mNavigationController.reload(true);
Expand All @@ -174,8 +188,12 @@ public void loadUrl(String url) {
* @return The sanitized URL.
*/
public static String sanitizeUrl(String url) {
if (url == null) return null;
if (url.startsWith("www.") || url.indexOf(":") == -1) url = "http://" + url;
if (url == null) {
return null;
}
if (url.startsWith("www.") || url.indexOf(":") == -1) {
url = "http://" + url;
}
return url;
}

Expand Down Expand Up @@ -211,7 +229,9 @@ public ShellViewAndroidDelegate getViewAndroidDelegate() {
private void initFromNativeTabContents(WebContents webContents) {
mViewAndroidDelegate = new ShellViewAndroidDelegate(mRootView);
assert (mWebContents != webContents);
if (mWebContents != null) mWebContents.clearNativeReference();
if (mWebContents != null) {
mWebContents.clearNativeReference();
}
webContents.setDelegates(
"", mViewAndroidDelegate, null, mWindow, WebContents.createDefaultInternalsHolder());
mWebContents = webContents;
Expand Down
40 changes: 29 additions & 11 deletions cobalt/shell/android/java/src/dev/cobalt/shell/ShellManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
package dev.cobalt.shell;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import org.chromium.base.ThreadUtils;
import org.chromium.components.embedder_support.view.ContentViewRenderView;
import org.chromium.content_public.browser.Visibility;
Expand Down Expand Up @@ -42,13 +45,15 @@ public class ShellManager {
// The target for all content rendering.
private ContentViewRenderView mContentViewRenderView;

private Context mContext;
private final Context mContext;
private final ViewGroup mShellContainer;

/**
* Constructor for inflating via XML.
* Constructor
*/
public ShellManager(final Context context) {
public ShellManager(final Context context, ViewGroup shellContainer) {
mContext = context;
mShellContainer = shellContainer;
if (sNatives == null) {
sNatives = ShellManagerJni.get();
}
Expand Down Expand Up @@ -116,7 +121,9 @@ public void launchShell(String url, Shell.OnWebContentsReadyListener listener) {
mNextWebContentsReadyListener = listener;
Shell previousShell = mActiveShell;
sNatives.launchShell(url);
if (previousShell != null) previousShell.close();
if (previousShell != null) {
previousShell.close();
}
}

@CalledByNative
Expand All @@ -126,23 +133,27 @@ private Object createShell(long nativeShellPtr) {
mContentViewRenderView.onNativeLibraryLoaded(mWindow);
}

Shell shellView = new Shell(getContext());
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Shell shellView = (Shell) inflater.inflate(R.layout.shell_view, null);
Comment on lines +136 to +138
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block can be simplified and improved. You can get the LayoutInflater more cleanly with LayoutInflater.from(getContext()). Also, using null as the root ViewGroup for inflate() is discouraged as it causes LayoutParams from the XML to be ignored. It's better to use the three-argument version inflate(R.layout.shell_view, mShellContainer, false). This will also allow simplifying the addView call in showShell to just mShellContainer.addView(shellView);.

Suggested change
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Shell shellView = (Shell) inflater.inflate(R.layout.shell_view, null);
Shell shellView = (Shell) LayoutInflater.from(getContext())
.inflate(R.layout.shell_view, mShellContainer, false);

shellView.initialize(nativeShellPtr, mWindow);
shellView.setWebContentsReadyListener(mNextWebContentsReadyListener);
mNextWebContentsReadyListener = null;

// TODO(tedchoc): Allow switching back to these inactive shells.
if (mActiveShell != null) removeShell(mActiveShell);
if (mActiveShell != null) {
removeShell(mActiveShell);
}

showShell(shellView);
return shellView;
}

private void showShell(Shell shellView) {
if (mActiveShell != null) {
mActiveShell.setContentViewRenderView(null);
}
shellView.setContentViewRenderView(mContentViewRenderView);
mShellContainer.addView(shellView,
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
mActiveShell = shellView;
WebContents webContents = mActiveShell.getWebContents();
if (webContents != null) {
Expand All @@ -153,8 +164,14 @@ private void showShell(Shell shellView) {

@CalledByNative
private void removeShell(Shell shellView) {
if (shellView == mActiveShell) mActiveShell = null;
if (shellView == mActiveShell) {
mActiveShell = null;
}
if (shellView.getParent() == null) {
return;
}
shellView.setContentViewRenderView(null);
mShellContainer.removeView(shellView);
}

/**
Expand All @@ -166,7 +183,8 @@ private void removeShell(Shell shellView) {
public void destroy() {
// Remove active shell (Currently single shell support only available).
if (mActiveShell != null) {
removeShell(mActiveShell);
mActiveShell.close();
mActiveShell = null;
}
if (mContentViewRenderView != null) {
mContentViewRenderView.destroy();
Expand Down
16 changes: 14 additions & 2 deletions cobalt/testing/browser_tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ static_library("cobalt_browsertests_test_runner") {
"content_test_launcher.cc",
"resource_load_observer.cc",
"resource_load_observer.h",
"web_contents_delegate_stub.cc",
"web_contents_delegate_stub.h",
"webrtc_content_browsertest_base.cc",
"webrtc_content_browsertest_base.h",
]
Expand All @@ -99,6 +101,7 @@ static_library("cobalt_browsertests_test_runner") {
"//base/test:test_config",
"//build:chromeos_buildflags",
"//cobalt/shell:cobalt_shell_app",
"//cobalt/shell:shell_test_switches_lib",
"//components/network_session_configurator/common:common",
"//components/services/storage:storage",
"//content/app:for_content_tests",
Expand Down Expand Up @@ -158,6 +161,7 @@ if (is_android) {
"//base:base_java",
"//base:base_java_test_support",
"//base:content_uri_utils_java",
"//cobalt/android:cobalt_main_java",
"//cobalt/shell/android:cobalt_shell_java",
"//components/download/internal/common:internal_java",
"//components/metrics:metrics_java",
Expand Down Expand Up @@ -198,7 +202,7 @@ test("cobalt_browsertests") {
#"media_browsertest.h",
#"media_session_browsertest.cc",
#"media_source_browsertest.cc",
#"navigation_browsertest.cc",
"navigation_browsertest.cc",
#"session_history_browsertest.cc",
#"site_per_process_browsertest.cc",
#"site_per_process_browsertest.h",
Expand All @@ -222,11 +226,14 @@ test("cobalt_browsertests") {

deps = [
":cobalt_browsertests_test_runner",
":cobalt_shell_test_lib",
"//base/test:test_support",
"//build:chromecast_buildflags",
"//build:chromeos_buildflags",
"//cc/slim",
"//cobalt/shell:cobalt_shell_lib",
"//cobalt/shell:pak",
"//cobalt/shell:shell_test_switches_lib",
"//components/attribution_reporting:mojom",
"//components/discardable_memory/client",
"//components/discardable_memory/common",
Expand All @@ -251,11 +258,11 @@ test("cobalt_browsertests") {
"//content/browser/background_sync:background_sync_proto",
"//content/child:for_content_tests",
"//content/gpu",
"//content/public/browser",
"//content/public/gpu",
"//content/renderer:for_content_tests",
"//content/services/auction_worklet/public/mojom:for_content_tests",
"//content/test:mojo_web_test_bindings",
"//content/test:test_support",
"//content/test:web_ui_managed_interface_tests_bindings",
"//content/test:web_ui_ts_test_mojo_bindings",
"//device/base/synchronization",
Expand Down Expand Up @@ -413,9 +420,11 @@ static_library("cobalt_shell_test_lib") {

deps = [
":cobalt_browsertests_support",
":cobalt_browsertests_support_mojom",
"//cc/base",
"//cobalt/shell:cobalt_shell_app",
"//cobalt/shell:cobalt_shell_lib",
"//cobalt/shell:shell_test_switches_lib",
"//components/prefs",
"//components/prefs:test_support",
"//components/variations",
Expand Down Expand Up @@ -450,6 +459,8 @@ source_set("cobalt_browsertests_support") {
"common/main_frame_counter_test_impl.h",
"common/power_monitor_test_impl.cc",
"common/power_monitor_test_impl.h",
"common/shell_test_switches.cc",
"common/shell_test_switches.h",
"renderer/render_frame_test_helper.cc",
"renderer/render_frame_test_helper.h",
"renderer/shell_render_frame_observer.cc",
Expand All @@ -463,6 +474,7 @@ source_set("cobalt_browsertests_support") {
"//components/custom_handlers:test_support",
"//components/metrics:test_support",
"//components/services/storage/test_api",
"//content/browser",
"//content/common:main_frame_counter",
"//content/public/child",
"//content/public/common",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "cobalt/shell/common/shell_switches.h"
#include "cobalt/testing/browser_tests/common/shell_controller.test-mojom.h"
#include "cobalt/testing/browser_tests/common/shell_test_switches.h"
#include "components/custom_handlers/protocol_handler.h"
#include "components/custom_handlers/protocol_handler_registry.h"
#include "components/custom_handlers/protocol_handler_throttle.h"
#include "components/custom_handlers/simple_protocol_handler_registry_factory.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ limitations under the License.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical">
<dev.cobalt.shell.ShellManager
<FrameLayout
android:id="@+id/shell_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,30 @@
package org.chromium.content_browsertests_apk;

import android.content.Context;

import dev.cobalt.coat.StarboardBridge;
import org.chromium.base.PathUtils;
import org.chromium.native_test.NativeBrowserTestApplication;
import org.chromium.ui.base.ResourceBundle;

/**
* A basic content_public.browser.tests {@link android.app.Application}.
*/
public class ContentBrowserTestsApplication extends NativeBrowserTestApplication {
public class ContentBrowserTestsApplication extends NativeBrowserTestApplication
implements StarboardBridge.HostApplication {
static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "content_shell";

private StarboardBridge mStarboardBridge;

@Override
public void setStarboardBridge(StarboardBridge starboardBridge) {
mStarboardBridge = starboardBridge;
}

@Override
public StarboardBridge getStarboardBridge() {
return mStarboardBridge;
}

@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Expand Down
Loading
Loading