chromium/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java

// Copyright 2020 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.feed;

import android.content.Context;
import android.util.DisplayMetrics;

import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace;
import org.jni_zero.NativeClassQualifiedName;
import org.jni_zero.NativeMethods;

import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.feed.v2.ContentOrder;
import org.chromium.chrome.browser.feed.v2.FeedUserActionType;
import org.chromium.chrome.browser.xsurface.ImageCacheHelper;
import org.chromium.chrome.browser.xsurface.ProcessScope;
import org.chromium.chrome.browser.xsurface_provider.XSurfaceProcessScopeProvider;

import java.util.Locale;

/** Bridge for FeedService-related calls. */
@JNINamespace("feed")
public final class FeedServiceBridge {
    // Access to JNI test hooks for other libraries. This can go away once more Feed code is
    // migrated to chrome/browser/feed.
    public static org.jni_zero.JniStaticTestMocker<FeedServiceBridge.Natives>
            getTestHooksForTesting() {
        return FeedServiceBridgeJni.TEST_HOOKS;
    }

    public static ProcessScope xSurfaceProcessScope() {
        return XSurfaceProcessScopeProvider.getProcessScope();
    }

    public static boolean isEnabled() {
        return FeedServiceBridgeJni.get().isEnabled();
    }

    /** Returns the top user specified locale. */
    private static Locale getLocale(Context context) {
        return context.getResources().getConfiguration().getLocales().get(0);
    }

    // Java functionality needed for the native FeedService.
    @CalledByNative
    public static String getLanguageTag() {
        return getLocale(ContextUtils.getApplicationContext()).toLanguageTag();
    }

    @CalledByNative
    public static double[] getDisplayMetrics() {
        DisplayMetrics metrics =
                ContextUtils.getApplicationContext().getResources().getDisplayMetrics();
        double[] result = {metrics.density, metrics.widthPixels, metrics.heightPixels};
        return result;
    }

    @CalledByNative
    public static void clearAll() {
        FeedSurfaceTracker.getInstance().clearAll();
    }

    @CalledByNative
    public static void prefetchImage(String url) {
        ProcessScope processScope = xSurfaceProcessScope();
        if (processScope != null) {
            ImageCacheHelper imageCacheHelper = processScope.provideImageCacheHelper();
            if (imageCacheHelper != null) {
                imageCacheHelper.prefetchImage(url);
            }
        }
    }

    /** Called at startup to trigger creation of |FeedService|. */
    public static void startup() {
        FeedServiceBridgeJni.get().startup();
    }

    /** Retrieves the config value for load_more_trigger_lookahead. */
    public static int getLoadMoreTriggerLookahead() {
        return FeedServiceBridgeJni.get().getLoadMoreTriggerLookahead();
    }

    /** Retrieves the config value for load_more_trigger_scroll_distance_dp. */
    public static int getLoadMoreTriggerScrollDistanceDp() {
        return FeedServiceBridgeJni.get().getLoadMoreTriggerScrollDistanceDp();
    }

    public static long getReliabilityLoggingId() {
        return FeedServiceBridgeJni.get().getReliabilityLoggingId();
    }

    public static @ContentOrder int getContentOrderForWebFeed() {
        return FeedServiceBridgeJni.get().getContentOrderForWebFeed();
    }

    public static void setContentOrderForWebFeed(@ContentOrder int contentOrder) {
        FeedServiceBridgeJni.get().setContentOrderForWebFeed(contentOrder);
    }

    /**
     * Reports that a user action occurred which is untied to a Feed tab. Use
     * FeedStream.reportOtherUserAction for stream-specific actions.
     */
    public static void reportOtherUserAction(
            @StreamKind int streamKind, @FeedUserActionType int userAction) {
        FeedServiceBridgeJni.get().reportOtherUserAction(streamKind, userAction);
    }

    /**
     * @return True if the user is signed in for feed purposes (i.e. if a personalized feed can be
     *         requested).
     */
    public static boolean isSignedIn() {
        return FeedServiceBridgeJni.get().isSignedIn();
    }

    /** Observes whether or not the Feed stream contains unread content */
    public static class UnreadContentObserver {
        private long mNativePtr;

        /**
         * Begins observing.
         *
         * @param isWebFeed  Whether to observe the Web Feed, or the For-you Feed.
         */
        public UnreadContentObserver(boolean isWebFeed) {
            mNativePtr = FeedServiceBridgeJni.get().addUnreadContentObserver(this, isWebFeed);
        }

        /** Stops observing. Must be called when this observer is no longer needed */
        public void destroy() {
            FeedServiceBridgeJni.get().destroy(mNativePtr);
            mNativePtr = 0;
        }

        /**
         * Called to signal whether unread content is available. Called once after the observer is
         * initialized, and after that, called each time unread content status changes.
         */
        @CalledByNative("UnreadContentObserver")
        public void hasUnreadContentChanged(boolean hasUnreadContent) {}
    }

    @NativeMethods
    public interface Natives {
        boolean isEnabled();

        void startup();

        int getLoadMoreTriggerLookahead();

        int getLoadMoreTriggerScrollDistanceDp();

        long getReliabilityLoggingId();

        void reportOtherUserAction(@StreamKind int streamKind, @FeedUserActionType int userAction);

        @ContentOrder
        int getContentOrderForWebFeed();

        void setContentOrderForWebFeed(@ContentOrder int contentOrder);

        long addUnreadContentObserver(Object object, boolean isWebFeed);

        boolean isSignedIn();

        @NativeClassQualifiedName("feed::JavaUnreadContentObserver")
        void destroy(long nativePtr);
    }
}