diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 4c7fdffb..bb225c33 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -10,8 +10,21 @@
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
@@ -28,11 +41,11 @@
-
+
-
-
+
+
@@ -43,69 +56,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -189,11 +144,11 @@
-
-
-
+
+
+
@@ -219,9 +174,8 @@
-
-
+
@@ -244,6 +198,7 @@
+
@@ -438,28 +393,26 @@
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
-
+
+
+
+
+
-
+
+
+
@@ -468,7 +421,9 @@
+
+
@@ -514,13 +469,6 @@
-
-
-
-
-
-
-
@@ -666,20 +614,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -730,7 +666,6 @@
-
@@ -738,7 +673,6 @@
-
@@ -746,7 +680,6 @@
-
@@ -754,7 +687,6 @@
-
@@ -762,7 +694,6 @@
-
@@ -770,7 +701,6 @@
-
@@ -786,7 +716,6 @@
-
@@ -794,7 +723,6 @@
-
@@ -811,25 +739,26 @@
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -837,63 +766,33 @@
-
-
+
-
-
-
-
-
+
+
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index bf47aef8..5585f669 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -4,9 +4,9 @@
-
-
+
+
+
\ No newline at end of file
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java
index 08d62707..6cb8f36b 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java
@@ -21,9 +21,7 @@
package com.pichillilorenzo.flutter_inappbrowser;
-import android.annotation.TargetApi;
import android.app.Activity;
-import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -32,7 +30,6 @@ import android.provider.Browser;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.RequiresApi;
import android.util.JsonReader;
import android.util.JsonToken;
import android.webkit.MimeTypeMap;
@@ -41,6 +38,8 @@ import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.util.Log;
+import com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs.ChromeCustomTabsActivity;
+
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
@@ -61,6 +60,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
public Activity activity;
public static MethodChannel channel;
public static WebViewActivity webViewActivity;
+ public static ChromeCustomTabsActivity chromeCustomTabsActivity;
private static final String NULL = "null";
protected static final String LOG_TAG = "InAppBrowserFlutterP";
@@ -102,38 +102,43 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
this.activity.runOnUiThread(new Runnable() {
@Override
public void run() {
- if ("_self".equals(target)) {
- Log.d(LOG_TAG, "in self");
- //Load the dialer
- if (url.startsWith(WebView.SCHEME_TEL))
- {
- try {
- Log.d(LOG_TAG, "loading in dialer");
- Intent intent = new Intent(Intent.ACTION_DIAL);
- intent.setData(Uri.parse(url));
- activity.startActivity(intent);
- } catch (android.content.ActivityNotFoundException e) {
- Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+ if (options.useChromeCustomTabs) {
+ open(url, options);
+ }
+ else {
+ if ("_self".equals(target)) {
+ Log.d(LOG_TAG, "in self");
+
+ //Load the dialer
+ if (url.startsWith(WebView.SCHEME_TEL))
+ {
+ try {
+ Log.d(LOG_TAG, "loading in dialer");
+ Intent intent = new Intent(Intent.ACTION_DIAL);
+ intent.setData(Uri.parse(url));
+ activity.startActivity(intent);
+ } catch (android.content.ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+ }
+ }
+ // load in InAppBrowserFlutterPlugin
+ else {
+ Log.d(LOG_TAG, "loading in InAppBrowserFlutterPlugin");
+ open(url, options);
}
}
- // load in InAppBrowserFlutterPlugin
+ // SYSTEM
+ else if ("_system".equals(target)) {
+ Log.d(LOG_TAG, "in system");
+ openExternal(url, result);
+ }
+ // BLANK - or anything else
else {
- Log.d(LOG_TAG, "loading in InAppBrowserFlutterPlugin");
+ Log.d(LOG_TAG, "in blank");
open(url, options);
}
}
- // SYSTEM
- else if ("_system".equals(target)) {
- Log.d(LOG_TAG, "in system");
- openExternal(url, result);
- }
- // BLANK - or anything else
- else {
- Log.d(LOG_TAG, "in blank");
- open(url, options);
- }
-
result.success(true);
}
});
@@ -360,8 +365,8 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
}
}
- private void open(final String url, InAppBrowserOptions options) {
- Intent intent = new Intent(activity, WebViewActivity.class);
+ public static void open(final String url, InAppBrowserOptions options) {
+ Intent intent = new Intent(registrar.activity(), (options.useChromeCustomTabs) ? ChromeCustomTabsActivity.class : WebViewActivity.class);
Bundle extras = new Bundle();
extras.putString("url", url);
@@ -369,7 +374,7 @@ public class InAppBrowserFlutterPlugin implements MethodCallHandler {
intent.putExtras(extras);
- activity.startActivity(intent);
+ registrar.activity().startActivity(intent);
}
public void loadUrl(String url, Map headers, Result result) {
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java
index 0264eebf..c6ad91bf 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java
@@ -9,28 +9,35 @@ import java.util.HashMap;
public class InAppBrowserOptions {
- boolean useShouldOverrideUrlLoading = false;
- boolean clearCache = false;
- String userAgent = "";
- boolean javaScriptEnabled = true;
- boolean javaScriptCanOpenWindowsAutomatically = false;
- boolean hidden = false;
- boolean toolbarTop = true;
- String toolbarTopBackgroundColor = "";
- String toolbarTopFixedTitle = "";
- boolean hideUrlBar = false;
- boolean mediaPlaybackRequiresUserGesture = true;
+ public boolean useShouldOverrideUrlLoading = false;
+ public boolean clearCache = false;
+ public String userAgent = "";
+ public boolean javaScriptEnabled = true;
+ public boolean javaScriptCanOpenWindowsAutomatically = false;
+ public boolean hidden = false;
+ public boolean toolbarTop = true;
+ public String toolbarTopBackgroundColor = "";
+ public String toolbarTopFixedTitle = "";
+ public boolean hideUrlBar = false;
+ public boolean mediaPlaybackRequiresUserGesture = true;
- boolean hideTitleBar = false;
- boolean closeOnCannotGoBack = true;
- boolean clearSessionCache = false;
- boolean builtInZoomControls = false;
- boolean supportZoom = true;
- boolean databaseEnabled = false;
- boolean domStorageEnabled = false;
- boolean useWideViewPort = true;
- boolean safeBrowsingEnabled = true;
- boolean progressBar = true;
+ public boolean hideTitleBar = false;
+ public boolean closeOnCannotGoBack = true;
+ public boolean clearSessionCache = false;
+ public boolean builtInZoomControls = false;
+ public boolean supportZoom = true;
+ public boolean databaseEnabled = false;
+ public boolean domStorageEnabled = false;
+ public boolean useWideViewPort = true;
+ public boolean safeBrowsingEnabled = true;
+ public boolean progressBar = true;
+
+ public boolean useChromeCustomTabs = false;
+ public boolean CCT_addShareButton = true;
+ public boolean CCT_showTitle = true;
+ public String CCT_toolbarColor = "";
+ public boolean CCT_enableUrlBarHiding = false;
+ public boolean CCT_instantAppsEnabled = false;
public void parse(HashMap options) {
Iterator it = options.entrySet().iterator();
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
index c6ffc8a3..bb0cb85c 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/WebViewActivity.java
@@ -61,7 +61,7 @@ public class WebViewActivity extends AppCompatActivity {
}
- public void prepareWebView() {
+ private void prepareWebView() {
inAppBrowserWebChromeClient = new InAppBrowserWebChromeClient(this);
webView.setWebChromeClient(inAppBrowserWebChromeClient);
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java
new file mode 100644
index 00000000..a1ddbad7
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ChromeCustomTabsActivity.java
@@ -0,0 +1,87 @@
+package com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.customtabs.CustomTabsIntent;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+
+import com.pichillilorenzo.flutter_inappbrowser.InAppBrowserFlutterPlugin;
+import com.pichillilorenzo.flutter_inappbrowser.InAppBrowserOptions;
+import com.pichillilorenzo.flutter_inappbrowser.R;
+
+import java.util.HashMap;
+
+public class ChromeCustomTabsActivity extends Activity {
+
+ CustomTabsIntent.Builder builder;
+ InAppBrowserOptions options;
+ private CustomTabActivityHelper customTabActivityHelper;
+ private final int CHROME_CUSTOM_TAB_REQUEST_CODE = 100;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.chrome_custom_tabs_layout);
+
+ Bundle b = getIntent().getExtras();
+ String url = b.getString("url");
+
+ options = new InAppBrowserOptions();
+ options.parse((HashMap) b.getSerializable("options"));
+
+ customTabActivityHelper = new CustomTabActivityHelper();
+
+ builder = new CustomTabsIntent.Builder();
+
+ prepareCustomTabs();
+
+ CustomTabsIntent customTabsIntent = builder.build();
+
+ customTabActivityHelper.openCustomTab(this, customTabsIntent, Uri.parse(url), CHROME_CUSTOM_TAB_REQUEST_CODE,
+ new CustomTabActivityHelper.CustomTabFallback() {
+ @Override
+ public void openUri(Activity activity, Uri uri) {
+ InAppBrowserFlutterPlugin.open(uri.toString(), options);
+ }
+ });
+ }
+
+ private void prepareCustomTabs() {
+ if (options.CCT_addShareButton)
+ builder.addDefaultShareMenuItem();
+
+ if (!options.CCT_toolbarColor.isEmpty())
+ builder.setToolbarColor(Color.parseColor(options.CCT_toolbarColor));
+
+ builder.setShowTitle(options.CCT_showTitle);
+
+ if (options.CCT_enableUrlBarHiding)
+ builder.enableUrlBarHiding();
+
+ builder.setInstantAppsEnabled(options.CCT_instantAppsEnabled);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ customTabActivityHelper.bindCustomTabsService(this);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ customTabActivityHelper.unbindCustomTabsService(this);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == CHROME_CUSTOM_TAB_REQUEST_CODE) {
+ finish();
+ }
+ }
+}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java
new file mode 100644
index 00000000..c3e08e16
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabActivityHelper.java
@@ -0,0 +1,155 @@
+package com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.customtabs.CustomTabsClient;
+import android.support.customtabs.CustomTabsIntent;
+import android.support.customtabs.CustomTabsServiceConnection;
+import android.support.customtabs.CustomTabsSession;
+
+import java.util.List;
+
+import static android.support.v4.app.ActivityCompat.startActivityForResult;
+
+/**
+ * This is a helper class to manage the connection to the Custom Tabs Service.
+ */
+public class CustomTabActivityHelper implements ServiceConnectionCallback {
+ private CustomTabsSession mCustomTabsSession;
+ private CustomTabsClient mClient;
+ private CustomTabsServiceConnection mConnection;
+ private ConnectionCallback mConnectionCallback;
+
+ /**
+ * Opens the URL on a Custom Tab if possible. Otherwise fallsback to opening it on a WebView.
+ *
+ * @param activity The host activity.
+ * @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available.
+ * @param uri the Uri to be opened.
+ * @param fallback a CustomTabFallback to be used if Custom Tabs is not available.
+ */
+ public static void openCustomTab(Activity activity,
+ CustomTabsIntent customTabsIntent,
+ Uri uri,
+ int requestCode,
+ CustomTabFallback fallback) {
+ String packageName = CustomTabsHelper.getPackageNameToUse(activity);
+
+ //If we cant find a package name, it means theres no browser that supports
+ //Chrome Custom Tabs installed. So, we fallback to the webview
+ if (packageName == null) {
+ if (fallback != null) {
+ fallback.openUri(activity, uri);
+ }
+ } else {
+ customTabsIntent.intent.setPackage(packageName);
+ customTabsIntent.intent.setData(uri);
+ activity.startActivityForResult(customTabsIntent.intent, requestCode);
+ }
+ }
+
+ /**
+ * Unbinds the Activity from the Custom Tabs Service.
+ * @param activity the activity that is connected to the service.
+ */
+ public void unbindCustomTabsService(Activity activity) {
+ if (mConnection == null) return;
+ activity.unbindService(mConnection);
+ mClient = null;
+ mCustomTabsSession = null;
+ mConnection = null;
+ }
+
+ /**
+ * Creates or retrieves an exiting CustomTabsSession.
+ *
+ * @return a CustomTabsSession.
+ */
+ public CustomTabsSession getSession() {
+ if (mClient == null) {
+ mCustomTabsSession = null;
+ } else if (mCustomTabsSession == null) {
+ mCustomTabsSession = mClient.newSession(null);
+ }
+ return mCustomTabsSession;
+ }
+
+ /**
+ * Register a Callback to be called when connected or disconnected from the Custom Tabs Service.
+ * @param connectionCallback
+ */
+ public void setConnectionCallback(ConnectionCallback connectionCallback) {
+ this.mConnectionCallback = connectionCallback;
+ }
+
+ /**
+ * Binds the Activity to the Custom Tabs Service.
+ * @param activity the activity to be binded to the service.
+ */
+ public void bindCustomTabsService(Activity activity) {
+ if (mClient != null) return;
+
+ String packageName = CustomTabsHelper.getPackageNameToUse(activity);
+ if (packageName == null) return;
+
+ mConnection = new ServiceConnection(this);
+ CustomTabsClient.bindCustomTabsService(activity, packageName, mConnection);
+ }
+
+ /**
+ * @see {@link CustomTabsSession#mayLaunchUrl(Uri, Bundle, List)}.
+ * @return true if call to mayLaunchUrl was accepted.
+ */
+ public boolean mayLaunchUrl(Uri uri, Bundle extras, List otherLikelyBundles) {
+ if (mClient == null) return false;
+
+ CustomTabsSession session = getSession();
+ if (session == null) return false;
+
+ return session.mayLaunchUrl(uri, extras, otherLikelyBundles);
+ }
+
+ @Override
+ public void onServiceConnected(CustomTabsClient client) {
+ mClient = client;
+ mClient.warmup(0L);
+ if (mConnectionCallback != null) mConnectionCallback.onCustomTabsConnected();
+ }
+
+ @Override
+ public void onServiceDisconnected() {
+ mClient = null;
+ mCustomTabsSession = null;
+ if (mConnectionCallback != null) mConnectionCallback.onCustomTabsDisconnected();
+ }
+
+ /**
+ * A Callback for when the service is connected or disconnected. Use those callbacks to
+ * handle UI changes when the service is connected or disconnected.
+ */
+ public interface ConnectionCallback {
+ /**
+ * Called when the service is connected.
+ */
+ void onCustomTabsConnected();
+
+ /**
+ * Called when the service is disconnected.
+ */
+ void onCustomTabsDisconnected();
+ }
+
+ /**
+ * To be used as a fallback to open the Uri when Custom Tabs is not available.
+ */
+ public interface CustomTabFallback {
+ /**
+ *
+ * @param activity The Activity that wants to open the Uri.
+ * @param uri The uri to be opened by the fallback.
+ */
+ void openUri(Activity activity, Uri uri);
+ }
+
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabsHelper.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabsHelper.java
new file mode 100644
index 00000000..c725235d
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/CustomTabsHelper.java
@@ -0,0 +1,129 @@
+package com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.support.customtabs.CustomTabsClient;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for Custom Tabs.
+ */
+public class CustomTabsHelper {
+ private static final String TAG = "CustomTabsHelper";
+ static final String STABLE_PACKAGE = "com.android.chrome";
+ static final String BETA_PACKAGE = "com.chrome.beta";
+ static final String DEV_PACKAGE = "com.chrome.dev";
+ static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
+ private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE =
+ "android.support.customtabs.extra.KEEP_ALIVE";
+ private static final String ACTION_CUSTOM_TABS_CONNECTION =
+ "android.support.customtabs.action.CustomTabsService";
+
+ private static String sPackageNameToUse;
+
+ private CustomTabsHelper() {}
+
+ public static void addKeepAliveExtra(Context context, Intent intent) {
+ Intent keepAliveIntent = new Intent().setClassName(
+ context.getPackageName(), KeepAliveService.class.getCanonicalName());
+ intent.putExtra(EXTRA_CUSTOM_TABS_KEEP_ALIVE, keepAliveIntent);
+ }
+
+ /**
+ * Goes through all apps that handle VIEW intents and have a warmup service. Picks
+ * the one chosen by the user if there is one, otherwise makes a best effort to return a
+ * valid package name.
+ *
+ * This is not threadsafe.
+ *
+ * @param context {@link Context} to use for accessing {@link PackageManager}.
+ * @return The package name recommended to use for connecting to custom tabs related components.
+ */
+ public static String getPackageNameToUse(Context context) {
+ if (sPackageNameToUse != null) return sPackageNameToUse;
+
+ PackageManager pm = context.getPackageManager();
+ // Get default VIEW intent handler.
+ Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
+ ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
+ String defaultViewHandlerPackageName = null;
+ if (defaultViewHandlerInfo != null) {
+ defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName;
+ }
+
+ // Get all apps that can handle VIEW intents.
+ List resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
+ List packagesSupportingCustomTabs = new ArrayList<>();
+ for (ResolveInfo info : resolvedActivityList) {
+ Intent serviceIntent = new Intent();
+ serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
+ serviceIntent.setPackage(info.activityInfo.packageName);
+ if (pm.resolveService(serviceIntent, 0) != null) {
+ packagesSupportingCustomTabs.add(info.activityInfo.packageName);
+ }
+ }
+
+ // Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
+ // and service calls.
+ if (packagesSupportingCustomTabs.isEmpty()) {
+ sPackageNameToUse = null;
+ } else if (packagesSupportingCustomTabs.size() == 1) {
+ sPackageNameToUse = packagesSupportingCustomTabs.get(0);
+ } else if (!TextUtils.isEmpty(defaultViewHandlerPackageName)
+ && !hasSpecializedHandlerIntents(context, activityIntent)
+ && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) {
+ sPackageNameToUse = defaultViewHandlerPackageName;
+ } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
+ sPackageNameToUse = STABLE_PACKAGE;
+ } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
+ sPackageNameToUse = BETA_PACKAGE;
+ } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
+ sPackageNameToUse = DEV_PACKAGE;
+ } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
+ sPackageNameToUse = LOCAL_PACKAGE;
+ }
+ return sPackageNameToUse;
+ }
+
+ /**
+ * Used to check whether there is a specialized handler for a given intent.
+ * @param intent The intent to check with.
+ * @return Whether there is a specialized handler for the given intent.
+ */
+ private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ List handlers = pm.queryIntentActivities(
+ intent,
+ PackageManager.GET_RESOLVED_FILTER);
+ if (handlers == null || handlers.size() == 0) {
+ return false;
+ }
+ for (ResolveInfo resolveInfo : handlers) {
+ IntentFilter filter = resolveInfo.filter;
+ if (filter == null) continue;
+ if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue;
+ if (resolveInfo.activityInfo == null) continue;
+ return true;
+ }
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Runtime exception while getting specialized handlers");
+ }
+ return false;
+ }
+
+ /**
+ * @return All possible chrome package names that provide custom tabs feature.
+ */
+ public static String[] getPackages() {
+ return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE};
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/KeepAliveService.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/KeepAliveService.java
new file mode 100644
index 00000000..088e6b91
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/KeepAliveService.java
@@ -0,0 +1,18 @@
+package com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+/**
+ * Empty service used by the custom tab to bind to, raising the application's importance.
+ */
+public class KeepAliveService extends Service {
+ private static final Binder sBinder = new Binder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return sBinder;
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ServiceConnection.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ServiceConnection.java
new file mode 100644
index 00000000..9783b015
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ServiceConnection.java
@@ -0,0 +1,32 @@
+package com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs;
+
+import android.content.ComponentName;
+import android.support.customtabs.CustomTabsClient;
+import android.support.customtabs.CustomTabsServiceConnection;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Implementation for the CustomTabsServiceConnection that avoids leaking the
+ * ServiceConnectionCallback
+ */
+public class ServiceConnection extends CustomTabsServiceConnection {
+ // A weak reference to the ServiceConnectionCallback to avoid leaking it.
+ private WeakReference mConnectionCallback;
+
+ public ServiceConnection(ServiceConnectionCallback connectionCallback) {
+ mConnectionCallback = new WeakReference<>(connectionCallback);
+ }
+
+ @Override
+ public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
+ ServiceConnectionCallback connectionCallback = mConnectionCallback.get();
+ if (connectionCallback != null) connectionCallback.onServiceConnected(client);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ ServiceConnectionCallback connectionCallback = mConnectionCallback.get();
+ if (connectionCallback != null) connectionCallback.onServiceDisconnected();
+ }
+}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ServiceConnectionCallback.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ServiceConnectionCallback.java
new file mode 100644
index 00000000..eed768cf
--- /dev/null
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/chrome_custom_tabs/ServiceConnectionCallback.java
@@ -0,0 +1,19 @@
+package com.pichillilorenzo.flutter_inappbrowser.chrome_custom_tabs;
+
+import android.support.customtabs.CustomTabsClient;
+
+/**
+ * Callback for events when connecting and disconnecting from Custom Tabs Service.
+ */
+public interface ServiceConnectionCallback {
+ /**
+ * Called when the service is connected.
+ * @param client a CustomTabsClient
+ */
+ void onServiceConnected(CustomTabsClient client);
+
+ /**
+ * Called when the service is disconnected.
+ */
+ void onServiceDisconnected();
+}
\ No newline at end of file
diff --git a/android/src/main/res/layout/chrome_custom_tabs_layout.xml b/android/src/main/res/layout/chrome_custom_tabs_layout.xml
new file mode 100644
index 00000000..f9504c9a
--- /dev/null
+++ b/android/src/main/res/layout/chrome_custom_tabs_layout.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/android/src/main/res/values/styles.xml b/android/src/main/res/values/styles.xml
index 9e82c07e..69344ed7 100644
--- a/android/src/main/res/values/styles.xml
+++ b/android/src/main/res/values/styles.xml
@@ -3,4 +3,13 @@
+
+
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 36014547..c37771df 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -87,9 +87,10 @@ class _MyAppState extends State {
body: new Center(
child: new RaisedButton(onPressed: () {
inAppBrowser.open("https://flutter.io/", options: {
+ "useChromeCustomTabs": true,
//"hidden": true,
//"toolbarTopFixedTitle": "Fixed title",
- "useShouldOverrideUrlLoading": true
+ //"useShouldOverrideUrlLoading": true
//"hideUrlBar": true,
//"toolbarTop": false,
//"toolbarBottom": false
diff --git a/pubspec.yaml b/pubspec.yaml
index 154eae6c..131f2fdb 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: flutter_inappbrowser
description: A Flutter plugin that allows you to open an in-app browser window. (inspired by the popular cordova-plugin-inappbrowser).
-version: 0.1.0
+version: 0.1.1
author: Lorenzo Pichilli
homepage: https://github.com/pichillilorenzo/flutter_inappbrowser