chromium/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionServiceImpl.java

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.customtabs;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsService;
import androidx.browser.customtabs.CustomTabsSessionToken;
import androidx.browser.customtabs.EngagementSignalsCallback;
import androidx.browser.customtabs.PrefetchOptions;

import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
import org.chromium.chrome.browser.init.ProcessInitializationHandler;
import org.chromium.components.embedder_support.util.Origin;

import java.util.List;

/** Custom tabs connection service, used by the embedded Chrome activities. */
public class CustomTabsConnectionServiceImpl extends CustomTabsConnectionService.Impl {
    private CustomTabsConnection mConnection;
    private Intent mBindIntent;

    @Override
    public void onCreate() {
        ProcessInitializationHandler.getInstance().initializePreNative();
        // Kick off the first access to avoid random StrictMode violations in clients.
        RequestThrottler.loadInBackground();
        super.onCreate();
    }

    @Override
    public void onBind(Intent intent) {
        mBindIntent = intent;
        mConnection = CustomTabsConnection.getInstance();
        mConnection.logCall("Service#onBind()", true);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        super.onUnbind(intent);
        if (mConnection != null) mConnection.logCall("Service#onUnbind()", true);
        return false; // No support for onRebind().
    }

    @Override
    protected boolean warmup(long flags) {
        if (!isFirstRunDone()) return false;
        return mConnection.warmup(flags);
    }

    @Override
    protected boolean newSession(CustomTabsSessionToken sessionToken) {
        return mConnection.newSession(sessionToken);
    }

    @Override
    protected boolean mayLaunchUrl(
            CustomTabsSessionToken sessionToken,
            Uri url,
            Bundle extras,
            List<Bundle> otherLikelyBundles) {
        if (!isFirstRunDone()) return false;
        return mConnection.mayLaunchUrl(sessionToken, url, extras, otherLikelyBundles);
    }

    @Override
    @androidx.browser.customtabs.ExperimentalPrefetch
    protected void prefetch(CustomTabsSessionToken sessionToken, Uri uri, PrefetchOptions options) {
        if (!isFirstRunDone()) return;
        mConnection.prefetch(sessionToken, uri, options);
    }

    @Override
    protected Bundle extraCommand(String commandName, Bundle args) {
        return mConnection.extraCommand(commandName, args);
    }

    @Override
    protected boolean updateVisuals(CustomTabsSessionToken sessionToken, Bundle bundle) {
        if (!isFirstRunDone()) return false;
        return mConnection.updateVisuals(sessionToken, bundle);
    }

    @Override
    protected boolean requestPostMessageChannel(
            CustomTabsSessionToken sessionToken,
            Uri postMessageSourceOrigin,
            @Nullable Uri postMessageTargetOrigin) {
        Origin sourceOrigin = Origin.create(postMessageSourceOrigin);
        if (sourceOrigin == null) return false;
        return mConnection.requestPostMessageChannel(
                sessionToken, sourceOrigin, Origin.create(postMessageTargetOrigin));
    }

    @Override
    protected int postMessage(CustomTabsSessionToken sessionToken, String message, Bundle extras) {
        if (!isFirstRunDone()) return CustomTabsService.RESULT_FAILURE_DISALLOWED;
        return mConnection.postMessage(sessionToken, message, extras);
    }

    @Override
    protected boolean validateRelationship(
            CustomTabsSessionToken sessionToken, int relation, Uri originAsUri, Bundle extras) {
        Origin origin = Origin.create(originAsUri);
        if (origin == null) return false;
        return mConnection.validateRelationship(sessionToken, relation, origin, extras);
    }

    @Override
    protected void cleanUpSession(CustomTabsSessionToken sessionToken) {
        mConnection.cleanUpSession(sessionToken);
    }

    @Override
    protected boolean receiveFile(
            @NonNull CustomTabsSessionToken sessionToken,
            @NonNull Uri uri,
            int purpose,
            @Nullable Bundle extras) {
        return mConnection.receiveFile(sessionToken, uri, purpose, extras);
    }

    @Override
    protected boolean isEngagementSignalsApiAvailable(
            CustomTabsSessionToken sessionToken, Bundle extras) {
        return mConnection.isEngagementSignalsApiAvailable(sessionToken, extras);
    }

    @Override
    protected boolean setEngagementSignalsCallback(
            CustomTabsSessionToken sessionToken,
            EngagementSignalsCallback callback,
            Bundle extras) {
        return mConnection.setEngagementSignalsCallback(sessionToken, callback, extras);
    }

    private boolean isFirstRunDone() {
        if (mBindIntent == null) return true;
        boolean firstRunNecessary = FirstRunFlowSequencer.checkIfFirstRunIsNecessary(false, true);
        if (!firstRunNecessary) {
            mBindIntent = null;
            return true;
        }
        return false;
    }
}