com.twitter.sdk.android.core.internal.scribe.DefaultScribeClient.java Source code

Java tutorial

Introduction

Here is the source code for com.twitter.sdk.android.core.internal.scribe.DefaultScribeClient.java

Source

/*
 * Copyright (C) 2015 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * 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.twitter.sdk.android.core.internal.scribe;

import android.os.Build;
import android.text.TextUtils;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.twitter.sdk.android.core.BuildConfig;
import com.twitter.sdk.android.core.Session;
import com.twitter.sdk.android.core.SessionManager;
import com.twitter.sdk.android.core.TwitterCore;
import com.twitter.sdk.android.core.TwitterSession;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;

import io.fabric.sdk.android.Kit;
import io.fabric.sdk.android.services.common.ExecutorUtils;
import io.fabric.sdk.android.services.common.IdManager;
import io.fabric.sdk.android.services.settings.Settings;
import io.fabric.sdk.android.services.settings.SettingsData;

/**
 * Instances of this class should always be created on a background thread.
 */
public class DefaultScribeClient extends ScribeClient {
    /*
     * We are using the syndication backend for all scribing until there is a separate schema and
     * category for other Fabric events.
     */
    private static final String SCRIBE_URL = "https://syndication.twitter.com";
    private static final String SCRIBE_PATH_VERSION = "i";
    private static final String SCRIBE_PATH_TYPE = "sdk";

    private static final String DEBUG_BUILD = "debug";

    private static volatile ScheduledExecutorService executor;

    private final Kit kit;
    private final List<SessionManager<? extends Session>> sessionManagers;
    private final String advertisingId;

    public DefaultScribeClient(Kit kit, String kitName, List<SessionManager<? extends Session>> sessionManagers,
            IdManager idManager) {
        this(kit, kitName, getGson(), sessionManagers, idManager);
    }

    DefaultScribeClient(Kit kit, String kitName, Gson gson, List<SessionManager<? extends Session>> sessionManagers,
            IdManager idManager) {
        super(kit, getExecutor(),
                getScribeConfig(Settings.getInstance().awaitSettingsData(), getUserAgent(kitName, kit)),
                new ScribeEvent.Transform(gson), TwitterCore.getInstance().getAuthConfig(), sessionManagers,
                TwitterCore.getInstance().getSSLSocketFactory(), idManager);

        this.sessionManagers = sessionManagers;
        this.kit = kit;
        this.advertisingId = idManager.getAdvertisingId();
    }

    public void scribe(EventNamespace... namespaces) {
        for (EventNamespace ns : namespaces) {
            scribe(ns, Collections.<ScribeItem>emptyList());
        }
    }

    public void scribe(EventNamespace namespace, List<ScribeItem> items) {
        final String language = getLanguageFromKit();
        final long timestamp = System.currentTimeMillis();
        /*
         * The advertising ID may be null if this method is called before doInBackground completes.
         * It also may be null depending on the users preferences and if Google Play Services has
         * been installed on the device.
         */
        scribe(ScribeEventFactory.newScribeEvent(namespace, "", timestamp, language, advertisingId, items));
    }

    public void scribe(ScribeEvent event) {
        super.scribe(event, getScribeSessionId(getActiveSession()));
    }

    public void scribe(EventNamespace namespace, String eventInfo) {
        final String language = getLanguageFromKit();
        final long timestamp = System.currentTimeMillis();
        /*
         * The advertising ID may be null if this method is called before doInBackground completes.
         * It also may be null depending on the users preferences and if Google Play Services has
         * been installed on the device.
         */
        scribe(ScribeEventFactory.newScribeEvent(namespace, eventInfo, timestamp, language, advertisingId,
                Collections.<ScribeItem>emptyList()));
    }

    // visible for tests
    Session getActiveSession() {
        Session session = null;
        for (SessionManager<? extends Session> sessionManager : sessionManagers) {
            session = sessionManager.getActiveSession();
            if (session != null) {
                break;
            }
        }
        return session;
    }

    // visible for tests
    long getScribeSessionId(Session activeSession) {
        final long scribeSessionId;
        if (activeSession != null) {
            scribeSessionId = activeSession.getId();
        } else {
            // It's possible that we're attempting to load a tweet before we have a valid
            // session. Store the scribe event locally with the logged out user id so that we can
            // send it up at a later time with the logged out session.
            scribeSessionId = TwitterSession.LOGGED_OUT_USER_ID;
        }
        return scribeSessionId;
    }

    private String getLanguageFromKit() {
        final String language;
        if (kit.getContext() != null) {
            language = kit.getContext().getResources().getConfiguration().locale.getLanguage();
        } else {
            language = "";
        }
        return language;
    }

    private static Gson getGson() {
        return new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
    }

    private static ScheduledExecutorService getExecutor() {
        if (executor == null) {
            synchronized (DefaultScribeClient.class) {
                if (executor == null) {
                    executor = ExecutorUtils.buildSingleThreadScheduledExecutorService("scribe");
                }
            }
        }
        return executor;
    }

    static ScribeConfig getScribeConfig(SettingsData settingsData, String userAgent) {
        // Get scribe configuration using analytics settings, which is used by crashlytics for
        // configuring Answers. This is temporary until we have can get our scribe settings from the
        // backend. If analytics settings are not available, fallback to defaults.
        final int maxFilesToKeep;
        final int sendIntervalSeconds;
        if (settingsData != null && settingsData.analyticsSettingsData != null) {
            maxFilesToKeep = settingsData.analyticsSettingsData.maxPendingSendFileCount;
            sendIntervalSeconds = settingsData.analyticsSettingsData.flushIntervalSeconds;
        } else {
            maxFilesToKeep = ScribeConfig.DEFAULT_MAX_FILES_TO_KEEP;
            sendIntervalSeconds = ScribeConfig.DEFAULT_SEND_INTERVAL_SECONDS;
        }

        final String scribeUrl = getScribeUrl(SCRIBE_URL, BuildConfig.SCRIBE_ENDPOINT_OVERRIDE);
        return new ScribeConfig(isEnabled(), scribeUrl, SCRIBE_PATH_VERSION, SCRIBE_PATH_TYPE,
                BuildConfig.SCRIBE_SEQUENCE, userAgent, maxFilesToKeep, sendIntervalSeconds);
    }

    /*
     * This method serves to disable the scribe strategy in testing, it causes massive memory leaks
     * that are not easily cleaned up unless we have a teardown method added to the kit class
     * interface.
     */
    private static boolean isEnabled() {
        return !BuildConfig.BUILD_TYPE.equals(DEBUG_BUILD);
    }

    static String getUserAgent(String kitName, Kit kit) {
        return new StringBuilder().append("Fabric/").append(kit.getFabric().getVersion()).append(" (Android ")
                .append(Build.VERSION.SDK_INT).append(") ").append(kitName).append("/").append(kit.getVersion())
                .toString();
    }

    // visible for tests
    static String getScribeUrl(String defaultUrl, String overrideUrl) {
        if (!TextUtils.isEmpty(overrideUrl)) {
            return overrideUrl;
        } else {
            return defaultUrl;
        }
    }
}