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