diff options
Diffstat (limited to 'chromium/weblayer/shell')
16 files changed, 332 insertions, 97 deletions
diff --git a/chromium/weblayer/shell/android/BUILD.gn b/chromium/weblayer/shell/android/BUILD.gn index bc3a270505f..5a6d1f7ff78 100644 --- a/chromium/weblayer/shell/android/BUILD.gn +++ b/chromium/weblayer/shell/android/BUILD.gn @@ -203,7 +203,7 @@ android_apk("weblayer_support_apk") { rebase_path("$root_gen_dir/CHROME_VERSION.json", root_build_dir) native_lib_version_arg = "@FileArg($_native_lib_file:full-quoted)" - shared_libraries = [ "//weblayer:libweblayer" ] + shared_libraries = [ "//weblayer:libweblayer_test" ] } python_library("weblayer_shell_wpt") { diff --git a/chromium/weblayer/shell/android/browsertests_apk/metrics_browsertest.cc b/chromium/weblayer/shell/android/browsertests_apk/metrics_browsertest.cc index 30ff1b25e2c..a4f0af9ae89 100644 --- a/chromium/weblayer/shell/android/browsertests_apk/metrics_browsertest.cc +++ b/chromium/weblayer/shell/android/browsertests_apk/metrics_browsertest.cc @@ -4,33 +4,51 @@ #include <deque> -#include "base/android/jni_android.h" #include "base/command_line.h" +#include "base/metrics/metrics_hashes.h" +#include "base/metrics/statistics_recorder.h" #include "base/no_destructor.h" #include "base/test/bind_test_util.h" +#include "components/metrics/log_decoder.h" +#include "components/metrics/metrics_log_uploader.h" #include "components/metrics/metrics_switches.h" +#include "content/public/test/browser_test_utils.h" #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h" #include "weblayer/browser/android/metrics/weblayer_metrics_service_client.h" #include "weblayer/browser/profile_impl.h" #include "weblayer/public/navigation_controller.h" #include "weblayer/public/profile.h" #include "weblayer/public/tab.h" +#include "weblayer/shell/android/browsertests_apk/metrics_test_helper.h" #include "weblayer/shell/browser/shell.h" #include "weblayer/test/weblayer_browser_test.h" -#include "weblayer/test/weblayer_browsertests_jni/MetricsTestHelper_jni.h" +#include "weblayer/test/weblayer_browser_test_utils.h" namespace weblayer { +namespace { + +bool HasHistogramWithHash(const metrics::ChromeUserMetricsExtension& uma_log, + uint64_t hash) { + for (int i = 0; i < uma_log.histogram_event_size(); ++i) { + if (uma_log.histogram_event(i).name_hash() == hash) { + return true; + } + } + return false; +} + +} // namespace + class MetricsBrowserTest : public WebLayerBrowserTest { public: void SetUp() override { - instance_ = this; - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); command_line->AppendSwitch(metrics::switches::kForceEnableMetricsReporting); - Java_MetricsTestHelper_installTestGmsBridge( - base::android::AttachCurrentThread(), HasUserConsent()); + InstallTestGmsBridge(HasUserConsent(), + base::BindRepeating(&MetricsBrowserTest::OnLogMetrics, + base::Unretained(this))); WebLayerMetricsServiceClient::GetInstance()->SetFastStartupForTesting(true); WebLayerMetricsServiceClient::GetInstance()->SetUploadIntervalForTesting( base::TimeDelta::FromMilliseconds(10)); @@ -38,20 +56,17 @@ class MetricsBrowserTest : public WebLayerBrowserTest { } void TearDown() override { - Java_MetricsTestHelper_removeTestGmsBridge( - base::android::AttachCurrentThread()); - instance_ = nullptr; + RemoveTestGmsBridge(); WebLayerBrowserTest::TearDown(); } - static void OnLogMetrics(const metrics::ChromeUserMetricsExtension& metric) { - if (!instance_) - return; - instance_->metrics_logs_.push_back(metric); - std::move(instance_->on_new_log_).Run(); + void OnLogMetrics(metrics::ChromeUserMetricsExtension metric) { + metrics_logs_.push_back(metric); + if (on_new_log_) + std::move(on_new_log_).Run(); } - metrics::ChromeUserMetricsExtension waitForNextMetricsLog() { + metrics::ChromeUserMetricsExtension WaitForNextMetricsLog() { if (metrics_logs_.empty()) { base::RunLoop run_loop; on_new_log_ = run_loop.QuitClosure(); @@ -71,23 +86,10 @@ class MetricsBrowserTest : public WebLayerBrowserTest { std::unique_ptr<Profile> profile_; std::deque<metrics::ChromeUserMetricsExtension> metrics_logs_; base::OnceClosure on_new_log_; - static MetricsBrowserTest* instance_; }; -MetricsBrowserTest* MetricsBrowserTest::instance_ = nullptr; - -void JNI_MetricsTestHelper_OnLogMetrics( - JNIEnv* env, - const base::android::JavaParamRef<jbyteArray>& data) { - metrics::ChromeUserMetricsExtension proto; - jbyte* src_bytes = env->GetByteArrayElements(data, nullptr); - proto.ParseFromArray(src_bytes, env->GetArrayLength(data.obj())); - env->ReleaseByteArrayElements(data, src_bytes, JNI_ABORT); - MetricsBrowserTest::OnLogMetrics(proto); -} - IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, ProtoHasExpectedFields) { - metrics::ChromeUserMetricsExtension log = waitForNextMetricsLog(); + metrics::ChromeUserMetricsExtension log = WaitForNextMetricsLog(); EXPECT_EQ(metrics::ChromeUserMetricsExtension::ANDROID_WEBLAYER, log.product()); EXPECT_TRUE(log.has_client_id()); @@ -118,7 +120,7 @@ IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, ProtoHasExpectedFields) { } IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, PageLoadsEnableMultipleUploads) { - waitForNextMetricsLog(); + WaitForNextMetricsLog(); // At this point, the MetricsService should be asleep, and should not have // created any more metrics logs. @@ -133,7 +135,7 @@ IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, PageLoadsEnableMultipleUploads) { // This may take slightly longer than UPLOAD_INTERVAL_MS, due to the time // spent processing the metrics log, but should be well within the timeout // (unless something is broken). - waitForNextMetricsLog(); + WaitForNextMetricsLog(); // If we get here, we got a second metrics log (and the test may pass). If // there was no second metrics log, then the above call will check fail with a @@ -143,6 +145,35 @@ IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, PageLoadsEnableMultipleUploads) { // might potentially have a third metrics log in the queue. } +IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, RendererHistograms) { + base::HistogramTester histogram_tester; + ASSERT_TRUE(embedded_test_server()->Start()); + + NavigateAndWaitForCompletion( + embedded_test_server()->GetURL("/simple_page.html"), shell()); + + uint64_t hash = base::HashMetricName("Android.SeccompStatus.RendererSandbox"); + + bool collect_final_metrics_for_log_called = false; + + WebLayerMetricsServiceClient::GetInstance() + ->SetCollectFinalMetricsForLogClosureForTesting( + base::BindLambdaForTesting( + [&]() { collect_final_metrics_for_log_called = true; })); + + // Not every WaitForNextMetricsLog call will end up calling + // MetricsServiceClient::CollectFinalMetricsForLog since there may already be + // staged logs to send (see ReportingService::SendNextLog). Since we need to + // wait for CollectFinalMetricsForLog to be run after the navigate call above, + // keep calling WaitForNextMetricsLog until CollectFinalMetricsForLog is + // called. + metrics::ChromeUserMetricsExtension uma_log; + while (!collect_final_metrics_for_log_called) + uma_log = WaitForNextMetricsLog(); + + ASSERT_TRUE(HasHistogramWithHash(uma_log, hash)); +} + class MetricsBrowserTestWithUserOptOut : public MetricsBrowserTest { bool HasUserConsent() override { return false; } }; diff --git a/chromium/weblayer/shell/android/browsertests_apk/metrics_test_helper.cc b/chromium/weblayer/shell/android/browsertests_apk/metrics_test_helper.cc new file mode 100644 index 00000000000..5b78584f5a1 --- /dev/null +++ b/chromium/weblayer/shell/android/browsertests_apk/metrics_test_helper.cc @@ -0,0 +1,61 @@ +// Copyright 2020 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. + +#include "weblayer/shell/android/browsertests_apk/metrics_test_helper.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/no_destructor.h" +#include "weblayer/test/weblayer_browsertests_jni/MetricsTestHelper_jni.h" + +namespace weblayer { + +namespace { + +OnLogsMetricsCallback& GetOnLogMetricsCallback() { + static base::NoDestructor<OnLogsMetricsCallback> s_callback; + return *s_callback; +} + +} // namespace + +void InstallTestGmsBridge(bool has_user_consent, + const OnLogsMetricsCallback on_log_metrics) { + GetOnLogMetricsCallback() = on_log_metrics; + Java_MetricsTestHelper_installTestGmsBridge( + base::android::AttachCurrentThread(), has_user_consent); +} + +void RemoveTestGmsBridge() { + Java_MetricsTestHelper_removeTestGmsBridge( + base::android::AttachCurrentThread()); + GetOnLogMetricsCallback().Reset(); +} + +void CreateProfile(const std::string& name) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_MetricsTestHelper_createProfile( + env, base::android::ConvertUTF8ToJavaString(env, name)); +} +void DestroyProfile(const std::string& name) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_MetricsTestHelper_destroyProfile( + env, base::android::ConvertUTF8ToJavaString(env, name)); +} + +void JNI_MetricsTestHelper_OnLogMetrics( + JNIEnv* env, + const base::android::JavaParamRef<jbyteArray>& data) { + auto& callback = GetOnLogMetricsCallback(); + if (!callback) + return; + + metrics::ChromeUserMetricsExtension proto; + jbyte* src_bytes = env->GetByteArrayElements(data, nullptr); + proto.ParseFromArray(src_bytes, env->GetArrayLength(data.obj())); + env->ReleaseByteArrayElements(data, src_bytes, JNI_ABORT); + callback.Run(proto); +} + +} // namespace weblayer diff --git a/chromium/weblayer/shell/android/browsertests_apk/metrics_test_helper.h b/chromium/weblayer/shell/android/browsertests_apk/metrics_test_helper.h new file mode 100644 index 00000000000..6c54134cbcc --- /dev/null +++ b/chromium/weblayer/shell/android/browsertests_apk/metrics_test_helper.h @@ -0,0 +1,36 @@ +// Copyright 2020 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. + +#ifndef WEBLAYER_SHELL_ANDROID_BROWSERTESTS_APK_METRICS_TEST_HELPER_H_ +#define WEBLAYER_SHELL_ANDROID_BROWSERTESTS_APK_METRICS_TEST_HELPER_H_ + +#include <string> + +#include "base/callback.h" +#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h" + +namespace weblayer { + +// Various utilities to bridge to Java code for metrics related tests. + +using OnLogsMetricsCallback = + base::RepeatingCallback<void(metrics::ChromeUserMetricsExtension)>; + +// Call this in the SetUp() test harness method to install the test +// GmsBridge and to set the metrics user consent state. +void InstallTestGmsBridge( + bool has_user_consent, + const OnLogsMetricsCallback on_log_metrics = OnLogsMetricsCallback()); + +// Call this in the TearDown() test harness method to remove the GmsBridge. +void RemoveTestGmsBridge(); + +// See Profile::Create()'s comments for the semantics of |name|. +void CreateProfile(const std::string& name); + +void DestroyProfile(const std::string& name); + +} // namespace weblayer + +#endif // WEBLAYER_SHELL_ANDROID_BROWSERTESTS_APK_METRICS_TEST_HELPER_H_ diff --git a/chromium/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java b/chromium/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java index 4837ddac429..ecc26c1f6ca 100644 --- a/chromium/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java +++ b/chromium/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java @@ -14,11 +14,14 @@ import android.widget.RelativeLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; +import org.chromium.base.CommandLine; import org.chromium.base.test.util.UrlUtils; import org.chromium.content_public.browser.BrowserStartupController; import org.chromium.native_test.NativeBrowserTest; import org.chromium.native_test.NativeBrowserTestActivity; import org.chromium.weblayer.Browser; +import org.chromium.weblayer.NewTabCallback; +import org.chromium.weblayer.NewTabType; import org.chromium.weblayer.Profile; import org.chromium.weblayer.Tab; import org.chromium.weblayer.TabCallback; @@ -50,12 +53,13 @@ public class WebLayerBrowserTestsActivity extends NativeBrowserTestActivity { WebLayer.loadAsync(getApplication(), webLayer -> { mWebLayer = webLayer; createShell(); + + NativeBrowserTest.javaStartupTasksComplete(); }); } catch (Exception e) { throw new RuntimeException("failed loading WebLayer", e); } - NativeBrowserTest.javaStartupTasksComplete(); } protected void createShell() { @@ -76,7 +80,10 @@ public class WebLayerBrowserTestsActivity extends NativeBrowserTestActivity { new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - Fragment fragment = WebLayer.createBrowserFragment("BrowserTestProfile"); + CommandLine commandLine = CommandLine.getInstance(); + String path = (commandLine.hasSwitch("start-in-incognito")) ? null : "BrowserTestProfile"; + + Fragment fragment = WebLayer.createBrowserFragment(path); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(viewId, fragment); @@ -93,6 +100,14 @@ public class WebLayerBrowserTestsActivity extends NativeBrowserTestActivity { mUrlView.setText(uri.toString()); } }); + // Set a new tab callback to make sure popups are added. + mTab.setNewTabCallback(new NewTabCallback() { + @Override + public void onNewTab(Tab tab, @NewTabType int type) {} + + @Override + public void onCloseTab() {} + }); } @Override diff --git a/chromium/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_private/MetricsTestHelper.java b/chromium/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_private/MetricsTestHelper.java index 41affaaf8ab..c89b0e38793 100644 --- a/chromium/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_private/MetricsTestHelper.java +++ b/chromium/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_private/MetricsTestHelper.java @@ -4,11 +4,16 @@ package org.chromium.weblayer_private; +import android.content.Context; +import android.text.TextUtils; + import org.chromium.base.Callback; +import org.chromium.base.ContextUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; +import org.chromium.weblayer.WebLayer; /** * Helper for metrics_browsertest.cc @@ -50,6 +55,26 @@ class MetricsTestHelper { } @CalledByNative + private static void createProfile(String name) { + Context appContext = ContextUtils.getApplicationContext(); + WebLayer weblayer = WebLayer.loadSync(appContext); + + String nameOrNull = null; + if (!TextUtils.isEmpty(name)) nameOrNull = name; + weblayer.getProfile(nameOrNull); + } + + @CalledByNative + private static void destroyProfile(String name) { + Context appContext = ContextUtils.getApplicationContext(); + WebLayer weblayer = WebLayer.loadSync(appContext); + + String nameOrNull = null; + if (!TextUtils.isEmpty(name)) nameOrNull = name; + weblayer.getProfile(nameOrNull).destroy(); + } + + @CalledByNative private static void removeTestGmsBridge() { GmsBridge.injectInstance(null); } diff --git a/chromium/weblayer/shell/android/shell_apk/AndroidManifest.xml b/chromium/weblayer/shell/android/shell_apk/AndroidManifest.xml index fabe6849287..83ab34ddbd4 100644 --- a/chromium/weblayer/shell/android/shell_apk/AndroidManifest.xml +++ b/chromium/weblayer/shell/android/shell_apk/AndroidManifest.xml @@ -9,7 +9,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.weblayer.shell"> - <application android:label="WebLayer shell"> + <application android:label="WebLayer shell" + android:supportsRtl="true"> <activity android:name="WebLayerShellActivity" android:launchMode="singleTask" android:theme="@style/ShellTheme" diff --git a/chromium/weblayer/shell/android/shell_apk/res/layout/shell_browser_controls.xml b/chromium/weblayer/shell/android/shell_apk/res/layout/shell_browser_controls.xml index a07648248cc..f0f01f50784 100644 --- a/chromium/weblayer/shell/android/shell_apk/res/layout/shell_browser_controls.xml +++ b/chromium/weblayer/shell/android/shell_apk/res/layout/shell_browser_controls.xml @@ -28,6 +28,7 @@ android:imeOptions="actionGo" android:layout_width="match_parent" android:layout_height="match_parent" + android:importantForAutofill="no" android:textSize="15sp"/> <View diff --git a/chromium/weblayer/shell/android/shell_apk/res/menu/app_menu.xml b/chromium/weblayer/shell/android/shell_apk/res/menu/app_menu.xml index 02821be9b0f..2d6ff129de0 100644 --- a/chromium/weblayer/shell/android/shell_apk/res/menu/app_menu.xml +++ b/chromium/weblayer/shell/android/shell_apk/res/menu/app_menu.xml @@ -17,4 +17,6 @@ android:title="Bottom view" /> <item android:id="@+id/site_settings_menu_id" android:title="Site Settings" /> + <item android:id="@+id/translate_menu_id" + android:title="Translate" /> </menu> diff --git a/chromium/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java b/chromium/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java index bb67a110ab9..fa140357af6 100644 --- a/chromium/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java +++ b/chromium/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java @@ -4,6 +4,7 @@ package org.chromium.weblayer.shell; +import android.app.Activity; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -19,6 +20,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; +import android.webkit.URLUtil; import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; @@ -32,6 +34,7 @@ import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import org.chromium.base.CommandLine; import org.chromium.base.IntentUtils; import org.chromium.weblayer.Browser; import org.chromium.weblayer.ContextMenuParams; @@ -43,6 +46,7 @@ import org.chromium.weblayer.NavigationController; import org.chromium.weblayer.NewTabCallback; import org.chromium.weblayer.NewTabType; import org.chromium.weblayer.Profile; +import org.chromium.weblayer.SettingType; import org.chromium.weblayer.SiteSettingsActivity; import org.chromium.weblayer.Tab; import org.chromium.weblayer.TabCallback; @@ -58,7 +62,7 @@ import java.util.List; * Activity for managing the Demo Shell. */ public class WebLayerShellActivity extends FragmentActivity { - private static final String PROFILE_NAME = "DefaultProfile"; + private static final String NON_INCOGNITO_PROFILE_NAME = "DefaultProfile"; private static class ContextMenuCreator implements View.OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener { @@ -133,6 +137,7 @@ public class WebLayerShellActivity extends FragmentActivity { private List<Tab> mPreviousTabList = new ArrayList<>(); private Runnable mExitFullscreenRunnable; private View mBottomView; + private boolean mInIncognitoMode; @Override protected void onCreate(final Bundle savedInstanceState) { @@ -173,6 +178,9 @@ public class WebLayerShellActivity extends FragmentActivity { popup.getMenuInflater().inflate(R.menu.app_menu, popup.getMenu()); MenuItem bottomMenuItem = popup.getMenu().findItem(R.id.toggle_bottom_view_id); bottomMenuItem.setChecked(mBottomView != null); + popup.getMenu() + .findItem(R.id.translate_menu_id) + .setVisible(mBrowser.getActiveTab().canTranslate()); popup.setOnMenuItemClickListener(item -> { if (item.getItemId() == R.id.reload_menu_id) { mBrowser.getActiveTab().getNavigationController().reload(); @@ -205,12 +213,20 @@ public class WebLayerShellActivity extends FragmentActivity { } if (item.getItemId() == R.id.site_settings_menu_id) { - Intent intent = - SiteSettingsActivity.createIntentForCategoryList(this, PROFILE_NAME); + // TODO(crbug.com/1083233): Figure out the right long-term behavior here. + if (mInIncognitoMode) return true; + + Intent intent = SiteSettingsActivity.createIntentForCategoryList( + this, NON_INCOGNITO_PROFILE_NAME); IntentUtils.safeStartActivity(this, intent); return true; } + if (item.getItemId() == R.id.translate_menu_id) { + mBrowser.getActiveTab().showTranslateUi(); + return true; + } + return false; }); popup.show(); @@ -254,6 +270,7 @@ public class WebLayerShellActivity extends FragmentActivity { fragment.setRetainInstance(true); mBrowser = Browser.fromFragment(fragment); mProfile = mBrowser.getProfile(); + mProfile.setBooleanSetting(SettingType.UKM_ENABLED, true); setTabCallbacks(mBrowser.getActiveTab(), fragment); mBrowser.setTopView(mTopContentsContainer); @@ -287,7 +304,7 @@ public class WebLayerShellActivity extends FragmentActivity { return; } String startupUrl = getUrlFromIntent(getIntent()); - if (TextUtils.isEmpty(startupUrl)) { + if (TextUtils.isEmpty(startupUrl) || !URLUtil.isValidUrl(startupUrl)) { startupUrl = "https://google.com"; } loadUrl(startupUrl); @@ -380,10 +397,10 @@ public class WebLayerShellActivity extends FragmentActivity { public void bringTabToFront() { tab.getBrowser().setActiveTab(tab); - Context context = WebLayerShellActivity.this; - Intent intent = new Intent(context, WebLayerShellActivity.class); + Activity activity = WebLayerShellActivity.this; + Intent intent = new Intent(activity, WebLayerShellActivity.class); intent.setAction(Intent.ACTION_MAIN); - context.getApplicationContext().startActivity(intent); + activity.startActivity(intent); } }); tab.getNavigationController().registerNavigationCallback(new NavigationCallback() { @@ -427,7 +444,14 @@ public class WebLayerShellActivity extends FragmentActivity { } } - Fragment fragment = WebLayer.createBrowserFragment(PROFILE_NAME); + if (CommandLine.isInitialized() + && CommandLine.getInstance().hasSwitch("start-in-incognito")) { + mInIncognitoMode = true; + } + + String profileName = mInIncognitoMode ? null : NON_INCOGNITO_PROFILE_NAME; + + Fragment fragment = WebLayer.createBrowserFragment(profileName); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.add(mMainViewId, fragment); diff --git a/chromium/weblayer/shell/app/shell_main_params.cc b/chromium/weblayer/shell/app/shell_main_params.cc index 36e58d734ae..9ece1e23cda 100644 --- a/chromium/weblayer/shell/app/shell_main_params.cc +++ b/chromium/weblayer/shell/app/shell_main_params.cc @@ -49,29 +49,45 @@ GURL GetStartupURL() { class MainDelegateImpl : public MainDelegate { public: void PreMainMessageLoopRun() override { + // On Android the Profile is created and owned in Java via an + // embedder-specific call to WebLayer.createBrowserFragment(). +#if !defined(OS_ANDROID) InitializeProfile(); +#endif Shell::Initialize(); +#if defined(OS_ANDROID) + Shell::CreateNewWindow(GetStartupURL(), gfx::Size()); +#else Shell::CreateNewWindow(profile_.get(), GetStartupURL(), gfx::Size()); +#endif } - void PostMainMessageLoopRun() override { DestroyProfile(); } + void PostMainMessageLoopRun() override { +#if !defined(OS_ANDROID) + DestroyProfile(); +#endif + } void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) override { Shell::SetMainMessageLoopQuitClosure(std::move(quit_closure)); } private: +#if !defined(OS_ANDROID) void InitializeProfile() { - profile_ = Profile::Create("web_shell"); + auto* command_line = base::CommandLine::ForCurrentProcess(); + std::string profile_name = + command_line->HasSwitch(switches::kStartInIncognito) ? "" : "web_shell"; - // TODO: create an incognito profile as well. + profile_ = Profile::Create(profile_name); } void DestroyProfile() { profile_.reset(); } std::unique_ptr<Profile> profile_; +#endif }; } // namespace diff --git a/chromium/weblayer/shell/browser/shell.cc b/chromium/weblayer/shell/browser/shell.cc index 5f3c69dad3f..58adffab13d 100644 --- a/chromium/weblayer/shell/browser/shell.cc +++ b/chromium/weblayer/shell/browser/shell.cc @@ -16,6 +16,8 @@ #include "base/strings/string_util.h" #include "build/build_config.h" #include "url/gurl.h" +#include "weblayer/browser/browser_impl.h" +#include "weblayer/browser/browser_list.h" #include "weblayer/browser/profile_impl.h" #include "weblayer/browser/tab_impl.h" #include "weblayer/public/navigation_controller.h" @@ -30,26 +32,26 @@ const int kDefaultTestWindowHeightDip = 700; std::vector<Shell*> Shell::windows_; -Shell::Shell(std::unique_ptr<Tab> tab) - : tab_(std::move(tab)), window_(nullptr) { +Shell::Shell(std::unique_ptr<Browser> browser) + : browser_(std::move(browser)), window_(nullptr) { windows_.push_back(this); - if (tab_) { - tab_->AddObserver(this); - tab_->GetNavigationController()->AddObserver(this); + if (tab()) { + tab()->AddObserver(this); + tab()->GetNavigationController()->AddObserver(this); #if !defined(OS_ANDROID) // Android does this in Java. // TODO: how will tests work with this on android? can we get to the // concrete type? - static_cast<TabImpl*>(tab_.get())->profile()->SetDownloadDelegate(this); + static_cast<TabImpl*>(tab())->profile()->SetDownloadDelegate(this); #endif } } Shell::~Shell() { - if (tab_) { - tab_->GetNavigationController()->RemoveObserver(this); - tab_->RemoveObserver(this); + if (tab()) { + tab()->GetNavigationController()->RemoveObserver(this); + tab()->RemoveObserver(this); } PlatformCleanUp(); @@ -63,17 +65,19 @@ Shell::~Shell() { // Always destroy WebContents before calling PlatformExit(). WebContents // destruction sequence may depend on the resources destroyed in // PlatformExit() (e.g. the display::Screen singleton). - tab_.reset(); + browser_.reset(); if (windows_.empty()) { + PlatformExit(); + if (*g_quit_main_message_loop) std::move(*g_quit_main_message_loop).Run(); } } -Shell* Shell::CreateShell(std::unique_ptr<Tab> tab, +Shell* Shell::CreateShell(std::unique_ptr<Browser> browser, const gfx::Size& initial_size) { - Shell* shell = new Shell(std::move(tab)); + Shell* shell = new Shell(std::move(browser)); shell->PlatformCreateWindow(initial_size.width(), initial_size.height()); shell->PlatformSetContents(); @@ -90,13 +94,6 @@ void Shell::CloseAllWindows() { // Pump the message loop to allow window teardown tasks to run. base::RunLoop().RunUntilIdle(); - - // If there were no windows open then the message loop quit closure will - // not have been run. - if (*g_quit_main_message_loop) - std::move(*g_quit_main_message_loop).Run(); - - PlatformExit(); } void Shell::SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) { @@ -104,11 +101,21 @@ void Shell::SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) { } Tab* Shell::tab() { + if (!browser()) + return nullptr; + CHECK(!browser()->GetTabs().empty()); + return browser()->GetTabs()[0]; +} + +Browser* Shell::browser() { #if defined(OS_ANDROID) // TODO(jam): this won't work if we need more than one Shell in a test. - return Tab::GetLastTabForTesting(); + const auto& browsers = BrowserList::GetInstance()->browsers(); + if (browsers.empty()) + return nullptr; + return *(browsers.begin()); #else - return tab_.get(); + return browser_.get(); #endif } @@ -121,7 +128,8 @@ void Shell::DisplayedUrlChanged(const GURL& url) { } void Shell::LoadStateChanged(bool is_loading, bool to_different_document) { - NavigationController* navigation_controller = tab_->GetNavigationController(); + NavigationController* navigation_controller = + tab()->GetNavigationController(); PlatformEnableUIControl(STOP_BUTTON, is_loading && to_different_document); @@ -158,16 +166,26 @@ gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) { return GetShellDefaultSize(); } +#if defined(OS_ANDROID) +Shell* Shell::CreateNewWindow(const GURL& url, const gfx::Size& initial_size) { + // On Android, the browser is owned by the Java side. + return CreateNewWindowWithBrowser(nullptr, url, initial_size); +} +#else Shell* Shell::CreateNewWindow(Profile* web_profile, const GURL& url, const gfx::Size& initial_size) { -#if defined(OS_ANDROID) - std::unique_ptr<Tab> tab; -#else - auto tab = Tab::Create(web_profile); + auto browser = Browser::Create(web_profile, nullptr); + browser->CreateTab(); + return CreateNewWindowWithBrowser(std::move(browser), url, initial_size); +} #endif - Shell* shell = CreateShell(std::move(tab), AdjustWindowSize(initial_size)); +Shell* Shell::CreateNewWindowWithBrowser(std::unique_ptr<Browser> browser, + const GURL& url, + const gfx::Size& initial_size) { + Shell* shell = + CreateShell(std::move(browser), AdjustWindowSize(initial_size)); if (!url.is_empty()) shell->LoadURL(url); return shell; diff --git a/chromium/weblayer/shell/browser/shell.h b/chromium/weblayer/shell/browser/shell.h index 78f48accb9f..5664d767ba3 100644 --- a/chromium/weblayer/shell/browser/shell.h +++ b/chromium/weblayer/shell/browser/shell.h @@ -35,6 +35,7 @@ class WMState; class GURL; namespace weblayer { +class Browser; class Profile; class Tab; @@ -56,9 +57,13 @@ class Shell : public TabObserver, // Do one time initialization at application startup. static void Initialize(); +#if defined(OS_ANDROID) + static Shell* CreateNewWindow(const GURL& url, const gfx::Size& initial_size); +#else static Shell* CreateNewWindow(Profile* web_profile, const GURL& url, const gfx::Size& initial_size); +#endif // Returns the currently open windows. static std::vector<Shell*>& windows() { return windows_; } @@ -72,6 +77,7 @@ class Shell : public TabObserver, static void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure); Tab* tab(); + Browser* browser(); gfx::NativeWindow window() { return window_; } @@ -80,7 +86,11 @@ class Shell : public TabObserver, private: enum UIControl { BACK_BUTTON, FORWARD_BUTTON, STOP_BUTTON }; - explicit Shell(std::unique_ptr<Tab> tab); + static Shell* CreateNewWindowWithBrowser(std::unique_ptr<Browser> browser, + const GURL& url, + const gfx::Size& initial_size); + + explicit Shell(std::unique_ptr<Browser> browser); // TabObserver implementation: void DisplayedUrlChanged(const GURL& url) override; @@ -102,7 +112,7 @@ class Shell : public TabObserver, AllowDownloadCallback callback) override; // Helper to create a new Shell. - static Shell* CreateShell(std::unique_ptr<Tab> tab, + static Shell* CreateShell(std::unique_ptr<Browser> browser, const gfx::Size& initial_size); // Helper for one time initialization of application @@ -141,7 +151,7 @@ class Shell : public TabObserver, // Set the title of shell window void PlatformSetTitle(const base::string16& title); - std::unique_ptr<Tab> tab_; + std::unique_ptr<Browser> browser_; gfx::NativeWindow window_; diff --git a/chromium/weblayer/shell/browser/shell_views.cc b/chromium/weblayer/shell/browser/shell_views.cc index cc442c555b1..ed799835e8f 100644 --- a/chromium/weblayer/shell/browser/shell_views.cc +++ b/chromium/weblayer/shell/browser/shell_views.cc @@ -6,6 +6,8 @@ #include <stddef.h> +#include <memory> + #include "base/command_line.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" @@ -52,7 +54,10 @@ class ShellWindowDelegateView : public views::WidgetDelegateView, public: enum UIControl { BACK_BUTTON, FORWARD_BUTTON, STOP_BUTTON }; - ShellWindowDelegateView(Shell* shell) : shell_(shell) {} + explicit ShellWindowDelegateView(Shell* shell) : shell_(shell) { + SetHasWindowSizeControls(true); + InitShellWindow(); + } ~ShellWindowDelegateView() override {} @@ -192,11 +197,11 @@ class ShellWindowDelegateView : public views::WidgetDelegateView, } layout->AddPaddingRow(0, 5); - - InitAccelerators(); } void InitAccelerators() { + // This function must be called when part of the widget hierarchy. + DCHECK(GetWidget()); static const ui::KeyboardCode keys[] = {ui::VKEY_F5, ui::VKEY_BROWSER_BACK, ui::VKEY_BROWSER_FORWARD}; for (size_t i = 0; i < base::size(keys); ++i) { @@ -239,16 +244,7 @@ class ShellWindowDelegateView : public views::WidgetDelegateView, } // Overridden from WidgetDelegateView - bool CanResize() const override { return true; } - bool CanMaximize() const override { return true; } - bool CanMinimize() const override { return true; } base::string16 GetWindowTitle() const override { return title_; } - void WindowClosing() override { - if (shell_) { - delete shell_; - shell_ = nullptr; - } - } // Overridden from View gfx::Size GetMinimumSize() const override { @@ -256,12 +252,7 @@ class ShellWindowDelegateView : public views::WidgetDelegateView, // (preferred) size. return gfx::Size(); } - void ViewHierarchyChanged( - const views::ViewHierarchyChangedDetails& details) override { - if (details.is_add && details.child == this) { - InitShellWindow(); - } - } + void AddedToWidget() override { InitAccelerators(); } // Overridden from AcceleratorTarget: bool AcceleratorPressed(const ui::Accelerator& accelerator) override { @@ -281,8 +272,7 @@ class ShellWindowDelegateView : public views::WidgetDelegateView, } private: - // Hold a reference of Shell for deleting it when the window is closing - Shell* shell_; + std::unique_ptr<Shell> shell_; // Window title base::string16 title_; @@ -382,7 +372,7 @@ void Shell::PlatformSetContents() { views::WidgetDelegate* widget_delegate = window_widget_->widget_delegate(); ShellWindowDelegateView* delegate_view = static_cast<ShellWindowDelegateView*>(widget_delegate); - delegate_view->AttachTab(tab_.get(), content_size_); + delegate_view->AttachTab(tab(), content_size_); window_->GetHost()->Show(); window_widget_->Show(); } diff --git a/chromium/weblayer/shell/common/shell_switches.cc b/chromium/weblayer/shell/common/shell_switches.cc index e70106da503..fa058d07acf 100644 --- a/chromium/weblayer/shell/common/shell_switches.cc +++ b/chromium/weblayer/shell/common/shell_switches.cc @@ -10,5 +10,8 @@ namespace switches { // Stops new Shell objects from navigating to a default url. const char kNoInitialNavigation[] = "no-initial-navigation"; +// Starts the shell with the profile in incognito mode. +const char kStartInIncognito[] = "start-in-incognito"; + } // namespace switches } // namespace weblayer diff --git a/chromium/weblayer/shell/common/shell_switches.h b/chromium/weblayer/shell/common/shell_switches.h index 3219f68433b..dfbb5b0e7df 100644 --- a/chromium/weblayer/shell/common/shell_switches.h +++ b/chromium/weblayer/shell/common/shell_switches.h @@ -10,6 +10,8 @@ namespace switches { extern const char kNoInitialNavigation[]; +extern const char kStartInIncognito[]; + } // namespace switches } // namespace weblayer |