0
0
mirror of https://github.com/ankidroid/Anki-Android.git synced 2024-09-20 12:02:16 +02:00

[Kotlin Migration] CustomTabActivityHelper

This commit is contained in:
Akshay 2022-01-10 23:23:41 +05:30 committed by Mike Hardy
parent 3359678588
commit 1ad753659d
2 changed files with 112 additions and 122 deletions

View File

@ -43,7 +43,7 @@ permission notice:
// Example of class name: "/com/ichi2/anki/UIUtils.kt"
// Ensure that it starts with '/' (slash)
def source = Source.MAIN
def className = "/com/ichi2/compat/customtabs/CustomTabActivityHelper.kt"
def className = ""
enum Source {
MAIN("/src/main/java"),

View File

@ -12,77 +12,38 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.ichi2.compat.customtabs
package com.ichi2.compat.customtabs;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.CheckResult;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.browser.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.browser.customtabs.CustomTabsServiceConnection;
import androidx.browser.customtabs.CustomTabsSession;
import java.util.List;
import timber.log.Timber;
import android.app.Activity
import android.net.Uri
import android.os.Bundle
import androidx.annotation.CheckResult
import androidx.annotation.VisibleForTesting
import androidx.browser.customtabs.CustomTabsClient
import androidx.browser.customtabs.CustomTabsIntent
import androidx.browser.customtabs.CustomTabsServiceConnection
import androidx.browser.customtabs.CustomTabsSession
import com.ichi2.utils.KotlinCleanup
import timber.log.Timber
/**
* This is a helper class to manage the connection to the Custom Tabs Service.
*/
public class CustomTabActivityHelper implements ServiceConnectionCallback {
private static boolean sCustomTabsFailed = false;
@Nullable
private CustomTabsSession mCustomTabsSession;
@Nullable
private CustomTabsClient mClient;
@Nullable
private CustomTabsServiceConnection mConnection;
/**
* 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(@NonNull Activity activity,
CustomTabsIntent customTabsIntent,
Uri uri,
CustomTabFallback fallback) {
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
//If we cant find a package name or there was a serious failure during init, we don't support
//Chrome Custom Tabs. So, we fallback to the webview
if (packageName == null || sCustomTabsFailed) {
if (fallback != null) {
fallback.openUri(activity, uri);
} else {
Timber.e("A version of Chrome supporting custom tabs was not available, and the fallback was null");
}
} else {
customTabsIntent.intent.setPackage(packageName);
customTabsIntent.launchUrl(activity, uri);
}
}
class CustomTabActivityHelper : ServiceConnectionCallback {
private var mCustomTabsSession: CustomTabsSession? = null
private var mClient: CustomTabsClient? = null
private var mConnection: CustomTabsServiceConnection? = null
/**
* 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;
fun unbindCustomTabsService(activity: Activity) {
if (mConnection == null) return
mConnection.let { activity.unbindService(it!!) }
mClient = null
mCustomTabsSession = null
mConnection = null
}
/**
@ -90,103 +51,132 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
*
* @return a CustomTabsSession.
*/
public CustomTabsSession getSession() {
if (mClient == null) {
mCustomTabsSession = null;
} else if (mCustomTabsSession == null) {
mCustomTabsSession = mClient.newSession(null);
val session: CustomTabsSession?
get() {
if (mClient == null) {
mCustomTabsSession = null
} else if (mCustomTabsSession == null) {
mCustomTabsSession = mClient!!.newSession(null)
}
return mCustomTabsSession
}
return mCustomTabsSession;
}
/**
* 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);
@KotlinCleanup("make activity nonnull")
fun bindCustomTabsService(activity: Activity?) {
if (mClient != null) return
val packageName = CustomTabsHelper.getPackageNameToUse(activity) ?: return
mConnection = ServiceConnection(this)
try {
CustomTabsClient.bindCustomTabsService(activity, packageName, mConnection);
} catch (SecurityException e) {
Timber.w(e, "CustomTabsService bind attempt failed, using fallback");
disableCustomTabHandler();
CustomTabsClient.bindCustomTabsService(activity!!, packageName, mConnection!!)
} catch (e: SecurityException) {
Timber.w(e, "CustomTabsService bind attempt failed, using fallback")
disableCustomTabHandler()
}
}
private void disableCustomTabHandler() {
Timber.i("Disabling custom tab handler and using fallback");
sCustomTabsFailed = true;
mClient = null;
mCustomTabsSession = null;
mConnection = null;
private fun disableCustomTabHandler() {
Timber.i("Disabling custom tab handler and using fallback")
sCustomTabsFailed = true
mClient = null
mCustomTabsSession = null
mConnection = null
}
/**
* @see {@link CustomTabsSession#mayLaunchUrl(Uri, Bundle, List)}.
* @return true if call to mayLaunchUrl was accepted.
*/
public boolean mayLaunchUrl(Uri uri, Bundle extras, List<Bundle> otherLikelyBundles) {
if (mClient == null) return false;
CustomTabsSession session = getSession();
if (session == null) return false;
return session.mayLaunchUrl(uri, extras, otherLikelyBundles);
fun mayLaunchUrl(uri: Uri?, extras: Bundle?, otherLikelyBundles: List<Bundle?>?): Boolean {
if (mClient == null) return false
val session = session ?: return false
return session.mayLaunchUrl(uri, extras, otherLikelyBundles)
}
@Override
public void onServiceConnected(CustomTabsClient client) {
override fun onServiceConnected(client: CustomTabsClient) {
try {
mClient = client;
mClient = client
try {
mClient.warmup(0L);
} catch (IllegalStateException e) {
mClient!!.warmup(0L)
} catch (e: IllegalStateException) {
// Issue 5337 - some browsers like TorBrowser don't adhere to Android 8 background limits
// They will crash as they attempt to start services. warmup failure shouldn't be fatal though.
Timber.w(e, "Ignoring CustomTabs implementation that doesn't conform to Android 8 background limits");
Timber.w(e, "Ignoring CustomTabs implementation that doesn't conform to Android 8 background limits")
}
getSession();
} catch (SecurityException e) {
//#6142 - A securityException here means that we're not able to load the CustomTabClient at all, whereas
//the IllegalStateException was a failure, but could be continued from
Timber.w(e, "CustomTabsService bind attempt failed, using fallback");
disableCustomTabHandler();
session
} catch (e: SecurityException) {
// #6142 - A securityException here means that we're not able to load the CustomTabClient at all, whereas
// the IllegalStateException was a failure, but could be continued from
Timber.w(e, "CustomTabsService bind attempt failed, using fallback")
disableCustomTabHandler()
}
}
@Override
public void onServiceDisconnected() {
mClient = null;
mCustomTabsSession = null;
override fun onServiceDisconnected() {
mClient = null
mCustomTabsSession = null
}
/**
* To be used as a fallback to open the Uri when Custom Tabs is not available.
*/
public interface CustomTabFallback {
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);
@KotlinCleanup("make activity nonnull")
fun openUri(activity: Activity?, uri: Uri?)
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE) @CheckResult
boolean isFailed() {
return sCustomTabsFailed && mClient == null;
}
@get:CheckResult
@get:VisibleForTesting(otherwise = VisibleForTesting.NONE)
val isFailed: Boolean
get() = sCustomTabsFailed && mClient == null
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
public static void resetFailed() {
sCustomTabsFailed = false;
companion object {
private var sCustomTabsFailed = false
/**
* 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.
*/
@KotlinCleanup("Consider nullability")
@JvmStatic
fun openCustomTab(
activity: Activity,
customTabsIntent: CustomTabsIntent?,
uri: Uri?,
fallback: CustomTabFallback?
) {
val packageName = CustomTabsHelper.getPackageNameToUse(activity)
// If we cant find a package name or there was a serious failure during init, we don't support
// Chrome Custom Tabs. So, we fallback to the webview
if (packageName == null || sCustomTabsFailed) {
if (fallback != null) {
fallback.openUri(activity, uri)
} else {
Timber.e("A version of Chrome supporting custom tabs was not available, and the fallback was null")
}
} else {
customTabsIntent!!.intent.setPackage(packageName)
customTabsIntent.launchUrl(activity, uri!!)
}
}
@JvmStatic
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun resetFailed() {
sCustomTabsFailed = false
}
}
}
}