🛃 Launch CCT on Null Session.

This is an upstream of this fix:
  https://github.com/GoogleChrome/android-browser-helper/commit/451e37ebaaf1cb6d132b2bba363951f461f1cb2f

Bug: 988346
Change-Id: I8e9d1eed51fd445cdef1e7f83776e1d437814028
Reviewed-on: https://chromium-review.googlesource.com/c/custom-tabs-client/+/1844173
Reviewed-by: Peter Conn <peconn@chromium.org>
Commit-Queue: Peter Conn <peconn@chromium.org>
diff --git a/customtabs/src/android/support/customtabs/trusted/TwaLauncher.java b/customtabs/src/android/support/customtabs/trusted/TwaLauncher.java
index 0fcaab2..6695a9c 100644
--- a/customtabs/src/android/support/customtabs/trusted/TwaLauncher.java
+++ b/customtabs/src/android/support/customtabs/trusted/TwaLauncher.java
@@ -54,9 +54,6 @@
     @Nullable
     private CustomTabsSession mSession;
 
-    @Nullable
-    private Runnable mOnSessionCreatedRunnable;
-
     private boolean mDestroyed;
 
     /**
@@ -151,17 +148,28 @@
 
         Runnable onSessionCreatedRunnable = () ->
                 launchWhenSessionEstablished(twaBuilder, splashScreenStrategy, completionCallback);
+
         if (mSession != null) {
             onSessionCreatedRunnable.run();
             return;
         }
 
-        mOnSessionCreatedRunnable = onSessionCreatedRunnable;
+        Runnable onSessionCreationFailedRunnable = () -> {
+            // The provider has been unable to create a session for us, we can't launch a
+            // Trusted Web Activity. We could either exit, forcing the user to try again,
+            // hopefully successfully this time or we could launch a Custom Tab giving the user
+            // a subpar experience (compared to a TWA).
+            // We'll open in a CCT, but pay attention to what users want.
+            launchCct(twaBuilder, completionCallback);
+        };
+
         if (mServiceConnection == null) {
             mServiceConnection = new TwaCustomTabsServiceConnection();
         }
-        CustomTabsClient.bindCustomTabsService(mContext, mProviderPackage,
-                mServiceConnection);
+
+        mServiceConnection.setSessionCreationRunnables(
+                onSessionCreatedRunnable, onSessionCreationFailedRunnable);
+        CustomTabsClient.bindCustomTabsService(mContext, mProviderPackage, mServiceConnection);
     }
 
     private void launchWhenSessionEstablished(TrustedWebActivityIntentBuilder twaBuilder,
@@ -211,6 +219,15 @@
     }
 
     private class TwaCustomTabsServiceConnection extends CustomTabsServiceConnection {
+        private Runnable mOnSessionCreatedRunnable;
+        private Runnable mOnSessionCreationFailedRunnable;
+
+        private void setSessionCreationRunnables(@Nullable Runnable onSuccess,
+                @Nullable Runnable onFailure) {
+            mOnSessionCreatedRunnable = onSuccess;
+            mOnSessionCreationFailedRunnable = onFailure;
+        }
+
         @Override
         public void onCustomTabsServiceConnected(ComponentName componentName,
                 CustomTabsClient client) {
@@ -218,10 +235,15 @@
                 client.warmup(0);
             }
             mSession = client.newSession(null, mSessionId);
-            if (mOnSessionCreatedRunnable != null) {
+
+            if (mSession != null && mOnSessionCreatedRunnable != null) {
                 mOnSessionCreatedRunnable.run();
-                mOnSessionCreatedRunnable = null;
+            } else if (mSession == null && mOnSessionCreationFailedRunnable != null) {
+                mOnSessionCreationFailedRunnable.run();
             }
+
+            mOnSessionCreatedRunnable = null;
+            mOnSessionCreationFailedRunnable = null;
         }
 
         @Override