Skip to content

Instantly share code, notes, and snippets.

@Asutosh11
Last active March 10, 2021 08:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Asutosh11/098e2e3c62e26dd79935777665d7c121 to your computer and use it in GitHub Desktop.
Save Asutosh11/098e2e3c62e26dd79935777665d7c121 to your computer and use it in GitHub Desktop.
Android: Open a web page in chrome custom tabs and also show a custom native view on top of it
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/btn_xml"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="8dp"
android:text="just a button"
android:textColor="#fff"
android:background="#31adad"
/>
</LinearLayout>
package com.asutosh.trials
import `in`.novopay.los.ui.offlinekyc.WebViewActivity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.text.TextUtils
import android.widget.RemoteViews
import androidx.browser.customtabs.CustomTabsIntent
import androidx.browser.customtabs.CustomTabsService
class CustomTabHelper {
var sPackageNameToUse: String? = null
val STABLE_PACKAGE = "com.android.chrome"
val BETA_PACKAGE = "com.chrome.beta"
val DEV_PACKAGE = "com.chrome.dev"
val LOCAL_PACKAGE = "com.google.android.apps.chrome"
/** @context: context of the activity or application context
* @url: the url to open in the chrome custom tab
* @pendingIntent: the intent that will be fired on clicking on the custom view on the chrome custom tab
* @packageName: package name from where the chrome custom tab is loaded
* @customXmlLayout: XML layout, where the custom native view to be shown on the chrome custom tab is
* @idOfCustomView: id of the custom native view to be shown on the chrome custom tab
*/
fun loadCustomChromeTab(
context: Context,
url: String,
pendingIntent: PendingIntent,
packageName: String,
customXmlLayout: Int,
idOfCustomView: Int) {
val builder = CustomTabsIntent.Builder()
// this view will be placed as a native view on the webpage loaded on chrome custom tab
val remoteViews = RemoteViews(packageName, customXmlLayout)
builder.setSecondaryToolbarViews(
remoteViews,
intArrayOf(idOfCustomView),
pendingIntent
)
val customTabsIntent = builder.build()
val packageName = getPackageNameToUse(context, url)
if (packageName == null) {
// if chrome not available open in web view
val intentOpenUri = Intent(context, WebViewActivity::class.java)
intentOpenUri.putExtra(WebViewActivity.EXTRA_URL, Uri.parse(url).toString())
context.startActivity(intentOpenUri)
} else {
// open in chrome custom tab
customTabsIntent.intent.setPackage(packageName)
customTabsIntent.launchUrl(context, Uri.parse(url))
}
}
fun getPackageNameToUse(context: Context, url: String): String? {
sPackageNameToUse?.let {
return it
}
val pm = context.getPackageManager()
val activityIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
val defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0)
var defaultViewHandlerPackageName: String? = null
defaultViewHandlerInfo?.let {
defaultViewHandlerPackageName = it.activityInfo.packageName
}
val resolvedActivityList = pm.queryIntentActivities(activityIntent, 0)
val packagesSupportingCustomTabs = ArrayList<String>()
for (info in resolvedActivityList) {
val serviceIntent = Intent()
serviceIntent.action = CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION
serviceIntent.setPackage(info.activityInfo.packageName)
pm.resolveService(serviceIntent, 0)?.let {
packagesSupportingCustomTabs.add(info.activityInfo.packageName)
}
}
when {
packagesSupportingCustomTabs.isEmpty() -> sPackageNameToUse = null
packagesSupportingCustomTabs.size == 1 -> sPackageNameToUse =
packagesSupportingCustomTabs.get(0)
!TextUtils.isEmpty(defaultViewHandlerPackageName)
&& !hasSpecializedHandlerIntents(context, activityIntent)
&& packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName) ->
sPackageNameToUse = defaultViewHandlerPackageName
packagesSupportingCustomTabs.contains(STABLE_PACKAGE) -> sPackageNameToUse =
STABLE_PACKAGE
packagesSupportingCustomTabs.contains(BETA_PACKAGE) -> sPackageNameToUse = BETA_PACKAGE
packagesSupportingCustomTabs.contains(DEV_PACKAGE) -> sPackageNameToUse = DEV_PACKAGE
packagesSupportingCustomTabs.contains(LOCAL_PACKAGE) -> sPackageNameToUse =
LOCAL_PACKAGE
}
return sPackageNameToUse
}
private fun hasSpecializedHandlerIntents(context: Context, intent: Intent): Boolean {
try {
val pm = context.getPackageManager()
val handlers = pm.queryIntentActivities(
intent,
PackageManager.GET_RESOLVED_FILTER
)
if (handlers == null || handlers.size == 0) {
return false
}
for (resolveInfo in handlers) {
val filter = resolveInfo.filter ?: continue
if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue
if (resolveInfo.activityInfo == null) continue
return true
}
} catch (e: RuntimeException) {
}
return false
}
}
val intent = Intent(applicationContext, FileChooserActivity::class.java)
val pendingIntent = PendingIntent.getActivity(applicationContext, 106, intent, PendingIntent.FLAG_UPDATE_CURRENT)
CustomTabHelper().loadCustomChromeTab(
this,
"http://example.com/",
pendingIntent,
packageName!!,
R.layout.custom_layout,
R.id.btn_xml)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment