From cfd70fda6eb0a5bde51fca4fd3b0fe9b0c0eadb0 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Wed, 26 Oct 2022 17:52:35 +0200 Subject: [PATCH] release 6.0.0-beta.9 --- CHANGELOG.md | 11 +- .../InAppWebViewFileProvider.java | 2 +- .../ActionBroadcastReceiver.java | 22 +- .../ChromeCustomTabsActivity.java | 64 +++++- .../ChromeCustomTabsChannelDelegate.java | 22 +- .../ChromeCustomTabsSettings.java | 5 + .../ChromeSafariBrowserManager.java | 14 +- .../CustomTabActivityHelper.java | 60 ++--- .../TrustedWebActivity.java | 31 ++- .../types/AndroidResource.java | 6 +- .../types/CustomTabsSecondaryToolbar.java | 83 +++++++ .../InAppWebViewChromeClient.java | 10 +- .../app/src/main/res/layout/remote_view.xml | 21 ++ .../app/src/main/res/layout/remote_view_2.xml | 14 ++ .../custom_action_button.dart | 44 ---- .../custom_menu_item.dart | 5 +- .../chrome_safari_browser/custom_tabs.dart | 109 +++++++++ .../chrome_safari_browser/main.dart | 2 - .../chrome_safari_browser/open_and_close.dart | 29 +-- .../sf_safari_view_controller.dart | 18 +- .../trusted_web_activity.dart | 9 +- example/integration_test/util.dart | 6 +- .../ios/Flutter/flutter_export_environment.sh | 5 +- example/ios/Runner.xcodeproj/project.pbxproj | 184 ++++++++++++++- example/ios/test/ActionViewController.swift | 58 +++++ .../test/Base.lproj/MainInterface.storyboard | 53 +++++ example/ios/test/Info.plist | 28 +++ example/ios/test/Media.xcassets/Contents.json | 6 + .../TouchBarBezel.colorset/Contents.json | 14 ++ .../chrome_safari_browser_example.screen.dart | 24 +- .../ChromeSafariBrowserManager.swift | 3 - .../SafariBrowserSettings.swift | 9 + .../SafariViewController.swift | 35 ++- ios/Classes/Types/ActivityButton.swift | 24 ++ ios/Classes/Types/UIEventAttribution.swift | 28 +++ ios/Classes/Types/UIImage.swift | 27 +++ lib/src/android/webview_feature.dart | 3 +- .../chrome_safari_browser.dart | 209 ++++++++++++++++-- .../chrome_safari_browser_settings.dart | 34 ++- .../chrome_safari_browser_settings.g.dart | 42 +++- lib/src/in_app_webview/in_app_webview.dart | 19 -- lib/src/types/activity_button.dart | 24 ++ lib/src/types/activity_button.g.dart | 54 +++++ lib/src/types/android_resource.dart | 19 +- lib/src/types/android_resource.g.dart | 13 ++ lib/src/types/main.dart | 8 +- lib/src/types/ui_event_attribution.dart | 35 +++ lib/src/types/ui_event_attribution.g.dart | 70 ++++++ lib/src/types/ui_image.dart | 28 +++ lib/src/types/ui_image.g.dart | 59 +++++ 50 files changed, 1494 insertions(+), 208 deletions(-) create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/CustomTabsSecondaryToolbar.java create mode 100644 example/android/app/src/main/res/layout/remote_view.xml create mode 100644 example/android/app/src/main/res/layout/remote_view_2.xml delete mode 100644 example/integration_test/chrome_safari_browser/custom_action_button.dart create mode 100644 example/ios/test/ActionViewController.swift create mode 100644 example/ios/test/Base.lproj/MainInterface.storyboard create mode 100644 example/ios/test/Info.plist create mode 100644 example/ios/test/Media.xcassets/Contents.json create mode 100644 example/ios/test/Media.xcassets/TouchBarBezel.colorset/Contents.json create mode 100644 ios/Classes/Types/ActivityButton.swift create mode 100644 ios/Classes/Types/UIEventAttribution.swift create mode 100644 ios/Classes/Types/UIImage.swift create mode 100644 lib/src/types/activity_button.dart create mode 100644 lib/src/types/activity_button.g.dart create mode 100644 lib/src/types/ui_event_attribution.dart create mode 100644 lib/src/types/ui_event_attribution.g.dart create mode 100644 lib/src/types/ui_image.dart create mode 100644 lib/src/types/ui_image.g.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index a5e6418d..9c586758 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,20 @@ ## 6.0.0-beta.9 -- Added `headers`, `otherLikelyURLs` arguments on `ChromeSafariBrowser.open` method for Android +- Added `headers`, `otherLikelyURLs`, `referrer` arguments on `ChromeSafariBrowser.open` method for Android - Added `onNavigationEvent`, `onServiceConnected`, `onRelationshipValidationResult` events on `ChromeSafariBrowser` for Android -- Added `mayLaunchUrl`, `launchUrl`, `updateActionButton`, `validateRelationship` methods on `ChromeSafariBrowser` for Android -- Added `startAnimations`, `exitAnimations`, `navigationBarColor`, `navigationBarDividerColor`, `secondaryToolbarColor` ChromeSafariBrowser settings for Android +- Added `mayLaunchUrl`, `launchUrl`, `updateActionButton`, `validateRelationship`, `setSecondaryToolbar`, `updateSecondaryToolbar` methods on `ChromeSafariBrowser` for Android +- Added `startAnimations`, `exitAnimations`, `navigationBarColor`, `navigationBarDividerColor`, `secondaryToolbarColor`, `alwaysUseBrowserUI` ChromeSafariBrowser settings for Android +- Added `ChromeSafariBrowserMenuItem.image` property for iOS - Added `didLoadSuccessfully` optional argument on `ChromeSafariBrowser.onCompletedInitialLoad` event for iOS - Added `onInitialLoadDidRedirect`, `onWillOpenInBrowser` events on `ChromeSafariBrowser` for iOS -- Added `clearWebsiteData`, `prewarmConnections`, `invalidatePrewarmingToken` static methods on `ChromeSafariBrowser` for iOS +- Added `activityButton`, `eventAttribution` ChromeSafariBrowser settings for iOS +- Added `clearWebsiteData`, `prewarmConnections`, `invalidatePrewarmingToken`, `getMaxToolbarItems` static methods on `ChromeSafariBrowser` for iOS - Added `getVariationsHeader` WebView static method ### BREAKING CHANGES - `ChromeSafariBrowser.onCompletedInitialLoad` event has an optional argument +- `ChromeSafariBrowserMenuItem.action` and `ChromeSafariBrowserActionButton.action` can be null - All `ChromeSafariBrowserSettings` properties are optionals ## 6.0.0-beta.8 diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFileProvider.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFileProvider.java index b94a2cac..7322b8b5 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFileProvider.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFileProvider.java @@ -4,6 +4,6 @@ import androidx.core.content.FileProvider; public class InAppWebViewFileProvider extends FileProvider { - // This class intentionally left blank. + public static final String fileProviderAuthorityExtension = "flutter_inappwebview.fileprovider"; } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ActionBroadcastReceiver.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ActionBroadcastReceiver.java index e58ead51..1b6ea859 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ActionBroadcastReceiver.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ActionBroadcastReceiver.java @@ -4,6 +4,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.util.Log; + +import androidx.browser.customtabs.CustomTabsIntent; public class ActionBroadcastReceiver extends BroadcastReceiver { protected static final String LOG_TAG = "ActionBroadcastReceiver"; @@ -13,16 +16,25 @@ public class ActionBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + int clickedId = intent.getIntExtra(CustomTabsIntent.EXTRA_REMOTEVIEWS_CLICKED_ID, -1); String url = intent.getDataString(); if (url != null) { Bundle b = intent.getExtras(); String viewId = b.getString(KEY_ACTION_VIEW_ID); - int id = b.getInt(KEY_ACTION_ID); - String title = b.getString(KEY_URL_TITLE); - ChromeCustomTabsActivity browser = ChromeSafariBrowserManager.browsers.get(viewId); - if (browser != null && browser.channelDelegate != null) { - browser.channelDelegate.onItemActionPerform(id, url, title); + if (clickedId == -1) { + int id = b.getInt(KEY_ACTION_ID); + String title = b.getString(KEY_URL_TITLE); + + ChromeCustomTabsActivity browser = ChromeSafariBrowserManager.browsers.get(viewId); + if (browser != null && browser.channelDelegate != null) { + browser.channelDelegate.onItemActionPerform(id, url, title); + } + } else { + ChromeCustomTabsActivity browser = ChromeSafariBrowserManager.browsers.get(viewId); + if (browser != null && browser.channelDelegate != null) { + browser.channelDelegate.onSecondaryItemActionPerform(browser.getResources().getResourceName(clickedId), url); + } } } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java index 0216c3a5..7842a67b 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivity.java @@ -9,7 +9,7 @@ import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.util.Log; +import android.widget.RemoteViews; import androidx.annotation.CallSuper; import androidx.annotation.NonNull; @@ -24,6 +24,7 @@ import com.pichillilorenzo.flutter_inappwebview.R; import com.pichillilorenzo.flutter_inappwebview.types.AndroidResource; import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsActionButton; import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsMenuItem; +import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsSecondaryToolbar; import com.pichillilorenzo.flutter_inappwebview.types.Disposable; import java.util.ArrayList; @@ -55,10 +56,14 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { public List initialOtherLikelyURLs; @Nullable public Map initialHeaders; + @Nullable + public String initialReferrer; public List menuItems = new ArrayList<>(); @Nullable public CustomTabsActionButton actionButton; @Nullable + public CustomTabsSecondaryToolbar secondaryToolbar; + @Nullable public ChromeCustomTabsChannelDelegate channelDelegate; @CallSuper @@ -84,11 +89,13 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { initialUrl = b.getString("url"); initialHeaders = (Map) b.getSerializable("headers"); + initialReferrer = b.getString("referrer"); initialOtherLikelyURLs = b.getStringArrayList("otherLikelyURLs"); customSettings = new ChromeCustomTabsSettings(); customSettings.parse((HashMap) b.getSerializable("settings")); actionButton = CustomTabsActionButton.fromMap((Map) b.getSerializable("actionButton")); + secondaryToolbar = CustomTabsSecondaryToolbar.fromMap((Map) b.getSerializable("secondaryToolbar")); List> menuItemList = (List>) b.getSerializable("menuItemList"); for (Map menuItem : menuItemList) { menuItems.add(CustomTabsMenuItem.fromMap(menuItem)); @@ -155,8 +162,9 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { } public void launchUrl(@NonNull String url, - @Nullable Map headers, - @Nullable List otherLikelyURLs) { + @Nullable Map headers, + @Nullable String referrer, + @Nullable List otherLikelyURLs) { mayLaunchUrl(url, otherLikelyURLs); builder = new CustomTabsIntent.Builder(customTabsSession); prepareCustomTabs(); @@ -164,7 +172,8 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { CustomTabsIntent customTabsIntent = builder.build(); prepareCustomTabsIntent(customTabsIntent); - CustomTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), headers, CHROME_CUSTOM_TAB_REQUEST_CODE); + CustomTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), headers, + referrer != null ? Uri.parse(referrer) : null, CHROME_CUSTOM_TAB_REQUEST_CODE); } public boolean mayLaunchUrl(@Nullable String url, @Nullable List otherLikelyURLs) { @@ -183,7 +192,7 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { public void customTabsConnected() { customTabsSession = customTabActivityHelper.getSession(); if (initialUrl != null) { - launchUrl(initialUrl, initialHeaders, initialOtherLikelyURLs); + launchUrl(initialUrl, initialHeaders, initialReferrer, initialOtherLikelyURLs); } } @@ -244,6 +253,33 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { createPendingIntent(actionButton.getId()), actionButton.isShouldTint()); } + + if (secondaryToolbar != null) { + AndroidResource layout = secondaryToolbar.getLayout(); + RemoteViews remoteViews = new RemoteViews(layout.getDefPackage(), layout.getIdentifier(this)); + int[] clickableIDs = new int[secondaryToolbar.getClickableIDs().size()]; + for (int i = 0, length = secondaryToolbar.getClickableIDs().size(); i < length; i++) { + AndroidResource clickableID = secondaryToolbar.getClickableIDs().get(i); + clickableIDs[i] = clickableID.getIdentifier(this); + } + builder.setSecondaryToolbarViews(remoteViews, clickableIDs, getSecondaryToolbarOnClickPendingIntent()); + } + } + + public PendingIntent getSecondaryToolbarOnClickPendingIntent() { + Intent broadcastIntent = new Intent(this, ActionBroadcastReceiver.class); + + Bundle extras = new Bundle(); + extras.putString(ActionBroadcastReceiver.KEY_ACTION_VIEW_ID, id); + broadcastIntent.putExtras(extras); + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + return PendingIntent.getBroadcast( + this, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); + } else { + return PendingIntent.getBroadcast( + this, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT); + } } private void prepareCustomTabsIntent(CustomTabsIntent customTabsIntent) { @@ -254,6 +290,9 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { if (customSettings.keepAliveEnabled) CustomTabsHelper.addKeepAliveExtra(this, customTabsIntent.intent); + + if (customSettings.alwaysUseBrowserUI) + CustomTabsIntent.setAlwaysUseBrowserUI(customTabsIntent.intent); } public void updateActionButton(@NonNull byte[] icon, @NonNull String description) { @@ -270,6 +309,21 @@ public class ChromeCustomTabsActivity extends Activity implements Disposable { actionButton.setDescription(description); } + public void updateSecondaryToolbar(CustomTabsSecondaryToolbar secondaryToolbar) { + if (customTabsSession == null) { + return; + } + AndroidResource layout = secondaryToolbar.getLayout(); + RemoteViews remoteViews = new RemoteViews(layout.getDefPackage(), layout.getIdentifier(this)); + int[] clickableIDs = new int[secondaryToolbar.getClickableIDs().size()]; + for (int i = 0, length = secondaryToolbar.getClickableIDs().size(); i < length; i++) { + AndroidResource clickableID = secondaryToolbar.getClickableIDs().get(i); + clickableIDs[i] = clickableID.getIdentifier(this); + } + customTabsSession.setSecondaryToolbarViews(remoteViews, clickableIDs, getSecondaryToolbarOnClickPendingIntent()); + this.secondaryToolbar = secondaryToolbar; + } + @Override protected void onStart() { super.onStart(); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java index 1af27d3b..137624a8 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsChannelDelegate.java @@ -9,6 +9,7 @@ import androidx.annotation.Nullable; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsActionButton; +import com.pichillilorenzo.flutter_inappwebview.types.CustomTabsSecondaryToolbar; import java.util.ArrayList; import java.util.HashMap; @@ -35,8 +36,9 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl { String url = (String) call.argument("url"); if (url != null) { Map headers = (Map) call.argument("headers"); + String referrer = (String) call.argument("referrer"); List otherLikelyURLs = (List) call.argument("otherLikelyURLs"); - chromeCustomTabsActivity.launchUrl(url, headers, otherLikelyURLs); + chromeCustomTabsActivity.launchUrl(url, headers, referrer, otherLikelyURLs); result.success(true); } else { result.success(false); @@ -73,6 +75,15 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl { result.success(false); } break; + case "updateSecondaryToolbar": + if (chromeCustomTabsActivity != null) { + CustomTabsSecondaryToolbar secondaryToolbar = CustomTabsSecondaryToolbar.fromMap((Map) call.argument("secondaryToolbar")); + chromeCustomTabsActivity.updateSecondaryToolbar(secondaryToolbar); + result.success(true); + } else { + result.success(false); + } + break; case "close": if (chromeCustomTabsActivity != null) { chromeCustomTabsActivity.onStop(); @@ -145,6 +156,15 @@ public class ChromeCustomTabsChannelDelegate extends ChannelDelegateImpl { channel.invokeMethod("onItemActionPerform", obj); } + public void onSecondaryItemActionPerform(String name, String url) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("name", name); + obj.put("url", url); + channel.invokeMethod("onSecondaryItemActionPerform", obj); + } + public void onRelationshipValidationResult(int relation, @NonNull Uri requestedOrigin, boolean result) { MethodChannel channel = getChannel(); if (channel == null) return; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsSettings.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsSettings.java index 10f3e707..8be604a0 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsSettings.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsSettings.java @@ -44,6 +44,7 @@ public class ChromeCustomTabsSettings implements ISettings startAnimations = new ArrayList<>(); public List exitAnimations = new ArrayList<>(); + public Boolean alwaysUseBrowserUI = false; @NonNull @Override @@ -138,6 +139,9 @@ public class ChromeCustomTabsSettings implements ISettings headers = (HashMap) call.argument("headers"); + String referrer = (String) call.argument("referrer"); ArrayList otherLikelyURLs = (ArrayList) call.argument("otherLikelyURLs"); HashMap settings = (HashMap) call.argument("settings"); HashMap actionButton = (HashMap) call.argument("actionButton"); + HashMap secondaryToolbar = (HashMap) call.argument("secondaryToolbar"); List> menuItemList = (List>) call.argument("menuItemList"); - open(plugin.activity, viewId, url, headers, otherLikelyURLs, settings, actionButton, menuItemList, result); + open(plugin.activity, viewId, url, headers, referrer, otherLikelyURLs, settings, actionButton, secondaryToolbar, menuItemList, result); } else { result.success(false); } @@ -64,26 +67,31 @@ public class ChromeSafariBrowserManager extends ChannelDelegateImpl { result.success(false); } break; + case "getMaxToolbarItems": + result.success(CustomTabsIntent.getMaxToolbarItems()); + break; default: result.notImplemented(); } } public void open(Activity activity, String viewId, @Nullable String url, @Nullable HashMap headers, - @Nullable ArrayList otherLikelyURLs, + @Nullable String referrer, @Nullable ArrayList otherLikelyURLs, HashMap settings, HashMap actionButton, + HashMap secondaryToolbar, List> menuItemList, MethodChannel.Result result) { Intent intent = null; Bundle extras = new Bundle(); extras.putString("url", url); - extras.putBoolean("isData", false); extras.putString("id", viewId); extras.putString("managerId", this.id); extras.putSerializable("headers", headers); + extras.putString("referrer", referrer); extras.putSerializable("otherLikelyURLs", otherLikelyURLs); extras.putSerializable("settings", settings); extras.putSerializable("actionButton", (Serializable) actionButton); + extras.putSerializable("secondaryToolbar", (Serializable) secondaryToolbar); extras.putSerializable("menuItemList", (Serializable) menuItemList); Boolean isSingleInstance = Util.getOrDefault(settings, "isSingleInstance", false); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/CustomTabActivityHelper.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/CustomTabActivityHelper.java index 57e78f07..10d930eb 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/CustomTabActivityHelper.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/CustomTabActivityHelper.java @@ -1,7 +1,7 @@ package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs; import android.app.Activity; -import android.content.pm.PackageManager; +import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.provider.Browser; @@ -28,42 +28,50 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback { private CustomTabsCallback mCustomTabsCallback; /** - * Opens the URL on a Custom Tab if possible. Otherwise fallsback to opening it on a WebView. + * Opens the URL on a Custom Tab if possible. * * @param activity The host activity. - * @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available. + * @param intent a intent to be used if Custom Tabs is available. * @param uri the Uri to be opened. */ + public static void openCustomTab(Activity activity, + Intent intent, + Uri uri, + @Nullable Map headers, + @Nullable Uri referrer, + int requestCode) { + intent.setData(uri); + if (headers != null) { + Bundle bundleHeaders = new Bundle(); + for (Map.Entry header : headers.entrySet()) { + bundleHeaders.putString(header.getKey(), header.getValue()); + } + intent.putExtra(Browser.EXTRA_HEADERS, bundleHeaders); + } + if (referrer != null) { + intent.putExtra(Intent.EXTRA_REFERRER, referrer); + } + activity.startActivityForResult(intent, requestCode); + } + public static void openCustomTab(Activity activity, CustomTabsIntent customTabsIntent, Uri uri, @Nullable Map headers, + @Nullable Uri referrer, int requestCode) { - customTabsIntent.intent.setData(uri); - if (headers != null) { - Bundle bundleHeaders = new Bundle(); - for (Map.Entry header : headers.entrySet()) { - bundleHeaders.putString(header.getKey(), header.getValue()); - } - customTabsIntent.intent.putExtra(Browser.EXTRA_HEADERS, bundleHeaders); - } - activity.startActivityForResult(customTabsIntent.intent, requestCode); + CustomTabActivityHelper.openCustomTab(activity, customTabsIntent.intent, uri, + headers, referrer, requestCode); } - public static void openCustomTab(Activity activity, - TrustedWebActivityIntent trustedWebActivityIntent, - Uri uri, - @Nullable Map headers, - int requestCode) { - trustedWebActivityIntent.getIntent().setData(uri); - if (headers != null) { - Bundle bundleHeaders = new Bundle(); - for (Map.Entry header : headers.entrySet()) { - bundleHeaders.putString(header.getKey(), header.getValue()); - } - trustedWebActivityIntent.getIntent().putExtra(Browser.EXTRA_HEADERS, bundleHeaders); - } - activity.startActivityForResult(trustedWebActivityIntent.getIntent(), requestCode); + public static void openTrustedWebActivity(Activity activity, + TrustedWebActivityIntent trustedWebActivityIntent, + Uri uri, + @Nullable Map headers, + @Nullable Uri referrer, + int requestCode) { + CustomTabActivityHelper.openCustomTab(activity, trustedWebActivityIntent.getIntent(), uri, + headers, referrer, requestCode); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/TrustedWebActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/TrustedWebActivity.java index b86578a0..aee48e5b 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/TrustedWebActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/TrustedWebActivity.java @@ -3,18 +3,14 @@ package com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs; import android.content.Intent; import android.graphics.Color; import android.net.Uri; -import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.browser.customtabs.CustomTabColorSchemeParams; import androidx.browser.customtabs.CustomTabsIntent; -import androidx.browser.customtabs.CustomTabsService; import androidx.browser.trusted.TrustedWebActivityIntent; import androidx.browser.trusted.TrustedWebActivityIntentBuilder; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -27,6 +23,7 @@ public class TrustedWebActivity extends ChromeCustomTabsActivity { @Override public void launchUrl(@NonNull String url, @Nullable Map headers, + @Nullable String referrer, @Nullable List otherLikelyURLs) { if (customTabsSession == null) { return; @@ -40,24 +37,33 @@ public class TrustedWebActivity extends ChromeCustomTabsActivity { TrustedWebActivityIntent trustedWebActivityIntent = builder.build(customTabsSession); prepareCustomTabsIntent(trustedWebActivityIntent); - CustomTabActivityHelper.openCustomTab(this, trustedWebActivityIntent, uri, headers, CHROME_CUSTOM_TAB_REQUEST_CODE); + CustomTabActivityHelper.openTrustedWebActivity(this, trustedWebActivityIntent, uri, headers, + referrer != null ? Uri.parse(referrer) : null, CHROME_CUSTOM_TAB_REQUEST_CODE); } @Override public void customTabsConnected() { customTabsSession = customTabActivityHelper.getSession(); if (initialUrl != null) { - launchUrl(initialUrl, initialHeaders, initialOtherLikelyURLs); + launchUrl(initialUrl, initialHeaders, initialReferrer, initialOtherLikelyURLs); } } private void prepareCustomTabs() { + CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder(); if (customSettings.toolbarBackgroundColor != null && !customSettings.toolbarBackgroundColor.isEmpty()) { - CustomTabColorSchemeParams.Builder defaultColorSchemeBuilder = new CustomTabColorSchemeParams.Builder(); - builder.setDefaultColorSchemeParams(defaultColorSchemeBuilder - .setToolbarColor(Color.parseColor(customSettings.toolbarBackgroundColor)) - .build()); + defaultColorSchemeBuilder.setToolbarColor(Color.parseColor(customSettings.toolbarBackgroundColor)); } + if (customSettings.navigationBarColor != null && !customSettings.navigationBarColor.isEmpty()) { + defaultColorSchemeBuilder.setNavigationBarColor(Color.parseColor(customSettings.navigationBarColor)); + } + if (customSettings.navigationBarDividerColor != null && !customSettings.navigationBarDividerColor.isEmpty()) { + defaultColorSchemeBuilder.setNavigationBarDividerColor(Color.parseColor(customSettings.navigationBarDividerColor)); + } + if (customSettings.secondaryToolbarColor != null && !customSettings.secondaryToolbarColor.isEmpty()) { + defaultColorSchemeBuilder.setSecondaryToolbarColor(Color.parseColor(customSettings.secondaryToolbarColor)); + } + builder.setDefaultColorSchemeParams(defaultColorSchemeBuilder.build()); if (customSettings.additionalTrustedOrigins != null && !customSettings.additionalTrustedOrigins.isEmpty()) { builder.setAdditionalTrustedOrigins(customSettings.additionalTrustedOrigins); @@ -66,7 +72,7 @@ public class TrustedWebActivity extends ChromeCustomTabsActivity { if (customSettings.displayMode != null) { builder.setDisplayMode(customSettings.displayMode); } - + builder.setScreenOrientation(customSettings.screenOrientation); } @@ -79,5 +85,8 @@ public class TrustedWebActivity extends ChromeCustomTabsActivity { if (customSettings.keepAliveEnabled) CustomTabsHelper.addKeepAliveExtra(this, intent); + + if (customSettings.alwaysUseBrowserUI) + CustomTabsIntent.setAlwaysUseBrowserUI(intent); } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/AndroidResource.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/AndroidResource.java index ba145359..86353dee 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/AndroidResource.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/AndroidResource.java @@ -10,11 +10,11 @@ import java.util.Map; public class AndroidResource { @NonNull - String name; + private String name; @Nullable - String defType; + private String defType; @Nullable - String defPackage; + private String defPackage; public AndroidResource(@NonNull String name, @Nullable String defType, @Nullable String defPackage) { this.name = name; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/CustomTabsSecondaryToolbar.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/CustomTabsSecondaryToolbar.java new file mode 100644 index 00000000..6a21267d --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/CustomTabsSecondaryToolbar.java @@ -0,0 +1,83 @@ +package com.pichillilorenzo.flutter_inappwebview.types; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class CustomTabsSecondaryToolbar { + @NonNull + private AndroidResource layout; + @NonNull + private List clickableIDs = new ArrayList<>(); + + public CustomTabsSecondaryToolbar(@NonNull AndroidResource layout, @NonNull List clickableIDs) { + this.layout = layout; + this.clickableIDs = clickableIDs; + } + + @Nullable + public static CustomTabsSecondaryToolbar fromMap(@Nullable Map map) { + if (map == null) { + return null; + } + AndroidResource layout = AndroidResource.fromMap((Map) map.get("layout")); + List clickableIDs = new ArrayList<>(); + List> clickableIDList = (List>) map.get("clickableIDs"); + if (clickableIDList != null) { + for (Map clickableIDMap : clickableIDList) { + AndroidResource clickableID = AndroidResource.fromMap((Map) clickableIDMap.get("id")); + if (clickableID != null) { + clickableIDs.add(clickableID); + } + } + } + return new CustomTabsSecondaryToolbar(layout, clickableIDs); + } + + @NonNull + public AndroidResource getLayout() { + return layout; + } + + public void setLayout(@NonNull AndroidResource layout) { + this.layout = layout; + } + + @NonNull + public List getClickableIDs() { + return clickableIDs; + } + + public void setClickableIDs(@NonNull List clickableIDs) { + this.clickableIDs = clickableIDs; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CustomTabsSecondaryToolbar that = (CustomTabsSecondaryToolbar) o; + + if (!layout.equals(that.layout)) return false; + return clickableIDs.equals(that.clickableIDs); + } + + @Override + public int hashCode() { + int result = layout.hashCode(); + result = 31 * result + clickableIDs.hashCode(); + return result; + } + + @Override + public String toString() { + return "CustomTabsSecondaryToolbar{" + + "layout=" + layout + + ", clickableIDs=" + clickableIDs + + '}'; + } +} diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java index 70ce80c6..95291151 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/webview/in_app_webview/InAppWebViewChromeClient.java @@ -41,6 +41,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; +import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFileProvider; import com.pichillilorenzo.flutter_inappwebview.types.CreateWindowAction; import com.pichillilorenzo.flutter_inappwebview.in_app_browser.ActivityResultListener; import com.pichillilorenzo.flutter_inappwebview.in_app_browser.InAppBrowserDelegate; @@ -73,8 +74,6 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR public static Map windowWebViewMessages = new HashMap<>(); private static int windowAutoincrementId = 0; - private static final String fileProviderAuthorityExtension = "flutter_inappwebview.fileprovider"; - private static final int PICKER = 1; private static final int PICKER_LEGACY = 3; final String DEFAULT_MIME_TYPES = "*/*"; @@ -1148,8 +1147,11 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR return null; } // for versions 6.0+ (23) we use the FileProvider to avoid runtime permissions - String packageName = activity.getApplicationContext().getPackageName(); - return FileProvider.getUriForFile(activity.getApplicationContext(), packageName + "." + fileProviderAuthorityExtension, capturedFile); + String fileProviderAuthority = activity.getApplicationContext().getPackageName() + "." + + InAppWebViewFileProvider.fileProviderAuthorityExtension; + return FileProvider.getUriForFile(activity.getApplicationContext(), + fileProviderAuthority, + capturedFile); } @Nullable diff --git a/example/android/app/src/main/res/layout/remote_view.xml b/example/android/app/src/main/res/layout/remote_view.xml new file mode 100644 index 00000000..ae940247 --- /dev/null +++ b/example/android/app/src/main/res/layout/remote_view.xml @@ -0,0 +1,21 @@ + + + +