chromium/components/download/network/android/java/src/org/chromium/components/download/BackgroundNetworkStatusListener.java

// Copyright 2021 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.components.download;

import android.os.Handler;

import androidx.annotation.VisibleForTesting;

import org.chromium.base.ThreadUtils;
import org.chromium.net.ConnectionType;
import org.chromium.net.NetworkChangeNotifierAutoDetect;
import org.chromium.net.RegistrationPolicyAlwaysRegister;

/**
 * Network listener that can notify network connectivity changes based on chromium network API.
 *
 * This object lives and must be used on background threads.
 */
class BackgroundNetworkStatusListener implements NetworkChangeNotifierAutoDetect.Observer {
    private final NetworkChangeNotifierAutoDetect mNotifier;
    private static AutoDetectFactory sAutoDetectFactory = new AutoDetectFactory();

    // An observer to receive network events on main thread.
    private final Observer mObserver;
    private Handler mMainThreadHandler = new Handler(ThreadUtils.getUiThreadLooper());

    /** Observer interface to receive network change events on the main thread. */
    interface Observer {
        /**
         * Called when {@link BackgroundNetworkStatusListener} is initialized on background thread.
         * @param connectionType
         */
        void onNetworkStatusReady(@ConnectionType int connectionType);

        /**
         * Called when connection type is changed.
         * @param newConnectionType The new connection type.
         */
        void onConnectionTypeChanged(@ConnectionType int newConnectionType);
    }

    /**
     * Creates the NetworkChangeNotifierAutoDetect used in this class. Included so that tests
     * can override it.
     */
    @VisibleForTesting
    public static class AutoDetectFactory {
        public NetworkChangeNotifierAutoDetect create(
                NetworkChangeNotifierAutoDetect.Observer observer,
                NetworkChangeNotifierAutoDetect.RegistrationPolicy policy) {
            return new NetworkChangeNotifierAutoDetect(observer, policy);
        }
    }

    @VisibleForTesting
    public static void setAutoDetectFactory(AutoDetectFactory factory) {
        sAutoDetectFactory = factory;
    }

    BackgroundNetworkStatusListener(Observer observer) {
        ThreadUtils.assertOnBackgroundThread();
        mObserver = observer;

        // Register policy that can fire network change events when the application is in the
        // background.
        mNotifier = sAutoDetectFactory.create(this, new RegistrationPolicyAlwaysRegister());

        // Update the connection type immediately on main thread.
        @ConnectionType int connectionType = getCurrentConnectionType();
        runOnMainThread(
                () -> {
                    mObserver.onNetworkStatusReady(connectionType);
                });
    }

    @ConnectionType
    int getCurrentConnectionType() {
        ThreadUtils.assertOnBackgroundThread();
        assert mNotifier != null;

        // TODO(crbug.com/40936429): remove this call if it is not necessary.
        mNotifier.updateCurrentNetworkState();
        return mNotifier.getCurrentNetworkState().getConnectionType();
    }

    void unRegister() {
        ThreadUtils.assertOnBackgroundThread();
        assert mNotifier != null;
        mNotifier.unregister();
    }

    private void runOnMainThread(Runnable runnable) {
        ThreadUtils.assertOnBackgroundThread();
        mMainThreadHandler.post(runnable);
    }

    /** {@link NetworkChangeNotifierAutoDetect.Observer} implementation. */
    @Override
    public void onConnectionTypeChanged(int newConnectionType) {
        runOnMainThread(
                () -> {
                    mObserver.onConnectionTypeChanged(newConnectionType);
                });
    }

    @Override
    public void onConnectionCostChanged(int newConnectionCost) {}

    @Override
    public void onConnectionSubtypeChanged(int newConnectionSubtype) {}

    @Override
    public void onNetworkConnect(long netId, int connectionType) {}

    @Override
    public void onNetworkSoonToDisconnect(long netId) {}

    @Override
    public void onNetworkDisconnect(long netId) {}

    @Override
    public void purgeActiveNetworkList(long[] activeNetIds) {}
}