summaryrefslogtreecommitdiff
path: root/chromium/weblayer/browser/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/weblayer/browser/java/org')
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java53
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java13
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java82
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java6
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java10
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/CookieManagerImpl.java11
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java8
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java1
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/MojoInterfaceRegistrar.java15
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java38
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java10
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java7
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java165
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java59
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java47
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java88
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/WebMessageReplyProxyImpl.java16
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ActionModeItemType.java17
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl3
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowserClient.aidl4
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IContextMenuParams.aidl11
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl3
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl4
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfileClient.aidl2
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl7
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITabClient.aidl10
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl7
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl8
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/LoadError.java5
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/RemoteMediaServiceConstants.java16
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/UrlBarOptionsKeys.java5
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java2
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouteDialogFragmentImpl.java11
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouterClientImpl.java112
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionManager.java59
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionNotificationHelper.java55
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/OWNERS5
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestFactory.java112
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java57
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl19
40 files changed, 960 insertions, 203 deletions
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java
index 6b1103e7324..4927ae672df 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java
@@ -7,31 +7,68 @@ package org.chromium.weblayer_private;
import android.app.SearchManager;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.os.RemoteException;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
+import androidx.annotation.Nullable;
+
import org.chromium.base.PackageManagerUtils;
import org.chromium.content_public.browser.ActionModeCallbackHelper;
import org.chromium.content_public.browser.SelectionPopupController;
import org.chromium.content_public.browser.WebContents;
+import org.chromium.weblayer_private.interfaces.APICallException;
+import org.chromium.weblayer_private.interfaces.ActionModeItemType;
+import org.chromium.weblayer_private.interfaces.ITabClient;
+import org.chromium.weblayer_private.interfaces.ObjectWrapper;
/**
* A class that handles selection action mode for WebLayer.
*/
public final class ActionModeCallback implements ActionMode.Callback {
private final ActionModeCallbackHelper mHelper;
+ // Can be null during init.
+ private @Nullable ITabClient mTabClient;
+
+ // Bitfield of @ActionModeItemType values.
+ private int mActionModeOverride;
+
+ // Convert from content ActionModeCallbackHelper.MENU_ITEM_* values to
+ // @ActionModeItemType values.
+ private static int contentToWebLayerType(int contentType) {
+ switch (contentType) {
+ case ActionModeCallbackHelper.MENU_ITEM_SHARE:
+ return ActionModeItemType.SHARE;
+ case ActionModeCallbackHelper.MENU_ITEM_WEB_SEARCH:
+ return ActionModeItemType.WEB_SEARCH;
+ case ActionModeCallbackHelper.MENU_ITEM_PROCESS_TEXT:
+ case 0:
+ return 0;
+ default:
+ assert false;
+ return 0;
+ }
+ }
public ActionModeCallback(WebContents webContents) {
mHelper =
SelectionPopupController.fromWebContents(webContents).getActionModeCallbackHelper();
}
+ public void setTabClient(ITabClient tabClient) {
+ mTabClient = tabClient;
+ }
+
+ public void setOverride(int actionModeItemTypes) {
+ mActionModeOverride = actionModeItemTypes;
+ }
+
@Override
public final boolean onCreateActionMode(ActionMode mode, Menu menu) {
int allowedActionModes = ActionModeCallbackHelper.MENU_ITEM_PROCESS_TEXT
| ActionModeCallbackHelper.MENU_ITEM_SHARE;
- if (isWebSearchAvailable()) {
+ if ((mActionModeOverride & ActionModeItemType.WEB_SEARCH) != 0 || isWebSearchAvailable()) {
allowedActionModes |= ActionModeCallbackHelper.MENU_ITEM_WEB_SEARCH;
}
mHelper.setAllowedMenuItems(allowedActionModes);
@@ -53,7 +90,19 @@ public final class ActionModeCallback implements ActionMode.Callback {
@Override
public final boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- return mHelper.onActionItemClicked(mode, item);
+ int menuItemType = contentToWebLayerType(mHelper.getAllowedMenuItemIfAny(mode, item));
+ if ((menuItemType & mActionModeOverride) == 0) {
+ return mHelper.onActionItemClicked(mode, item);
+ }
+ assert WebLayerFactoryImpl.getClientMajorVersion() >= 88;
+ try {
+ mTabClient.onActionItemClicked(
+ menuItemType, ObjectWrapper.wrap(mHelper.getSelectedText()));
+ } catch (RemoteException e) {
+ throw new APICallException(e);
+ }
+ mode.finish();
+ return true;
}
@Override
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java
index f842c3a3c6e..131769baba0 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserControlsContainerView.java
@@ -161,6 +161,11 @@ class BrowserControlsContainerView extends FrameLayout {
* Requests that the browser controls visibility state be changed.
*/
void setAnimationConstraint(@BrowserControlsState int constraint);
+
+ /**
+ * Called when the offset of the controls changes.
+ */
+ void onOffsetsChanged(boolean isTop, int controlsOffset);
}
BrowserControlsContainerView(Context context, ContentViewRenderView contentViewRenderView,
@@ -371,7 +376,12 @@ class BrowserControlsContainerView extends FrameLayout {
mLastHeight = height;
if (mLastWidth > 0 && mLastHeight > 0 && mViewResourceAdapter == null) {
createAdapterAndLayer();
- if (mLastShownAmountWithView == DEFAULT_LAST_SHOWN_AMOUNT && mSavedState != null) {
+ if (mIsFullscreen) {
+ // This calls setControlsOffset() as onOffsetsChanged() does (mostly) nothing when
+ // fullscreen.
+ setControlsOffset(mIsTop ? -mLastHeight : mLastHeight, 0);
+ } else if (mLastShownAmountWithView == DEFAULT_LAST_SHOWN_AMOUNT
+ && mSavedState != null) {
// If there wasn't a View before and we have non-empty saved state from a previous
// BrowserControlsContainerView instance, apply those saved offsets now. We can't
// rely on BrowserControlsOffsetManager to notify us of the correct location as we
@@ -498,6 +508,7 @@ class BrowserControlsContainerView extends FrameLayout {
BrowserControlsContainerViewJni.get().setBottomControlsOffset(
mNativeBrowserControlsContainerView);
}
+ mDelegate.onOffsetsChanged(mIsTop, mControlsOffset);
}
private void reportHeightChange() {
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
index 689b89e8df8..534373f07d3 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
@@ -71,12 +71,20 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
private final UrlBarControllerImpl mUrlBarController;
private boolean mFragmentStarted;
private boolean mFragmentResumed;
- private boolean mFragmentStoppedForConfigurationChange;
+
+ // Tracks whether the fragment is in the middle of a configuration change and was attached when
+ // the configuration change started. This is set to true in onFragmentStop() and false when
+ // isViewAttachedToWindow() is true in either onViewAttachedToWindow() or onFragmentStarted().
+ // It's important to only set this to false when isViewAttachedToWindow() is true, as otherwise
+ // the WebContents may be prematurely hidden.
+ private boolean mInConfigurationChangeAndWasAttached;
+
// Cache the value instead of querying system every time.
private Boolean mPasswordEchoEnabled;
private Boolean mDarkThemeEnabled;
private Float mFontScale;
private boolean mViewAttachedToWindow;
+ private boolean mNotifyOnBrowserControlsOffsetsChanged;
// Created in the constructor from saved state and used in setClient().
private PersistenceInfo mPersistenceInfo;
@@ -156,7 +164,7 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
mWindowAndroid = windowAndroid;
mEmbedderActivityContext = embedderAppContext;
mViewController = new BrowserViewController(
- windowAndroid, this, mViewControllerState, mFragmentStoppedForConfigurationChange);
+ windowAndroid, this, mViewControllerState, mInConfigurationChangeAndWasAttached);
mLocaleReceiver = new LocaleChangedBroadcastReceiver(windowAndroid.getContext().get());
mPasswordEchoEnabled = null;
}
@@ -231,8 +239,10 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
@Override
public TabImpl createTab() {
- TabImpl tab = new TabImpl(mProfile, mWindowAndroid);
- addTab(tab);
+ TabImpl tab = new TabImpl(this, mProfile, mWindowAndroid);
+ // This needs |alwaysAdd| set to true as the Tab is created with the Browser already set to
+ // this.
+ addTab(tab, /* alwaysAdd */ true);
return tab;
}
@@ -282,14 +292,17 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
@Override
public void addTab(ITab iTab) {
StrictModeWorkaround.apply();
- TabImpl tab = (TabImpl) iTab;
- if (tab.getBrowser() == this) return;
+ addTab((TabImpl) iTab, /* alwaysAdd */ false);
+ }
+
+ private void addTab(TabImpl tab, boolean alwaysAdd) {
+ if (!alwaysAdd && tab.getBrowser() == this) return;
BrowserImplJni.get().addTab(mNativeBrowser, tab.getNativeTab());
}
@CalledByNative
private void createJavaTabForNativeTab(long nativeTab) {
- new TabImpl(mProfile, mWindowAndroid, nativeTab);
+ new TabImpl(this, mProfile, mWindowAndroid, nativeTab);
}
private void checkPreferences() {
@@ -356,36 +369,23 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
}
@CalledByNative
- private void onTabAdded(TabImpl tab) {
+ private void onTabAdded(TabImpl tab) throws RemoteException {
tab.attachToBrowser(this);
- try {
- if (mClient != null) mClient.onTabAdded(tab);
- } catch (RemoteException e) {
- throw new APICallException(e);
- }
+ if (mClient != null) mClient.onTabAdded(tab);
}
@CalledByNative
- private void onActiveTabChanged(TabImpl tab) {
+ private void onActiveTabChanged(TabImpl tab) throws RemoteException {
if (mViewController != null) mViewController.setActiveTab(tab);
- if (mInDestroy) return;
- try {
- if (mClient != null) {
- mClient.onActiveTabChanged(tab != null ? tab.getId() : 0);
- }
- } catch (RemoteException e) {
- throw new APICallException(e);
+ if (!mInDestroy && mClient != null) {
+ mClient.onActiveTabChanged(tab != null ? tab.getId() : 0);
}
}
@CalledByNative
- private void onTabRemoved(TabImpl tab) {
+ private void onTabRemoved(TabImpl tab) throws RemoteException {
if (mInDestroy) return;
- try {
- if (mClient != null) mClient.onTabRemoved(tab.getId());
- } catch (RemoteException e) {
- throw new APICallException(e);
- }
+ if (mClient != null) mClient.onTabRemoved(tab.getId());
// This doesn't reset state on TabImpl as |browser| is either about to be
// destroyed, or switching to a different fragment.
}
@@ -471,6 +471,21 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
}
@Override
+ public void setBrowserControlsOffsetsEnabled(boolean enable) {
+ mNotifyOnBrowserControlsOffsetsChanged = enable;
+ }
+
+ public void onBrowserControlsOffsetsChanged(TabImpl tab, boolean isTop, int controlsOffset) {
+ if (mNotifyOnBrowserControlsOffsetsChanged && tab == getActiveTab()) {
+ try {
+ mClient.onBrowserControlsOffsetsChanged(isTop, controlsOffset);
+ } catch (RemoteException e) {
+ throw new APICallException(e);
+ }
+ }
+ }
+
+ @Override
public boolean isRestoringPreviousState() {
return BrowserImplJni.get().isRestoringPreviousState(mNativeBrowser);
}
@@ -504,15 +519,17 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
}
public void onFragmentStart() {
- mFragmentStoppedForConfigurationChange = false;
mFragmentStarted = true;
+ if (mViewAttachedToWindow) {
+ mInConfigurationChangeAndWasAttached = false;
+ }
BrowserImplJni.get().onFragmentStart(mNativeBrowser);
updateAllTabs();
checkPreferences();
}
public void onFragmentStop(boolean forConfigurationChange) {
- mFragmentStoppedForConfigurationChange = forConfigurationChange;
+ mInConfigurationChangeAndWasAttached = forConfigurationChange;
mFragmentStarted = false;
updateAllTabs();
}
@@ -536,8 +553,8 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
return mFragmentResumed;
}
- public boolean isFragmentStoppedForConfigurationChange() {
- return mFragmentStoppedForConfigurationChange;
+ public boolean isInConfigurationChangeAndWasAttached() {
+ return mInConfigurationChangeAndWasAttached;
}
public boolean isViewAttachedToWindow() {
@@ -547,6 +564,9 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
@Override
public void onViewAttachedToWindow(View v) {
mViewAttachedToWindow = true;
+ if (mFragmentStarted) {
+ mInConfigurationChangeAndWasAttached = false;
+ }
updateAllTabsViewAttachedState();
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
index fd9628bb755..013a665589a 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
@@ -270,6 +270,12 @@ public final class BrowserViewController
}
@Override
+ public void onOffsetsChanged(boolean isTop, int controlsOffset) {
+ if (mTab == null) return;
+ mTab.getBrowser().onBrowserControlsOffsetsChanged(mTab, isTop, controlsOffset);
+ }
+
+ @Override
public void onGestureStateChanged() {
// This is called from |mGestureStateTracker|.
assert mGestureStateTracker != null;
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
index 983632cae0d..2619d519d0f 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java
@@ -24,6 +24,7 @@ import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
@@ -677,7 +678,7 @@ public class ContentViewRenderView
ContentViewRenderViewJni.get().init(ContentViewRenderView.this, rootWindow);
assert mNativeContentViewRenderView != 0;
mWindowAndroid = rootWindow;
- requestMode(mode, (Boolean result) -> {});
+ requestMode(mode, null);
mDisplayAndroidObserver = new DisplayAndroid.DisplayAndroidObserver() {
@Override
public void onRotationChanged(int rotation) {
@@ -689,10 +690,9 @@ public class ContentViewRenderView
updateBackgroundColor();
}
- public void requestMode(@Mode int mode, ValueCallback<Boolean> callback) {
+ public void requestMode(@Mode int mode, @Nullable ValueCallback<Boolean> callback) {
boolean allowSurfaceControl = !mSelectionHandlesActive;
assert mode == MODE_SURFACE_VIEW || mode == MODE_TEXTURE_VIEW;
- assert callback != null;
if (mRequested != null
&& (mRequested.getMode() != mode
|| mRequested.getAllowSurfaceControl() != allowSurfaceControl)) {
@@ -710,7 +710,7 @@ public class ContentViewRenderView
listener.setRequestData(mRequested);
}
assert mRequested.getMode() == mode;
- mRequested.addCallback(callback);
+ if (callback != null) mRequested.addCallback(callback);
}
/**
@@ -805,7 +805,7 @@ public class ContentViewRenderView
// requestMode will take into account the updated |mSelectionHandlesActive|
// and respond appropriately, even if mode is the same.
- requestMode(mCurrent.getMode(), (Boolean result) -> {});
+ requestMode(mCurrent.getMode(), null);
}
public InsetObserverView getInsetObserverView() {
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/CookieManagerImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/CookieManagerImpl.java
index e2c56ccc4d6..ba3e80a7566 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/CookieManagerImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/CookieManagerImpl.java
@@ -11,7 +11,6 @@ import org.chromium.base.Callback;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
-import org.chromium.weblayer_private.interfaces.APICallException;
import org.chromium.weblayer_private.interfaces.CookieChangeCause;
import org.chromium.weblayer_private.interfaces.ICookieChangedCallbackClient;
import org.chromium.weblayer_private.interfaces.ICookieManager;
@@ -73,13 +72,9 @@ public final class CookieManagerImpl extends ICookieManager.Stub {
}
@CalledByNative
- private static void onCookieChange(
- ICookieChangedCallbackClient callback, String cookie, int cause) {
- try {
- callback.onCookieChanged(cookie, mojoCauseToJavaType(cause));
- } catch (RemoteException e) {
- throw new APICallException(e);
- }
+ private static void onCookieChange(ICookieChangedCallbackClient callback, String cookie,
+ int cause) throws RemoteException {
+ callback.onCookieChanged(cookie, mojoCauseToJavaType(cause));
}
@CookieChangeCause
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java
index 244b369f07a..4fc1c2f39dd 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java
@@ -82,6 +82,14 @@ public final class CrashReporterControllerImpl extends ICrashReporterController.
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
TraceEvent.instant(TAG, "CrashReporterController: Begin uploading crash");
File minidumpFile = getCrashFileManager().getCrashFileWithLocalId(localId);
+ if (minidumpFile == null) {
+ try {
+ mClient.onCrashUploadFailed(localId, "invalid crash id");
+ } catch (RemoteException e) {
+ throw new AndroidRuntimeException(e);
+ }
+ return;
+ }
MinidumpUploader.Result result = new MinidumpUploader().upload(minidumpFile);
if (result.isSuccess()) {
CrashFileManager.markUploadSuccess(minidumpFile);
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java
index 3c74a6dcd1b..219560ada96 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FaviconCallbackProxy.java
@@ -53,6 +53,7 @@ public final class FaviconCallbackProxy extends IFaviconFetcher.Stub {
@CalledByNative
private void onFaviconChanged(Bitmap bitmap) throws RemoteException {
+ mTab.onFaviconChanged(bitmap);
mClient.onFaviconChanged(bitmap);
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/MojoInterfaceRegistrar.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/MojoInterfaceRegistrar.java
index d124792cd0d..ec49f06da6e 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/MojoInterfaceRegistrar.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/MojoInterfaceRegistrar.java
@@ -6,8 +6,11 @@ package org.chromium.weblayer_private;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.content_public.browser.InterfaceRegistrar;
+import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.content_public.browser.WebContents;
+import org.chromium.payments.mojom.PaymentRequest;
import org.chromium.services.service_manager.InterfaceRegistry;
+import org.chromium.weblayer_private.payments.WebLayerPaymentRequestFactory;
import org.chromium.webshare.mojom.ShareService;
/**
@@ -17,6 +20,8 @@ class MojoInterfaceRegistrar {
@CalledByNative
private static void registerMojoInterfaces() {
InterfaceRegistrar.Registry.addWebContentsRegistrar(new WebContentsInterfaceRegistrar());
+ InterfaceRegistrar.Registry.addRenderFrameHostRegistrar(
+ new RenderFrameHostInterfaceRegistrar());
}
private static class WebContentsInterfaceRegistrar implements InterfaceRegistrar<WebContents> {
@@ -25,4 +30,14 @@ class MojoInterfaceRegistrar {
registry.addInterface(ShareService.MANAGER, new WebShareServiceFactory(webContents));
}
}
+
+ private static class RenderFrameHostInterfaceRegistrar
+ implements InterfaceRegistrar<RenderFrameHost> {
+ @Override
+ public void registerInterfaces(
+ InterfaceRegistry registry, final RenderFrameHost renderFrameHost) {
+ registry.addInterface(
+ PaymentRequest.MANAGER, new WebLayerPaymentRequestFactory(renderFrameHost));
+ }
+ }
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
index 3151068451c..0436c92162e 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
@@ -5,8 +5,10 @@
package org.chromium.weblayer_private;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.webkit.WebResourceResponse;
+import org.chromium.base.TimeUtilsJni;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
@@ -28,6 +30,10 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
private long mNativeNavigationController;
private INavigationControllerClient mNavigationControllerClient;
+ // Conversion between native TimeTicks and SystemClock.uptimeMillis().
+ private long mNativeTickOffsetUs;
+ private boolean mNativeTickOffsetUsComputed;
+
public NavigationControllerImpl(TabImpl tab, INavigationControllerClient client) {
mTab = tab;
mNavigationControllerClient = client;
@@ -215,11 +221,43 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
}
@CalledByNative
+ private void onFirstContentfulPaint2(
+ long navigationStartTick, long firstContentfulPaintDurationMs) throws RemoteException {
+ if (WebLayerFactoryImpl.getClientMajorVersion() < 88) return;
+
+ mNavigationControllerClient.onFirstContentfulPaint2(
+ (navigationStartTick - getNativeTickOffsetUs()) / 1000,
+ firstContentfulPaintDurationMs);
+ }
+
+ @CalledByNative
+ private void onLargestContentfulPaint(long navigationStartTick,
+ long largestContentfulPaintDurationMs) throws RemoteException {
+ if (WebLayerFactoryImpl.getClientMajorVersion() < 88) return;
+
+ mNavigationControllerClient.onLargestContentfulPaint(
+ (navigationStartTick - getNativeTickOffsetUs()) / 1000,
+ largestContentfulPaintDurationMs);
+ }
+
+ @CalledByNative
private void onOldPageNoLongerRendered(String uri) throws RemoteException {
if (WebLayerFactoryImpl.getClientMajorVersion() < 85) return;
mNavigationControllerClient.onOldPageNoLongerRendered(uri);
}
+ private long getNativeTickOffsetUs() {
+ // See logic in CustomTabsConnection.java that this was based on.
+ if (!mNativeTickOffsetUsComputed) {
+ // Compute offset from time ticks to uptimeMillis.
+ mNativeTickOffsetUsComputed = true;
+ long nativeNowUs = TimeUtilsJni.get().getTimeTicksNowUs();
+ long javaNowUs = SystemClock.uptimeMillis() * 1000;
+ mNativeTickOffsetUs = nativeNowUs - javaNowUs;
+ }
+ return mNativeTickOffsetUs;
+ }
+
private static final class NavigateParamsImpl extends INavigateParams.Stub {
private boolean mReplaceCurrentEntry;
private boolean mIntentProcessingDisabled;
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
index 7815edb19f1..1430e36d1d4 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
@@ -161,6 +161,13 @@ public final class NavigationImpl extends INavigation.Stub {
return NavigationImplJni.get().isReload(mNativeNavigationImpl);
}
+ @Override
+ public void disableNetworkErrorAutoReload() {
+ if (!NavigationImplJni.get().disableNetworkErrorAutoReload(mNativeNavigationImpl)) {
+ throw new IllegalStateException();
+ }
+ }
+
private void throwIfNativeDestroyed() {
if (mNativeNavigationImpl == 0) {
throw new IllegalStateException("Using Navigation after native destroyed");
@@ -182,6 +189,8 @@ public final class NavigationImpl extends INavigation.Stub {
return LoadError.CONNECTIVITY_ERROR;
case ImplLoadError.OTHER_ERROR:
return LoadError.OTHER_ERROR;
+ case ImplLoadError.SAFE_BROWSING_ERROR:
+ return LoadError.SAFE_BROWSING_ERROR;
default:
throw new IllegalArgumentException("Unexpected load error " + loadError);
}
@@ -211,5 +220,6 @@ public final class NavigationImpl extends INavigation.Stub {
boolean setUserAgentString(long nativeNavigationImpl, String value);
boolean isPageInitiated(long nativeNavigationImpl);
boolean isReload(long nativeNavigationImpl);
+ boolean disableNetworkErrorAutoReload(long nativeNavigationImpl);
}
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
index 0979cab4c25..0bd9d7b7e58 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
@@ -12,6 +12,7 @@ import android.graphics.drawable.Drawable;
import android.webkit.ValueCallback;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import org.chromium.base.Callback;
import org.chromium.base.StrictModeContext;
@@ -127,6 +128,12 @@ public class PageInfoControllerDelegateImpl extends PageInfoControllerDelegate {
}));
}
+ @Override
+ @Nullable
+ public Drawable getPreviewUiIcon() {
+ return null;
+ }
+
private static boolean isHttpOrHttps(GURL url) {
String scheme = url.getScheme();
return UrlConstants.HTTP_SCHEME.equals(scheme) || UrlConstants.HTTPS_SCHEME.equals(scheme);
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
index 96d559d7931..1fc0f36e619 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
@@ -4,7 +4,9 @@
package org.chromium.weblayer_private;
+import android.Manifest.permission;
import android.app.Activity;
+import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.os.Build;
@@ -19,6 +21,7 @@ import android.view.ViewStructure;
import android.view.autofill.AutofillValue;
import android.webkit.ValueCallback;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -34,6 +37,7 @@ import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate
import org.chromium.components.browser_ui.util.ComposedBrowserControlsVisibilityDelegate;
import org.chromium.components.browser_ui.widget.InsetObserverView;
import org.chromium.components.embedder_support.contextmenu.ContextMenuParams;
+import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.components.external_intents.InterceptNavigationDelegateImpl;
import org.chromium.components.find_in_page.FindInPageBridge;
import org.chromium.components.find_in_page.FindMatchRectsDetails;
@@ -55,6 +59,7 @@ import org.chromium.ui.base.ViewAndroidDelegate;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.url.GURL;
import org.chromium.weblayer_private.interfaces.APICallException;
+import org.chromium.weblayer_private.interfaces.IContextMenuParams;
import org.chromium.weblayer_private.interfaces.IDownloadCallbackClient;
import org.chromium.weblayer_private.interfaces.IErrorPageCallbackClient;
import org.chromium.weblayer_private.interfaces.IFaviconFetcher;
@@ -100,9 +105,8 @@ public final class TabImpl extends ITab.Stub {
private FullscreenCallbackProxy mFullscreenCallbackProxy;
private TabViewAndroidDelegate mViewAndroidDelegate;
private GoogleAccountsCallbackProxy mGoogleAccountsCallbackProxy;
- // BrowserImpl this TabImpl is in. This is null before attached to a Browser. While this is null
- // before attached, there are code paths that may trigger calling methods before set.
- @Nullable
+ // BrowserImpl this TabImpl is in.
+ @NonNull
private BrowserImpl mBrowser;
/**
* The AutofillProvider that integrates with system-level autofill. This is null until
@@ -138,6 +142,7 @@ public final class TabImpl extends ITab.Stub {
private DisplayCutoutController mDisplayCutoutController;
private boolean mPostContainerViewInitDone;
+ private ActionModeCallback mActionModeCallback;
private WebLayerAccessibilityUtil.Observer mAccessibilityObserver;
@@ -236,7 +241,8 @@ public final class TabImpl extends ITab.Stub {
return sTabMap.get(tabId);
}
- public TabImpl(ProfileImpl profile, WindowAndroid windowAndroid) {
+ public TabImpl(BrowserImpl browser, ProfileImpl profile, WindowAndroid windowAndroid) {
+ mBrowser = browser;
mId = ++sNextId;
init(profile, windowAndroid, TabImplJni.get().createTab(profile.getNativeProfile(), this));
}
@@ -245,8 +251,10 @@ public final class TabImpl extends ITab.Stub {
* This constructor is called when the native side triggers creation of a TabImpl
* (as happens with popups and other scenarios).
*/
- public TabImpl(ProfileImpl profile, WindowAndroid windowAndroid, long nativeTab) {
+ public TabImpl(
+ BrowserImpl browser, ProfileImpl profile, WindowAndroid windowAndroid, long nativeTab) {
mId = ++sNextId;
+ mBrowser = browser;
TabImplJni.get().setJavaImpl(nativeTab, TabImpl.this);
init(profile, windowAndroid, nativeTab);
}
@@ -308,7 +316,7 @@ public final class TabImpl extends ITab.Stub {
// before installing this observer.
if (WebLayerFactoryImpl.getClientMajorVersion() >= 85) {
mMediaSessionHelper = new MediaSessionHelper(
- mWebContents, MediaSessionManager.createMediaSessionHelperDelegate(mId));
+ mWebContents, MediaSessionManager.createMediaSessionHelperDelegate(this));
}
}
@@ -318,7 +326,8 @@ public final class TabImpl extends ITab.Stub {
mPostContainerViewInitDone = true;
SelectionPopupController controller =
SelectionPopupController.fromWebContents(mWebContents);
- controller.setActionModeCallback(new ActionModeCallback(mWebContents));
+ mActionModeCallback = new ActionModeCallback(mWebContents);
+ controller.setActionModeCallback(mActionModeCallback);
controller.setSelectionClient(SelectionClient.createSmartSelectionClient(mWebContents));
}
@@ -334,6 +343,9 @@ public final class TabImpl extends ITab.Stub {
* Sets the BrowserImpl this TabImpl is contained in.
*/
public void attachToBrowser(BrowserImpl browser) {
+ // NOTE: during tab creation this is called with |mBrowser| set to |browser|. This happens
+ // because the tab is created with |mBrowser| already set (to avoid having a bunch of null
+ // checks).
mBrowser = browser;
updateFromBrowser();
}
@@ -417,7 +429,6 @@ public final class TabImpl extends ITab.Stub {
public void onAttachedToViewController(
long topControlsContainerViewHandle, long bottomControlsContainerViewHandle) {
// attachToFragment() must be called before activate().
- assert mBrowser != null;
TabImplJni.get().setBrowserControlsContainerViews(
mNativeTab, topControlsContainerViewHandle, bottomControlsContainerViewHandle);
mInfoBarContainer.onTabAttachedToViewController();
@@ -454,7 +465,7 @@ public final class TabImpl extends ITab.Stub {
public boolean isVisible() {
return isActiveTab()
&& ((mBrowser.isStarted() && mBrowser.isViewAttachedToWindow())
- || mBrowser.isFragmentStoppedForConfigurationChange());
+ || mBrowser.isInConfigurationChangeAndWasAttached());
}
@CalledByNative
@@ -469,7 +480,7 @@ public final class TabImpl extends ITab.Stub {
}
public boolean isActiveTab() {
- return mBrowser != null && mBrowser.getActiveTab() == this;
+ return mBrowser.getActiveTab() == this;
}
private void updateWebContentsVisibility() {
@@ -529,6 +540,7 @@ public final class TabImpl extends ITab.Stub {
StrictModeWorkaround.apply();
mClient = client;
mTabCallbackProxy = new TabCallbackProxy(mNativeTab, client);
+ mActionModeCallback.setTabClient(mClient);
}
@Override
@@ -596,11 +608,13 @@ public final class TabImpl extends ITab.Stub {
@Override
public void setTranslateTargetLanguage(String targetLanguage) {
+ StrictModeWorkaround.apply();
TabImplJni.get().setTranslateTargetLanguage(mNativeTab, targetLanguage);
}
@Override
public void setScrollOffsetsEnabled(boolean enabled) {
+ StrictModeWorkaround.apply();
if (enabled) {
if (mGestureStateListenerWithScroll == null) {
mGestureStateListenerWithScroll = new GestureStateListenerWithScroll() {
@@ -624,6 +638,49 @@ public final class TabImpl extends ITab.Stub {
}
}
+ @Override
+ public void setFloatingActionModeOverride(int actionModeItemTypes) {
+ StrictModeWorkaround.apply();
+ mActionModeCallback.setOverride(actionModeItemTypes);
+ }
+
+ @Override
+ public void setDesktopUserAgentEnabled(boolean enable) {
+ StrictModeWorkaround.apply();
+ TabImplJni.get().setDesktopUserAgentEnabled(mNativeTab, enable);
+ }
+
+ @Override
+ public boolean isDesktopUserAgentEnabled() {
+ StrictModeWorkaround.apply();
+ return TabImplJni.get().isDesktopUserAgentEnabled(mNativeTab);
+ }
+
+ @Override
+ public void download(IContextMenuParams contextMenuParams) {
+ StrictModeWorkaround.apply();
+ NativeContextMenuParamsHolder nativeContextMenuParamsHolder =
+ (NativeContextMenuParamsHolder) contextMenuParams;
+
+ WindowAndroid window = getBrowser().getWindowAndroid();
+ if (window.hasPermission(permission.WRITE_EXTERNAL_STORAGE)) {
+ continueDownload(nativeContextMenuParamsHolder);
+ return;
+ }
+
+ String[] requestPermissions = new String[] {permission.WRITE_EXTERNAL_STORAGE};
+ window.requestPermissions(requestPermissions, (permissions, grantResults) -> {
+ if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ continueDownload(nativeContextMenuParamsHolder);
+ }
+ });
+ }
+
+ private void continueDownload(NativeContextMenuParamsHolder nativeContextMenuParamsHolder) {
+ TabImplJni.get().download(
+ mNativeTab, nativeContextMenuParamsHolder.mNativeContextMenuParams);
+ }
+
public void removeFaviconCallbackProxy(FaviconCallbackProxy proxy) {
mFaviconCallbackProxies.remove(proxy);
}
@@ -809,16 +866,12 @@ public final class TabImpl extends ITab.Stub {
}
@CalledByNative
- private void onFindResultAvailable(
- int numberOfMatches, int activeMatchOrdinal, boolean finalUpdate) {
- try {
- if (mFindInPageCallbackClient != null) {
- // The WebLayer API deals in indices instead of ordinals.
- mFindInPageCallbackClient.onFindResult(
- numberOfMatches, activeMatchOrdinal - 1, finalUpdate);
- }
- } catch (RemoteException e) {
- throw new AndroidRuntimeException(e);
+ private void onFindResultAvailable(int numberOfMatches, int activeMatchOrdinal,
+ boolean finalUpdate) throws RemoteException {
+ if (mFindInPageCallbackClient != null) {
+ // The WebLayer API deals in indices instead of ordinals.
+ mFindInPageCallbackClient.onFindResult(
+ numberOfMatches, activeMatchOrdinal - 1, finalUpdate);
}
if (mFindResultBar != null) {
@@ -947,6 +1000,11 @@ public final class TabImpl extends ITab.Stub {
mMediaStreamManager.destroy();
mMediaStreamManager = null;
+ if (mMediaSessionHelper != null) {
+ mMediaSessionHelper.destroy();
+ mMediaSessionHelper = null;
+ }
+
// Destroying FaviconCallbackProxy removes from mFaviconCallbackProxies. Copy to avoid
// problems.
Set<FaviconCallbackProxy> faviconCallbackProxies = mFaviconCallbackProxies;
@@ -1015,14 +1073,56 @@ public final class TabImpl extends ITab.Stub {
return TextUtils.isEmpty(s) ? null : s;
}
+ private static class NativeContextMenuParamsHolder extends IContextMenuParams.Stub {
+ // Note: avoid adding more members since an object with a finalizer will delay GC of any
+ // object it references.
+ private final long mNativeContextMenuParams;
+
+ NativeContextMenuParamsHolder(long nativeContextMenuParams) {
+ mNativeContextMenuParams = nativeContextMenuParams;
+ }
+
+ /**
+ * A finalizer is required to ensure that the native object associated with
+ * this object gets destructed, otherwise there would be a memory leak.
+ *
+ * This is safe because it makes a simple call into C++ code that is both
+ * thread-safe and very fast.
+ *
+ * @see java.lang.Object#finalize()
+ */
+ @Override
+ protected final void finalize() throws Throwable {
+ super.finalize();
+ TabImplJni.get().destroyContextMenuParams(mNativeContextMenuParams);
+ }
+ }
+
@CalledByNative
- private void showContextMenu(ContextMenuParams params) throws RemoteException {
+ private void showContextMenu(ContextMenuParams params, long nativeContextMenuParams)
+ throws RemoteException {
if (WebLayerFactoryImpl.getClientMajorVersion() < 82) return;
- mClient.showContextMenu(ObjectWrapper.wrap(params.getPageUrl()),
+ if (WebLayerFactoryImpl.getClientMajorVersion() < 88) {
+ mClient.showContextMenu(ObjectWrapper.wrap(params.getPageUrl()),
+ ObjectWrapper.wrap(nonEmptyOrNull(params.getLinkUrl())),
+ ObjectWrapper.wrap(nonEmptyOrNull(params.getLinkText())),
+ ObjectWrapper.wrap(nonEmptyOrNull(params.getTitleText())),
+ ObjectWrapper.wrap(nonEmptyOrNull(params.getSrcUrl())));
+ return;
+ }
+
+ boolean canDownload =
+ (params.isImage() && UrlUtilities.isDownloadableScheme(params.getSrcUrl()))
+ || (params.isVideo() && UrlUtilities.isDownloadableScheme(params.getSrcUrl())
+ && params.canSaveMedia())
+ || (params.isAnchor() && UrlUtilities.isDownloadableScheme(params.getLinkUrl()));
+ mClient.showContextMenu2(ObjectWrapper.wrap(params.getPageUrl()),
ObjectWrapper.wrap(nonEmptyOrNull(params.getLinkUrl())),
ObjectWrapper.wrap(nonEmptyOrNull(params.getLinkText())),
ObjectWrapper.wrap(nonEmptyOrNull(params.getTitleText())),
- ObjectWrapper.wrap(nonEmptyOrNull(params.getSrcUrl())));
+ ObjectWrapper.wrap(nonEmptyOrNull(params.getSrcUrl())), params.isImage(),
+ params.isVideo(), canDownload,
+ new NativeContextMenuParamsHolder(nativeContextMenuParams));
}
@VisibleForTesting
@@ -1037,8 +1137,6 @@ public final class TabImpl extends ITab.Stub {
}
private void onBrowserControlsConstraintUpdated(int constraint) {
- // WARNING: this may be called before attached. This means |mBrowser| may be null.
-
// If something has overridden the FIP's SHOWN constraint, cancel FIP. This causes FIP to
// dismiss when entering fullscreen.
if (constraint != BrowserControlsState.SHOWN) {
@@ -1105,7 +1203,11 @@ public final class TabImpl extends ITab.Stub {
@Nullable
private BrowserViewController getViewController() {
if (!isActiveTab()) return null;
- return mBrowser.getPossiblyNullViewController();
+ // During rotation it's possible for this to be called before BrowserViewController has been
+ // updated. Verify BrowserViewController reflects this is the active tab before returning
+ // it.
+ BrowserViewController viewController = mBrowser.getPossiblyNullViewController();
+ return viewController != null && viewController.getTab() == this ? viewController : null;
}
@VisibleForTesting
@@ -1123,6 +1225,13 @@ public final class TabImpl extends ITab.Stub {
return translateInfoBar.getTargetLanguageForTesting();
}
+ /** Called by {@link FaviconCallbackProxy} when the favicon for the current page has changed. */
+ public void onFaviconChanged(Bitmap bitmap) {
+ if (mMediaSessionHelper != null) {
+ mMediaSessionHelper.updateFavicon(bitmap);
+ }
+ }
+
@NativeMethods
interface Natives {
TabImpl fromWebContents(WebContents webContents);
@@ -1151,5 +1260,9 @@ public final class TabImpl extends ITab.Stub {
boolean canTranslate(long nativeTabImpl);
void showTranslateUi(long nativeTabImpl);
void setTranslateTargetLanguage(long nativeTabImpl, String targetLanguage);
+ void setDesktopUserAgentEnabled(long nativeTabImpl, boolean enable);
+ boolean isDesktopUserAgentEnabled(long nativeTabImpl);
+ void download(long nativeTabImpl, long nativeContextMenuParams);
+ void destroyContextMenuParams(long contextMenuParams);
}
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
index a2d2212ee72..937ba551330 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
@@ -21,6 +21,7 @@ import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.infobar.ActionType;
+import org.chromium.chrome.browser.infobar.InfobarEvent;
import org.chromium.components.infobars.InfoBar;
import org.chromium.components.infobars.InfoBarCompactLayout;
import org.chromium.components.translate.TranslateMenu;
@@ -76,38 +77,6 @@ public class TranslateCompactInfoBar extends InfoBar
private static final String INFOBAR_HISTOGRAM_TRANSLATION_COUNT =
"Translate.CompactInfobar.TranslationsPerPage";
- /**
- * This is used to back a UMA histogram, so it should be treated as
- * append-only. The values should not be changed or reused, and
- * INFOBAR_HISTOGRAM_BOUNDARY should be the last.
- */
- private static final int INFOBAR_IMPRESSION = 0;
- private static final int INFOBAR_TARGET_TAB_TRANSLATE = 1;
- private static final int INFOBAR_DECLINE = 2;
- private static final int INFOBAR_OPTIONS = 3;
- private static final int INFOBAR_MORE_LANGUAGES = 4;
- private static final int INFOBAR_MORE_LANGUAGES_TRANSLATE = 5;
- private static final int INFOBAR_PAGE_NOT_IN = 6;
- private static final int INFOBAR_ALWAYS_TRANSLATE = 7;
- private static final int INFOBAR_NEVER_TRANSLATE = 8;
- private static final int INFOBAR_NEVER_TRANSLATE_SITE = 9;
- private static final int INFOBAR_SCROLL_HIDE = 10;
- private static final int INFOBAR_SCROLL_SHOW = 11;
- private static final int INFOBAR_REVERT = 12;
- private static final int INFOBAR_SNACKBAR_ALWAYS_TRANSLATE_IMPRESSION = 13;
- private static final int INFOBAR_SNACKBAR_NEVER_TRANSLATE_IMPRESSION = 14;
- private static final int INFOBAR_SNACKBAR_NEVER_TRANSLATE_SITE_IMPRESSION = 15;
- private static final int INFOBAR_SNACKBAR_CANCEL_ALWAYS = 16;
- private static final int INFOBAR_SNACKBAR_CANCEL_NEVER_SITE = 17;
- private static final int INFOBAR_SNACKBAR_CANCEL_NEVER = 18;
- private static final int INFOBAR_ALWAYS_TRANSLATE_UNDO = 19;
- private static final int INFOBAR_CLOSE_DEPRECATED = 20;
- private static final int INFOBAR_SNACKBAR_AUTO_ALWAYS_IMPRESSION = 21;
- private static final int INFOBAR_SNACKBAR_AUTO_NEVER_IMPRESSION = 22;
- private static final int INFOBAR_SNACKBAR_CANCEL_AUTO_ALWAYS = 23;
- private static final int INFOBAR_SNACKBAR_CANCEL_AUTO_NEVER = 24;
- private static final int INFOBAR_HISTOGRAM_BOUNDARY = 25;
-
// Need 2 instances of TranslateMenuHelper to prevent a race condition bug which happens when
// showing language menu after dismissing overflow menu.
private TranslateMenuHelper mOverflowMenuHelper;
@@ -124,7 +93,7 @@ public class TranslateCompactInfoBar extends InfoBar
private static InfoBar create(TabImpl tab, int initialStep, String sourceLanguageCode,
String targetLanguageCode, boolean alwaysTranslate, boolean triggeredFromMenu,
String[] languages, String[] languageCodes, int[] hashCodes, int tabTextColor) {
- recordInfobarAction(INFOBAR_IMPRESSION);
+ recordInfobarAction(InfobarEvent.INFOBAR_IMPRESSION);
return new TranslateCompactInfoBar(initialStep, sourceLanguageCode, targetLanguageCode,
alwaysTranslate, triggeredFromMenu, languages, languageCodes, hashCodes,
tabTextColor);
@@ -217,7 +186,7 @@ public class TranslateCompactInfoBar extends InfoBar
@Override
public void onClick(View v) {
mTabLayout.endScrollingAnimationIfPlaying();
- recordInfobarAction(INFOBAR_OPTIONS);
+ recordInfobarAction(InfobarEvent.INFOBAR_OPTIONS);
initMenuHelper(TranslateMenu.MENU_OVERFLOW);
mOverflowMenuHelper.show(TranslateMenu.MENU_OVERFLOW, getParentWidth());
mMenuExpanded = true;
@@ -298,7 +267,7 @@ public class TranslateCompactInfoBar extends InfoBar
if (isDismissed()) return;
if (!mUserInteracted) {
- recordInfobarAction(INFOBAR_DECLINE);
+ recordInfobarAction(InfobarEvent.INFOBAR_DECLINE);
}
// NOTE: In Chrome there is a check for whether auto "never translate" should be triggered
@@ -322,11 +291,11 @@ public class TranslateCompactInfoBar extends InfoBar
switch (tab.getPosition()) {
case SOURCE_TAB_INDEX:
incrementAndRecordTranslationsPerPageCount();
- recordInfobarAction(INFOBAR_REVERT);
+ recordInfobarAction(InfobarEvent.INFOBAR_REVERT);
onButtonClicked(ActionType.TRANSLATE_SHOW_ORIGINAL);
return;
case TARGET_TAB_INDEX:
- recordInfobarAction(INFOBAR_TARGET_TAB_TRANSLATE);
+ recordInfobarAction(InfobarEvent.INFOBAR_TARGET_TAB_TRANSLATE);
recordInfobarLanguageData(
INFOBAR_HISTOGRAM_TRANSLATE_LANGUAGE, mOptions.targetLanguageCode());
startTranslating(TARGET_TAB_INDEX);
@@ -346,34 +315,34 @@ public class TranslateCompactInfoBar extends InfoBar
public void onOverflowMenuItemClicked(int itemId) {
switch (itemId) {
case TranslateMenu.ID_OVERFLOW_MORE_LANGUAGE:
- recordInfobarAction(INFOBAR_MORE_LANGUAGES);
+ recordInfobarAction(InfobarEvent.INFOBAR_MORE_LANGUAGES);
initMenuHelper(TranslateMenu.MENU_TARGET_LANGUAGE);
mLanguageMenuHelper.show(TranslateMenu.MENU_TARGET_LANGUAGE, getParentWidth());
return;
case TranslateMenu.ID_OVERFLOW_ALWAYS_TRANSLATE:
// Only show snackbar when "Always Translate" is enabled.
if (!mOptions.getTranslateState(TranslateOptions.Type.ALWAYS_LANGUAGE)) {
- recordInfobarAction(INFOBAR_ALWAYS_TRANSLATE);
+ recordInfobarAction(InfobarEvent.INFOBAR_ALWAYS_TRANSLATE);
recordInfobarLanguageData(INFOBAR_HISTOGRAM_ALWAYS_TRANSLATE_LANGUAGE,
mOptions.sourceLanguageCode());
createAndShowSnackbar(ACTION_OVERFLOW_ALWAYS_TRANSLATE);
} else {
- recordInfobarAction(INFOBAR_ALWAYS_TRANSLATE_UNDO);
+ recordInfobarAction(InfobarEvent.INFOBAR_ALWAYS_TRANSLATE_UNDO);
handleTranslateOptionPostSnackbar(ACTION_OVERFLOW_ALWAYS_TRANSLATE);
}
return;
case TranslateMenu.ID_OVERFLOW_NEVER_LANGUAGE:
- recordInfobarAction(INFOBAR_NEVER_TRANSLATE);
+ recordInfobarAction(InfobarEvent.INFOBAR_NEVER_TRANSLATE);
recordInfobarLanguageData(
INFOBAR_HISTOGRAM_NEVER_TRANSLATE_LANGUAGE, mOptions.sourceLanguageCode());
createAndShowSnackbar(ACTION_OVERFLOW_NEVER_LANGUAGE);
return;
case TranslateMenu.ID_OVERFLOW_NEVER_SITE:
- recordInfobarAction(INFOBAR_NEVER_TRANSLATE_SITE);
+ recordInfobarAction(InfobarEvent.INFOBAR_NEVER_TRANSLATE_SITE);
createAndShowSnackbar(ACTION_OVERFLOW_NEVER_SITE);
return;
case TranslateMenu.ID_OVERFLOW_NOT_THIS_LANGUAGE:
- recordInfobarAction(INFOBAR_PAGE_NOT_IN);
+ recordInfobarAction(InfobarEvent.INFOBAR_PAGE_NOT_IN);
initMenuHelper(TranslateMenu.MENU_SOURCE_LANGUAGE);
mLanguageMenuHelper.show(TranslateMenu.MENU_SOURCE_LANGUAGE, getParentWidth());
return;
@@ -386,7 +355,7 @@ public class TranslateCompactInfoBar extends InfoBar
public void onTargetMenuItemClicked(String code) {
// Reset target code in both UI and native.
if (mNativeTranslateInfoBarPtr != 0 && mOptions.setTargetLanguage(code)) {
- recordInfobarAction(INFOBAR_MORE_LANGUAGES_TRANSLATE);
+ recordInfobarAction(InfobarEvent.INFOBAR_MORE_LANGUAGES_TRANSLATE);
recordInfobarLanguageData(
INFOBAR_HISTOGRAM_MORE_LANGUAGES_LANGUAGE, mOptions.targetLanguageCode());
TranslateCompactInfoBarJni.get().applyStringTranslateOption(mNativeTranslateInfoBarPtr,
@@ -536,7 +505,7 @@ public class TranslateCompactInfoBar extends InfoBar
private static void recordInfobarAction(int action) {
RecordHistogram.recordEnumeratedHistogram(
- INFOBAR_HISTOGRAM, action, INFOBAR_HISTOGRAM_BOUNDARY);
+ INFOBAR_HISTOGRAM, action, InfobarEvent.INFOBAR_HISTOGRAM_BOUNDARY);
}
private void recordInfobarLanguageData(String histogram, String langCode) {
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
index 41e100e1b47..3c500e2a3f2 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
@@ -8,6 +8,7 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.os.Bundle;
+import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
@@ -29,10 +30,12 @@ import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.components.content_settings.ContentSettingsType;
import org.chromium.components.embedder_support.util.Origin;
+import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.components.omnibox.SecurityButtonAnimationDelegate;
import org.chromium.components.omnibox.SecurityStatusIcon;
import org.chromium.components.page_info.PageInfoController;
import org.chromium.components.page_info.PermissionParamsListBuilderDelegate;
+import org.chromium.components.security_state.ConnectionSecurityLevel;
import org.chromium.content_public.browser.WebContents;
import org.chromium.weblayer_private.interfaces.IObjectWrapper;
import org.chromium.weblayer_private.interfaces.IUrlBarController;
@@ -114,6 +117,7 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
private final UrlBarControllerImpl mController;
private float mTextSize;
private boolean mShowPageInfoWhenUrlTextClicked;
+ private boolean mShowPublisherUrl;
// These refer to the resources in the embedder's APK, not WebLayer's.
private @ColorRes int mUrlTextColor;
@@ -136,6 +140,8 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
mTextSize = options.getFloat(UrlBarOptionsKeys.URL_TEXT_SIZE, DEFAULT_TEXT_SIZE);
mShowPageInfoWhenUrlTextClicked = options.getBoolean(
UrlBarOptionsKeys.SHOW_PAGE_INFO_WHEN_URL_TEXT_CLICKED, /*default= */ false);
+ mShowPublisherUrl =
+ options.getBoolean(UrlBarOptionsKeys.SHOW_PUBLISHER_URL, /*default= */ false);
mUrlTextColor = options.getInt(UrlBarOptionsKeys.URL_TEXT_COLOR, /*default= */ 0);
mUrlIconColor = options.getInt(UrlBarOptionsKeys.URL_ICON_COLOR, /*default= */ 0);
@@ -179,8 +185,24 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
private void updateView() {
if (mBrowserImpl == null) return;
- String displayUrl =
- UrlBarControllerImplJni.get().getUrlForDisplay(mNativeUrlBarController);
+ int securityLevel = UrlBarControllerImplJni.get().getConnectionSecurityLevel(
+ mNativeUrlBarController);
+
+ String publisherUrl =
+ UrlBarControllerImplJni.get().getPublisherUrl(mNativeUrlBarController);
+
+ String displayUrl;
+ int securityIcon;
+ if (mShowPublisherUrl && securityLevel != ConnectionSecurityLevel.DANGEROUS
+ && !TextUtils.isEmpty(publisherUrl)) {
+ displayUrl = getContext().getResources().getString(R.string.amp_publisher_url,
+ UrlUtilities.extractPublisherFromPublisherUrl(publisherUrl));
+ securityIcon = R.drawable.amp_icon;
+ } else {
+ displayUrl = getUrlForDisplay();
+ securityIcon = getSecurityIcon();
+ }
+
mUrlTextView.setText(displayUrl);
mUrlTextView.setTextSize(
TypedValue.COMPLEX_UNIT_SP, Math.max(MINIMUM_TEXT_SIZE, mTextSize));
@@ -189,11 +211,9 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
mUrlTextView.setTextColor(ContextCompat.getColor(embedderContext, mUrlTextColor));
}
- mSecurityButtonAnimationDelegate.updateSecurityButton(getSecurityIcon());
+ mSecurityButtonAnimationDelegate.updateSecurityButton(securityIcon);
mSecurityButton.setContentDescription(getContext().getResources().getString(
- SecurityStatusIcon.getSecurityIconContentDescriptionResourceId(
- UrlBarControllerImplJni.get().getConnectionSecurityLevel(
- mNativeUrlBarController))));
+ SecurityStatusIcon.getSecurityIconContentDescriptionResourceId(securityLevel)));
if (mUrlIconColor != 0 && embedderContext != null) {
ImageViewCompat.setImageTintList(mSecurityButton,
@@ -225,9 +245,19 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
private void showPageInfoUi(View v) {
WebContents webContents = mBrowserImpl.getActiveTab().getWebContents();
+
+ String publisherUrl = null;
+ if (mShowPublisherUrl) {
+ String publisherUrlMaybeNull =
+ UrlBarControllerImplJni.get().getPublisherUrl(mNativeUrlBarController);
+ if (publisherUrlMaybeNull != null && !TextUtils.isEmpty(publisherUrlMaybeNull)) {
+ publisherUrl =
+ UrlUtilities.extractPublisherFromPublisherUrl(publisherUrlMaybeNull);
+ }
+ }
+
PageInfoController.show(mBrowserImpl.getWindowAndroid().getActivity().get(),
- webContents,
- /* contentPublisher= */ null, PageInfoController.OpenedFromSource.TOOLBAR,
+ webContents, publisherUrl, PageInfoController.OpenedFromSource.TOOLBAR,
PageInfoControllerDelegateImpl.create(webContents),
new PermissionParamsListBuilderDelegate(mBrowserImpl.getProfile()) {
@Override
@@ -260,6 +290,7 @@ public class UrlBarControllerImpl extends IUrlBarController.Stub {
long createUrlBarController(long browserPtr);
void deleteUrlBarController(long urlBarControllerImplPtr);
String getUrlForDisplay(long nativeUrlBarControllerImpl);
+ String getPublisherUrl(long nativeUrlBarControllerImpl);
int getConnectionSecurityLevel(long nativeUrlBarControllerImpl);
boolean shouldShowDangerTriangleForWarningLevel(long nativeUrlBarControllerImpl);
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
index 29f8b0a1626..b15c1a39df8 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
@@ -42,9 +42,9 @@ import org.chromium.base.TraceEvent;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
-import org.chromium.base.compat.ApiHelperForO;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.metrics.RecordHistogram;
import org.chromium.components.browser_ui.contacts_picker.ContactsPickerDialog;
import org.chromium.components.browser_ui.photo_picker.DecoderServiceHost;
import org.chromium.components.browser_ui.photo_picker.ImageDecoder;
@@ -78,6 +78,7 @@ import org.chromium.weblayer_private.interfaces.IWebLayerClient;
import org.chromium.weblayer_private.interfaces.ObjectWrapper;
import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
import org.chromium.weblayer_private.media.MediaRouteDialogFragmentImpl;
+import org.chromium.weblayer_private.media.MediaRouterClientImpl;
import org.chromium.weblayer_private.media.MediaSessionManager;
import org.chromium.weblayer_private.media.MediaStreamManager;
import org.chromium.weblayer_private.metrics.MetricsServiceClient;
@@ -117,7 +118,7 @@ public final class WebLayerImpl extends IWebLayer.Stub {
// The required package ID for WebLayer when loaded as a shared library, hardcoded in the
// resources. If this value changes make sure to change _SHARED_LIBRARY_HARDCODED_ID in
// //build/android/gyp/util/protoresources.py.
- private static final int REQUIRED_PACKAGE_IDENTIFIER = 12;
+ private static final int REQUIRED_PACKAGE_IDENTIFIER = 36;
private final ProfileManager mProfileManager = new ProfileManager();
@@ -217,7 +218,6 @@ public final class WebLayerImpl extends IWebLayer.Stub {
notifyWebViewRunningInProcess(remoteContext.getClassLoader());
}
- remoteContext = processRemoteContext(remoteContext);
Context appContext = minimalInitForContext(
ObjectWrapper.unwrap(appContextWrapper, Context.class), remoteContext);
PackageInfo packageInfo = WebViewFactory.getLoadedPackageInfo();
@@ -379,7 +379,7 @@ public final class WebLayerImpl extends IWebLayer.Stub {
StrictModeWorkaround.apply();
// This is a no-op if init has already happened.
minimalInitForContext(ObjectWrapper.unwrap(appContext, Context.class),
- processRemoteContext(ObjectWrapper.unwrap(remoteContext, Context.class)));
+ ObjectWrapper.unwrap(remoteContext, Context.class));
return CrashReporterControllerImpl.getInstance();
}
@@ -411,13 +411,26 @@ public final class WebLayerImpl extends IWebLayer.Stub {
}
@Override
+ public void onRemoteMediaServiceStarted(IObjectWrapper sessionService, Intent intent) {
+ StrictModeWorkaround.apply();
+ MediaRouterClientImpl.serviceStarted(
+ ObjectWrapper.unwrap(sessionService, Service.class), intent);
+ }
+
+ @Override
+ public void onRemoteMediaServiceDestroyed(int id) {
+ StrictModeWorkaround.apply();
+ MediaRouterClientImpl.serviceDestroyed(id);
+ }
+
+ @Override
public IBinder initializeImageDecoder(IObjectWrapper appContext, IObjectWrapper remoteContext) {
StrictModeWorkaround.apply();
assert ContextUtils.getApplicationContext() == null;
CommandLine.init(null);
minimalInitForContext(ObjectWrapper.unwrap(appContext, Context.class),
- processRemoteContext(ObjectWrapper.unwrap(remoteContext, Context.class)));
+ ObjectWrapper.unwrap(remoteContext, Context.class));
LibraryLoader.getInstance().setLibraryProcessType(
LibraryProcessType.PROCESS_WEBLAYER_CHILD);
LibraryLoader.getInstance().ensureInitialized();
@@ -439,6 +452,19 @@ public final class WebLayerImpl extends IWebLayer.Stub {
public void setClient(IWebLayerClient client) {
StrictModeWorkaround.apply();
sClient = client;
+
+ if (WebLayerFactoryImpl.getClientMajorVersion() >= 88) {
+ try {
+ RecordHistogram.recordTimesHistogram("WebLayer.Startup.ClassLoaderCreationTime",
+ sClient.getClassLoaderCreationTime());
+ RecordHistogram.recordTimesHistogram(
+ "WebLayer.Startup.ContextCreationTime", sClient.getContextCreationTime());
+ RecordHistogram.recordTimesHistogram("WebLayer.Startup.WebLayerLoaderCreationTime",
+ sClient.getWebLayerLoaderCreationTime());
+ } catch (RemoteException e) {
+ throw new APICallException(e);
+ }
+ }
}
@Override
@@ -506,6 +532,42 @@ public final class WebLayerImpl extends IWebLayer.Stub {
}
}
+ public static Intent createRemoteMediaServiceIntent() {
+ if (sClient == null) {
+ throw new IllegalStateException("WebLayer should have been initialized already.");
+ }
+
+ try {
+ return sClient.createRemoteMediaServiceIntent();
+ } catch (RemoteException e) {
+ throw new APICallException(e);
+ }
+ }
+
+ public static int getPresentationApiNotificationId() {
+ if (sClient == null) {
+ throw new IllegalStateException("WebLayer should have been initialized already.");
+ }
+
+ try {
+ return sClient.getPresentationApiNotificationId();
+ } catch (RemoteException e) {
+ throw new APICallException(e);
+ }
+ }
+
+ public static int getRemotePlaybackApiNotificationId() {
+ if (sClient == null) {
+ throw new IllegalStateException("WebLayer should have been initialized already.");
+ }
+
+ try {
+ return sClient.getRemotePlaybackApiNotificationId();
+ } catch (RemoteException e) {
+ throw new APICallException(e);
+ }
+ }
+
public static String getClientApplicationName() {
Context context = ContextUtils.getApplicationContext();
return new StringBuilder()
@@ -606,6 +668,10 @@ public final class WebLayerImpl extends IWebLayer.Stub {
/** Forces adding entries to the package identifiers array until we hit the required ID. */
private static void forceAddAssetPaths(Context remoteContext, int packageId) {
+ if (packageId > REQUIRED_PACKAGE_IDENTIFIER) {
+ throw new AndroidRuntimeException(
+ "WebLayer package ID too large, aborting: " + packageId);
+ }
try {
Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
String path = remoteContext.getApplicationInfo().sourceDir;
@@ -823,18 +889,6 @@ public final class WebLayerImpl extends IWebLayer.Stub {
}
}
- private static Context processRemoteContext(Context remoteContext) {
- // If WebLayer is in a DFM, make sure the correct resources are used.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- try {
- return ApiHelperForO.createContextForSplit(remoteContext, "weblayer");
- } catch (PackageManager.NameNotFoundException e) {
- // WebLayer is not in a split, the original context will have the resources.
- }
- }
- return remoteContext;
- }
-
private static Context createContextForMode(Context remoteContext, int uiMode) {
Configuration configuration = new Configuration();
configuration.uiMode = uiMode;
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebMessageReplyProxyImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebMessageReplyProxyImpl.java
index d639a42cf3a..980275d0eb3 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebMessageReplyProxyImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebMessageReplyProxyImpl.java
@@ -44,22 +44,14 @@ public final class WebMessageReplyProxyImpl extends IWebMessageReplyProxy.Stub {
}
@CalledByNative
- private void onNativeDestroyed() {
+ private void onNativeDestroyed() throws RemoteException {
mNativeWebMessageReplyProxyImpl = 0;
- try {
- mClient.onReplyProxyDestroyed(mId);
- } catch (RemoteException e) {
- throw new APICallException(e);
- }
+ mClient.onReplyProxyDestroyed(mId);
}
@CalledByNative
- private void onPostMessage(String message) {
- try {
- mClient.onPostMessage(mId, message);
- } catch (RemoteException e) {
- throw new APICallException(e);
- }
+ private void onPostMessage(String message) throws RemoteException {
+ mClient.onPostMessage(mId, message);
}
@Override
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ActionModeItemType.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ActionModeItemType.java
new file mode 100644
index 00000000000..bbce175453d
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ActionModeItemType.java
@@ -0,0 +1,17 @@
+// 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.
+
+package org.chromium.weblayer_private.interfaces;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@IntDef({ActionModeItemType.SHARE, ActionModeItemType.WEB_SEARCH})
+@Retention(RetentionPolicy.SOURCE)
+public @interface ActionModeItemType {
+ int SHARE = 1 << 0;
+ int WEB_SEARCH = 1 << 1;
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl
index 485e4b45769..950df71a49e 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl
@@ -43,4 +43,7 @@ interface IBrowser {
// Added in 87.
boolean isRestoringPreviousState() = 14;
+
+ // Added in 88.
+ void setBrowserControlsOffsetsEnabled(in boolean enable) = 13;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowserClient.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowserClient.aidl
index 6c7eff74173..e7bbb456a83 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowserClient.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowserClient.aidl
@@ -15,4 +15,8 @@ interface IBrowserClient {
// Added in 87.
IRemoteFragment createMediaRouteDialogFragment() = 3;
void onRestoreCompleted() = 5;
+
+ // Added in 88.
+ void onBrowserControlsOffsetsChanged(in boolean isTop,
+ in int controlsOffset) = 4;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IContextMenuParams.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IContextMenuParams.aidl
new file mode 100644
index 00000000000..58baad20468
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IContextMenuParams.aidl
@@ -0,0 +1,11 @@
+// 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.
+
+package org.chromium.weblayer_private.interfaces;
+
+/**
+ * Holds on to the native ContextMenuParams object.
+ */
+interface IContextMenuParams {
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
index 5c94e3418ea..bc05deb6794 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
@@ -33,4 +33,7 @@ interface INavigation {
// @since 86
boolean isPageInitiated() = 11;
boolean isReload() = 12;
+
+ // @since 88
+ void disableNetworkErrorAutoReload() = 17;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl
index 73432f8bd19..0c3fa33d8db 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl
@@ -33,4 +33,8 @@ interface INavigationControllerClient {
// Added in M85.
void onOldPageNoLongerRendered(in String uri) = 9;
+
+ // Added in M88.
+ void onFirstContentfulPaint2(long navigationStartMs, long firstContentfulPaintDurationMs) = 10;
+ void onLargestContentfulPaint(long navigationStartMs, long largestContentfulPaintDurationMs) = 11;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfileClient.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfileClient.aidl
index 50de21109a1..16cb26715b4 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfileClient.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IProfileClient.aidl
@@ -4,7 +4,7 @@
package org.chromium.weblayer_private.interfaces;
-// Added in Version 87.
+// Added in Version 88.
interface IProfileClient {
void onProfileDestroyed() = 0;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
index a2985dbc8d4..03f1d69064e 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITab.aidl
@@ -6,6 +6,7 @@ package org.chromium.weblayer_private.interfaces;
import java.util.List;
+import org.chromium.weblayer_private.interfaces.IContextMenuParams;
import org.chromium.weblayer_private.interfaces.IDownloadCallbackClient;
import org.chromium.weblayer_private.interfaces.IErrorPageCallbackClient;
import org.chromium.weblayer_private.interfaces.IFaviconFetcher;
@@ -75,5 +76,11 @@ interface ITab {
// Added in 87
void setScrollOffsetsEnabled(in boolean enabled) = 26;
+
+ // Added in 88
+ void setFloatingActionModeOverride(in int actionModeItemTypes) = 27;
boolean willAutomaticallyReloadAfterCrash() = 28;
+ void setDesktopUserAgentEnabled(in boolean enable) = 29;
+ boolean isDesktopUserAgentEnabled() = 30;
+ void download(in IContextMenuParams contextMenuParams) = 31;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITabClient.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITabClient.aidl
index 94e02e8c47b..1b8028c83c4 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITabClient.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/ITabClient.aidl
@@ -4,6 +4,7 @@
package org.chromium.weblayer_private.interfaces;
+import org.chromium.weblayer_private.interfaces.IContextMenuParams;
import org.chromium.weblayer_private.interfaces.IObjectWrapper;
/**
@@ -21,6 +22,7 @@ interface ITabClient {
// void onCloseTab() = 3;
// Added in M82.
+ // Deprecated in M88.
void showContextMenu(in IObjectWrapper pageUrl, in IObjectWrapper linkUrl,
in IObjectWrapper linkText, in IObjectWrapper titleOrAltText,
in IObjectWrapper srcUrl) = 4;
@@ -46,4 +48,12 @@ interface ITabClient {
// Added in M87
void onVerticalScrollOffsetChanged(in int offset) = 11;
+
+ // Added in M88
+ void onActionItemClicked(
+ in int actionModeItemType, in IObjectWrapper selectedString) = 12;
+ void showContextMenu2(in IObjectWrapper pageUrl, in IObjectWrapper linkUrl,
+ in IObjectWrapper linkText, in IObjectWrapper titleOrAltText,
+ in IObjectWrapper srcUrl, in boolean isImage, in boolean isVideo, in boolean canDownload,
+ in IContextMenuParams contextMenuParams) = 13;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl
index ae9df666cf0..d1bbc1dc6ba 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayer.aidl
@@ -105,4 +105,11 @@ interface IWebLayer {
IMediaRouteDialogFragment createMediaRouteDialogFragmentImpl(
in IRemoteFragmentClient remoteFragmentClient) = 21;
IProfile getIncognitoProfile(in String profileName) = 24;
+
+ // Added in Version 88.
+ void onRemoteMediaServiceStarted(in IObjectWrapper sessionService, in Intent intent) = 22;
+ void onRemoteMediaServiceDestroyed(int id) = 23;
+
+ // WARNING: when choosing next value make sure you look back for the max, as
+ // merges may mean the last function does not have the max value.
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl
index a26f56deb45..933e8507b57 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl
@@ -13,4 +13,12 @@ interface IWebLayerClient {
// Since Version 86.
Intent createImageDecoderServiceIntent() = 3;
+
+ // Since Version 88.
+ long getClassLoaderCreationTime() = 4;
+ long getContextCreationTime() = 5;
+ long getWebLayerLoaderCreationTime() = 6;
+ Intent createRemoteMediaServiceIntent() = 7;
+ int getPresentationApiNotificationId() = 8;
+ int getRemotePlaybackApiNotificationId() = 9;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/LoadError.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/LoadError.java
index eba5fbf0c51..9a37dfa0061 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/LoadError.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/LoadError.java
@@ -10,7 +10,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@IntDef({LoadError.NO_ERROR, LoadError.HTTP_CLIENT_ERROR, LoadError.HTTP_SERVER_ERROR,
- LoadError.SSL_ERROR, LoadError.CONNECTIVITY_ERROR, LoadError.OTHER_ERROR})
+ LoadError.SSL_ERROR, LoadError.CONNECTIVITY_ERROR, LoadError.OTHER_ERROR,
+ LoadError.SAFE_BROWSING_ERROR})
@Retention(RetentionPolicy.SOURCE)
public @interface LoadError {
int NO_ERROR = 0;
@@ -19,4 +20,6 @@ public @interface LoadError {
int SSL_ERROR = 3;
int CONNECTIVITY_ERROR = 4;
int OTHER_ERROR = 5;
+ // Sent since 88.
+ int SAFE_BROWSING_ERROR = 6;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/RemoteMediaServiceConstants.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/RemoteMediaServiceConstants.java
new file mode 100644
index 00000000000..375e3d8a28f
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/RemoteMediaServiceConstants.java
@@ -0,0 +1,16 @@
+// 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.
+
+package org.chromium.weblayer_private.interfaces;
+
+/** Keys for remote media service intent extras. */
+public interface RemoteMediaServiceConstants {
+ // Used as a key in the client's AndroidManifest.xml to enable remote media playback, i.e.
+ // Presentation API, Remote Playback API, and Media Fling (automatic casting of html5 videos).
+ String FEATURE_ENABLED_KEY = "org.chromium.weblayer.ENABLE_REMOTE_MEDIA";
+
+ // Used internally by WebLayer as a key to the various values of remote media service
+ // notification IDs.
+ String NOTIFICATION_ID_KEY = "REMOTE_MEDIA_SERVICE_NOTIFICATION_ID_KEY";
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/UrlBarOptionsKeys.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/UrlBarOptionsKeys.java
index 40957da4af7..3045944cba1 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/UrlBarOptionsKeys.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/UrlBarOptionsKeys.java
@@ -10,6 +10,11 @@ public interface UrlBarOptionsKeys {
* If true, clicking on the url shows page info. Default is false.
*/
String SHOW_PAGE_INFO_WHEN_URL_TEXT_CLICKED = "ShowPageInfoWhenUrlTextClicked";
+ /**
+ * If true, shows publisher url. Default is false.
+ * @since 88
+ */
+ String SHOW_PUBLISHER_URL = "ShowPublisherUrl";
String URL_ICON_COLOR = "UrlIconColor";
String URL_TEXT_COLOR = "UrlTextColor";
String URL_TEXT_SIZE = "UrlTextSize";
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java
index 3ef535d997e..a76b13c3ba8 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java
@@ -15,5 +15,5 @@ public interface WebLayerVersionConstants {
*
* @see WebLayer#isAvailable()
*/
- int MAX_SKEW = 3;
+ int MAX_SKEW = 4;
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouteDialogFragmentImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouteDialogFragmentImpl.java
index aede72b184c..c3c4a2c34f9 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouteDialogFragmentImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouteDialogFragmentImpl.java
@@ -33,6 +33,7 @@ import org.chromium.weblayer_private.interfaces.IRemoteFragment;
import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient;
import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
/**
@@ -53,6 +54,10 @@ public class MediaRouteDialogFragmentImpl extends RemoteFragmentImpl {
private boolean mStarted;
private FragmentController mFragmentController;
+ // The instance for the currently active dialog, if any. This is a WeakReference to get around
+ // StaticFieldLeak warnings.
+ private static WeakReference<MediaRouteDialogFragmentImpl> sInstanceForTest;
+
/**
* A fake FragmentActivity needed to make the Fragment system happy.
*
@@ -195,6 +200,7 @@ public class MediaRouteDialogFragmentImpl extends RemoteFragmentImpl {
public MediaRouteDialogFragmentImpl(IRemoteFragmentClient remoteFragmentClient) {
super(remoteFragmentClient);
+ sInstanceForTest = new WeakReference<MediaRouteDialogFragmentImpl>(this);
}
@Override
@@ -239,6 +245,7 @@ public class MediaRouteDialogFragmentImpl extends RemoteFragmentImpl {
StrictModeWorkaround.apply();
super.onDestroy();
mFragmentController.dispatchDestroy();
+ sInstanceForTest = null;
}
@Override
@@ -300,4 +307,8 @@ public class MediaRouteDialogFragmentImpl extends RemoteFragmentImpl {
private Context getWebLayerContext() {
return mContext;
}
+
+ public static MediaRouteDialogFragmentImpl getInstanceForTest() {
+ return sInstanceForTest.get();
+ }
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouterClientImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouterClientImpl.java
index 86a596bda08..588aa8d4de6 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouterClientImpl.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaRouterClientImpl.java
@@ -4,23 +4,51 @@
package org.chromium.weblayer_private.media;
+import android.app.Service;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.support.v4.media.session.MediaSessionCompat;
import androidx.fragment.app.FragmentManager;
+import org.chromium.base.ContextUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.components.browser_ui.media.MediaNotificationController;
import org.chromium.components.browser_ui.media.MediaNotificationInfo;
+import org.chromium.components.browser_ui.media.MediaNotificationManager;
+import org.chromium.components.browser_ui.notifications.NotificationWrapper;
+import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder;
import org.chromium.components.media_router.MediaRouterClient;
import org.chromium.content_public.browser.WebContents;
import org.chromium.weblayer_private.IntentUtils;
import org.chromium.weblayer_private.TabImpl;
+import org.chromium.weblayer_private.WebLayerImpl;
+import org.chromium.weblayer_private.interfaces.RemoteMediaServiceConstants;
/** Provides WebLayer-specific behavior for Media Router. */
@JNINamespace("weblayer")
public class MediaRouterClientImpl extends MediaRouterClient {
+ static int sPresentationNotificationId;
+ static int sRemotingNotificationId;
+
private MediaRouterClientImpl() {}
+ public static void serviceStarted(Service service, Intent intent) {
+ int notificationId = intent.getIntExtra(RemoteMediaServiceConstants.NOTIFICATION_ID_KEY, 0);
+ if (notificationId == 0) {
+ throw new RuntimeException("Invalid RemoteMediaService notification id");
+ }
+ MediaSessionNotificationHelper.serviceStarted(service, intent, notificationId);
+ }
+
+ public static void serviceDestroyed(int notificationId) {
+ MediaSessionNotificationHelper.serviceDestroyed(notificationId);
+ }
+
@Override
public int getTabId(WebContents webContents) {
TabImpl tab = TabImpl.fromWebContents(webContents);
@@ -34,7 +62,19 @@ public class MediaRouterClientImpl extends MediaRouterClient {
@Override
public void showNotification(MediaNotificationInfo notificationInfo) {
- // TODO: implement.
+ MediaNotificationManager.show(notificationInfo, () -> {
+ return new MediaRouterNotificationControllerDelegate(notificationInfo.id);
+ });
+ }
+
+ @Override
+ public int getPresentationNotificationId() {
+ return getPresentationNotificationIdFromClient();
+ }
+
+ @Override
+ public int getRemotingNotificationId() {
+ return getRemotingNotificationIdFromClient();
}
@Override
@@ -51,4 +91,74 @@ public class MediaRouterClientImpl extends MediaRouterClient {
MediaRouterClient.setInstance(new MediaRouterClientImpl());
}
+
+ @CalledByNative
+ public static boolean isMediaRouterEnabled() {
+ Context context = ContextUtils.getApplicationContext();
+ try {
+ ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
+ context.getPackageName(), PackageManager.GET_META_DATA);
+ return ai.metaData.getBoolean(RemoteMediaServiceConstants.FEATURE_ENABLED_KEY);
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ private static class MediaRouterNotificationControllerDelegate
+ implements MediaNotificationController.Delegate {
+ // The ID distinguishes between Presentation and Remoting services/notifications.
+ private final int mNotificationId;
+
+ MediaRouterNotificationControllerDelegate(int notificationId) {
+ mNotificationId = notificationId;
+ }
+
+ @Override
+ public Intent createServiceIntent() {
+ return WebLayerImpl.createRemoteMediaServiceIntent().putExtra(
+ RemoteMediaServiceConstants.NOTIFICATION_ID_KEY, mNotificationId);
+ }
+
+ @Override
+ public String getAppName() {
+ return WebLayerImpl.getClientApplicationName();
+ }
+
+ @Override
+ public String getNotificationGroupName() {
+ if (mNotificationId == getPresentationNotificationIdFromClient()) {
+ return "org.chromium.weblayer.PresentationApi";
+ }
+
+ assert mNotificationId == getRemotingNotificationIdFromClient();
+ return "org.chromium.weblayer.RemotePlaybackApi";
+ }
+
+ @Override
+ public NotificationWrapperBuilder createNotificationWrapperBuilder() {
+ return MediaSessionNotificationHelper.createNotificationWrapperBuilder(mNotificationId);
+ }
+
+ @Override
+ public void onMediaSessionUpdated(MediaSessionCompat session) {
+ // TODO(estade): implement.
+ }
+
+ @Override
+ public void logNotificationShown(NotificationWrapper notification) {}
+ }
+
+ private static int getPresentationNotificationIdFromClient() {
+ if (sPresentationNotificationId == 0) {
+ sPresentationNotificationId = WebLayerImpl.getPresentationApiNotificationId();
+ }
+ return sPresentationNotificationId;
+ }
+
+ private static int getRemotingNotificationIdFromClient() {
+ if (sRemotingNotificationId == 0) {
+ sRemotingNotificationId = WebLayerImpl.getRemotePlaybackApiNotificationId();
+ }
+ return sRemotingNotificationId;
+ }
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionManager.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionManager.java
index 3311c77593a..d555a77cf20 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionManager.java
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionManager.java
@@ -12,14 +12,12 @@ import org.chromium.components.browser_ui.media.MediaNotificationController;
import org.chromium.components.browser_ui.media.MediaNotificationInfo;
import org.chromium.components.browser_ui.media.MediaNotificationManager;
import org.chromium.components.browser_ui.media.MediaSessionHelper;
-import org.chromium.components.browser_ui.notifications.ForegroundServiceUtils;
-import org.chromium.components.browser_ui.notifications.NotificationMetadata;
import org.chromium.components.browser_ui.notifications.NotificationWrapper;
import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder;
+import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
import org.chromium.weblayer_private.IntentUtils;
+import org.chromium.weblayer_private.TabImpl;
import org.chromium.weblayer_private.WebLayerImpl;
-import org.chromium.weblayer_private.WebLayerNotificationChannels;
-import org.chromium.weblayer_private.WebLayerNotificationWrapperBuilder;
/**
* A glue class for MediaSession.
@@ -31,43 +29,30 @@ public class MediaSessionManager {
private static int sNotificationId;
public static void serviceStarted(Service service, Intent intent) {
- MediaNotificationController controller = getController();
- if (controller != null && controller.processIntent(service, intent)) return;
-
- // The service has been started with startForegroundService() but the
- // notification hasn't been shown. See similar logic in {@link
- // ChromeMediaNotificationControllerDelegate}.
- MediaNotificationController.finishStartingForegroundServiceOnO(
- service, createNotificationWrapperBuilder().buildNotificationWrapper());
- // Call stopForeground to guarantee Android unset the foreground bit.
- ForegroundServiceUtils.getInstance().stopForeground(
- service, Service.STOP_FOREGROUND_REMOVE);
- service.stopSelf();
+ MediaSessionNotificationHelper.serviceStarted(service, intent, getNotificationId());
}
public static void serviceDestroyed() {
- MediaNotificationController controller = getController();
- if (controller != null) controller.onServiceDestroyed();
- MediaNotificationManager.clear(getNotificationId());
+ MediaSessionNotificationHelper.serviceDestroyed(getNotificationId());
}
- public static MediaSessionHelper.Delegate createMediaSessionHelperDelegate(int tabId) {
+ public static MediaSessionHelper.Delegate createMediaSessionHelperDelegate(TabImpl tab) {
return new MediaSessionHelper.Delegate() {
@Override
public Intent createBringTabToFrontIntent() {
- return IntentUtils.createBringTabToFrontIntent(tabId);
+ return IntentUtils.createBringTabToFrontIntent(tab.getId());
}
@Override
- public boolean fetchLargeFaviconImage() {
- // TODO(crbug.com/1076463): WebLayer doesn't support favicons.
- return false;
+ public BrowserContextHandle getBrowserContextHandle() {
+ return tab.getProfile();
}
@Override
public MediaNotificationInfo.Builder createMediaNotificationInfoBuilder() {
- return new MediaNotificationInfo.Builder().setInstanceId(tabId).setId(
- getNotificationId());
+ return new MediaNotificationInfo.Builder()
+ .setInstanceId(tab.getId())
+ .setId(getNotificationId());
}
@Override
@@ -79,12 +64,13 @@ public class MediaSessionManager {
@Override
public void hideMediaNotification() {
- MediaNotificationManager.hide(tabId, getNotificationId());
+ MediaNotificationManager.hide(tab.getId(), getNotificationId());
}
@Override
public void activateAndroidMediaSession() {
- MediaNotificationManager.activateAndroidMediaSession(tabId, getNotificationId());
+ MediaNotificationManager.activateAndroidMediaSession(
+ tab.getId(), getNotificationId());
}
};
}
@@ -108,7 +94,8 @@ public class MediaSessionManager {
@Override
public NotificationWrapperBuilder createNotificationWrapperBuilder() {
- return MediaSessionManager.createNotificationWrapperBuilder();
+ return MediaSessionNotificationHelper.createNotificationWrapperBuilder(
+ getNotificationId());
}
@Override
@@ -120,22 +107,8 @@ public class MediaSessionManager {
public void logNotificationShown(NotificationWrapper notification) {}
}
- private static NotificationWrapperBuilder createNotificationWrapperBuilder() {
- // Only the null tag will work as expected, because {@link Service#startForeground()} only
- // takes an ID and no tag. If we pass a tag here, then the notification that's used to
- // display a paused state (no foreground service) will not be identified as the same one
- // that's used with the foreground service.
- return WebLayerNotificationWrapperBuilder.create(
- WebLayerNotificationChannels.ChannelId.MEDIA_PLAYBACK,
- new NotificationMetadata(0, null /*notificationTag*/, getNotificationId()));
- }
-
private static int getNotificationId() {
if (sNotificationId == 0) sNotificationId = WebLayerImpl.getMediaSessionNotificationId();
return sNotificationId;
}
-
- private static MediaNotificationController getController() {
- return MediaNotificationManager.getController(getNotificationId());
- }
}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionNotificationHelper.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionNotificationHelper.java
new file mode 100644
index 00000000000..fbd9b5da8b3
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/media/MediaSessionNotificationHelper.java
@@ -0,0 +1,55 @@
+// 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.
+
+package org.chromium.weblayer_private.media;
+
+import android.app.Service;
+import android.content.Intent;
+
+import org.chromium.components.browser_ui.media.MediaNotificationController;
+import org.chromium.components.browser_ui.media.MediaNotificationManager;
+import org.chromium.components.browser_ui.notifications.ForegroundServiceUtils;
+import org.chromium.components.browser_ui.notifications.NotificationMetadata;
+import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder;
+import org.chromium.weblayer_private.WebLayerNotificationChannels;
+import org.chromium.weblayer_private.WebLayerNotificationWrapperBuilder;
+
+/**
+ * A helper class for management of MediaSession (local device), Presentation API and Remote
+ * Playback API (casting) notifications and foreground services.
+ */
+class MediaSessionNotificationHelper {
+ static void serviceStarted(Service service, Intent intent, int notificationId) {
+ MediaNotificationController controller =
+ MediaNotificationManager.getController(notificationId);
+ if (controller != null && controller.processIntent(service, intent)) return;
+
+ // The service has been started with startForegroundService() but the
+ // notification hasn't been shown. See similar logic in {@link
+ // ChromeMediaNotificationControllerDelegate}.
+ MediaNotificationController.finishStartingForegroundServiceOnO(service,
+ createNotificationWrapperBuilder(notificationId).buildNotificationWrapper());
+ // Call stopForeground to guarantee Android unset the foreground bit.
+ ForegroundServiceUtils.getInstance().stopForeground(
+ service, Service.STOP_FOREGROUND_REMOVE);
+ service.stopSelf();
+ }
+
+ static void serviceDestroyed(int notificationId) {
+ MediaNotificationController controller =
+ MediaNotificationManager.getController(notificationId);
+ if (controller != null) controller.onServiceDestroyed();
+ MediaNotificationManager.clear(notificationId);
+ }
+
+ static NotificationWrapperBuilder createNotificationWrapperBuilder(int notificationId) {
+ // Only the null tag will work as expected, because {@link Service#startForeground()} only
+ // takes an ID and no tag. If we pass a tag here, then the notification that's used to
+ // display a paused state (no foreground service) will not be identified as the same one
+ // that's used with the foreground service.
+ return WebLayerNotificationWrapperBuilder.create(
+ WebLayerNotificationChannels.ChannelId.MEDIA_PLAYBACK,
+ new NotificationMetadata(0, null /*notificationTag*/, notificationId));
+ }
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/OWNERS b/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/OWNERS
new file mode 100644
index 00000000000..faba26b9c87
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/OWNERS
@@ -0,0 +1,5 @@
+# TEAM: payments-dev@chromium.org
+# COMPONENT: Blink>Payments
+# OS: Android
+
+file://components/payments/OWNERS
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestFactory.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestFactory.java
new file mode 100644
index 00000000000..c3231fc4fde
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestFactory.java
@@ -0,0 +1,112 @@
+// 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.
+
+package org.chromium.weblayer_private.payments;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
+import org.chromium.components.payments.InvalidPaymentRequest;
+import org.chromium.components.payments.PaymentFeatureList;
+import org.chromium.components.payments.PaymentRequestService;
+import org.chromium.components.payments.PaymentRequestServiceUtil;
+import org.chromium.components.payments.PrefsStrings;
+import org.chromium.components.user_prefs.UserPrefs;
+import org.chromium.content_public.browser.FeaturePolicyFeature;
+import org.chromium.content_public.browser.RenderFrameHost;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContentsStatics;
+import org.chromium.mojo.system.MojoException;
+import org.chromium.mojo.system.MojoResult;
+import org.chromium.payments.mojom.PaymentRequest;
+import org.chromium.services.service_manager.InterfaceFactory;
+import org.chromium.weblayer_private.ProfileImpl;
+import org.chromium.weblayer_private.TabImpl;
+
+/** Creates an instance of PaymentRequest for use in WebLayer. */
+public class WebLayerPaymentRequestFactory implements InterfaceFactory<PaymentRequest> {
+ private final RenderFrameHost mRenderFrameHost;
+
+ /**
+ * Production implementation of the WebLayerPaymentRequestService's Delegate. Gives true answers
+ * about the system.
+ */
+ private static class WebLayerPaymentRequestDelegateImpl
+ implements PaymentRequestService.Delegate {
+ private final RenderFrameHost mRenderFrameHost;
+
+ /* package */ WebLayerPaymentRequestDelegateImpl(RenderFrameHost renderFrameHost) {
+ mRenderFrameHost = renderFrameHost;
+ }
+
+ @Override
+ public boolean isOffTheRecord() {
+ ProfileImpl profile = getProfile();
+ if (profile == null) return true;
+ return profile.isIncognito();
+ }
+
+ @Override
+ public String getInvalidSslCertificateErrorMessage() {
+ assert false : "Not implemented yet";
+ return "";
+ }
+
+ @Override
+ public boolean prefsCanMakePayment() {
+ BrowserContextHandle profile = getProfile();
+ return profile != null
+ && UserPrefs.get(profile).getBoolean(PrefsStrings.CAN_MAKE_PAYMENT_ENABLED);
+ }
+
+ @Nullable
+ @Override
+ public String getTwaPackageName() {
+ return null;
+ }
+
+ @Nullable
+ private ProfileImpl getProfile() {
+ WebContents webContents =
+ PaymentRequestServiceUtil.getLiveWebContents(mRenderFrameHost);
+ if (webContents == null) return null;
+ TabImpl tab = TabImpl.fromWebContents(webContents);
+ if (tab == null) return null;
+ return tab.getProfile();
+ }
+ }
+
+ /**
+ * Creates an instance of WebLayerPaymentRequestFactory.
+ * @param renderFrameHost The frame that issues the payment request on the merchant page.
+ */
+ public WebLayerPaymentRequestFactory(RenderFrameHost renderFrameHost) {
+ mRenderFrameHost = renderFrameHost;
+ }
+
+ @Override
+ public PaymentRequest createImpl() {
+ if (mRenderFrameHost == null) return new InvalidPaymentRequest();
+ if (!mRenderFrameHost.isFeatureEnabled(FeaturePolicyFeature.PAYMENT)) {
+ mRenderFrameHost.getRemoteInterfaces().onConnectionError(
+ new MojoException(MojoResult.PERMISSION_DENIED));
+ return null;
+ }
+
+ if (!PaymentFeatureList.isEnabled(PaymentFeatureList.WEB_PAYMENTS)) {
+ return new InvalidPaymentRequest();
+ }
+
+ PaymentRequestService.Delegate delegate =
+ new WebLayerPaymentRequestDelegateImpl(mRenderFrameHost);
+
+ WebContents webContents = WebContentsStatics.fromRenderFrameHost(mRenderFrameHost);
+ if (webContents == null || webContents.isDestroyed()) return new InvalidPaymentRequest();
+
+ return PaymentRequestService.createPaymentRequest(mRenderFrameHost,
+ /*isOffTheRecord=*/delegate.isOffTheRecord(), delegate,
+ (paymentRequestService)
+ -> new WebLayerPaymentRequestService(paymentRequestService, delegate));
+ }
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java
new file mode 100644
index 00000000000..15a27e1be91
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java
@@ -0,0 +1,57 @@
+// 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.
+
+package org.chromium.weblayer_private.payments;
+
+import org.chromium.components.payments.BrowserPaymentRequest;
+import org.chromium.components.payments.PaymentAppService;
+import org.chromium.components.payments.PaymentRequestService;
+import org.chromium.components.payments.PaymentRequestService.Delegate;
+import org.chromium.payments.mojom.PaymentDetails;
+import org.chromium.payments.mojom.PaymentValidationErrors;
+
+/** The WebLayer-specific part of the payment request service. */
+public class WebLayerPaymentRequestService implements BrowserPaymentRequest {
+ /**
+ * Create an instance of {@link WebLayerPaymentRequestService}.
+ * @param paymentRequestService The payment request service.
+ * @param delegate The delegate of the payment request service.
+ */
+ public WebLayerPaymentRequestService(
+ PaymentRequestService paymentRequestService, Delegate delegate) {
+ assert false : "Not implemented yet";
+ }
+
+ @Override
+ public void onPaymentDetailsUpdated(
+ PaymentDetails details, boolean hasNotifiedInvokedPaymentApp) {
+ assert false : "Not implemented yet";
+ }
+
+ @Override
+ public void onPaymentDetailsNotUpdated(String selectedShippingOptionError) {
+ assert false : "Not implemented yet";
+ }
+
+ @Override
+ public void complete(int result) {
+ assert false : "Not implemented yet";
+ }
+
+ @Override
+ public void retry(PaymentValidationErrors errors) {
+ assert false : "Not implemented yet";
+ }
+
+ @Override
+ public void close() {
+ assert false : "Not implemented yet";
+ }
+
+ @Override
+ public void addPaymentAppFactories(PaymentAppService service) {
+ assert false : "Not implemented yet";
+ }
+
+}
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
index 53eff3330ed..e11d7a1ded7 100644
--- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/test_interfaces/ITestWebLayer.aidl
@@ -4,6 +4,8 @@
package org.chromium.weblayer_private.test_interfaces;
+import android.os.Bundle;
+import org.chromium.weblayer_private.interfaces.IBrowser;
import org.chromium.weblayer_private.interfaces.IObjectWrapper;
import org.chromium.weblayer_private.interfaces.ITab;
@@ -38,7 +40,7 @@ interface ITestWebLayer {
void addInfoBar(in ITab tab, in IObjectWrapper runnable) = 10;
// Gets the infobar container view associated with |tab|.
- IObjectWrapper getInfoBarContainerView(in ITab tab) = 11;
+ IObjectWrapper /* View */ getInfoBarContainerView(in ITab tab) = 11;
void setIgnoreMissingKeyForTranslateManager(in boolean ignore) = 12;
void forceNetworkConnectivityState(in boolean networkAvailable) = 13;
@@ -53,4 +55,19 @@ interface ITestWebLayer {
// Returns true if a fullscreen toast was shown for |tab|.
boolean didShowFullscreenToast(in ITab tab) = 17;
+
+ // Does setup for MediaRouter tests, mocking out Chromecast devices.
+ void initializeMockMediaRouteProvider(
+ boolean closeRouteWithErrorOnSend, boolean disableIsSupportsSource,
+ in String createRouteErrorMessage, in String joinRouteErrorMessage) = 18;
+
+ // Gets a button from the currently visible media route selection dialog. The button represents a
+ // route and contains the text |name|. Returns null if no such dialog or button exists.
+ IObjectWrapper /* View */ getMediaRouteButton(String name) = 19;
+
+ // Causes the renderer process in the tab's main frame to crash.
+ void crashTab(in ITab tab) = 20;
+
+ boolean isWindowOnSmallDevice(in IBrowser browser) = 21;
+ IObjectWrapper getSecurityButton(IObjectWrapper /* View */ urlBarView) = 22;
}