<commit_before>/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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.google.android.exoplayer2.upstream;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.ExecutorService;

/**
 * Manages the background loading of {@link Loadable}s.
 */
public final class Loader implements LoaderErrorThrower {

  /**
   * Thrown when an unexpected exception or error is encountered during loading.
   */
  public static final class UnexpectedLoaderException extends IOException {

    public UnexpectedLoaderException(Throwable cause) {
      super("Unexpected " + cause.getClass().getSimpleName() + ": " + cause.getMessage(), cause);
    }

  }

  /**
   * An object that can be loaded using a {@link Loader}.
   */
  public interface Loadable {

    /**
     * Cancels the load.
     */
    void cancelLoad();

    /**
     * Returns whether the load has been canceled.
     */
    boolean isLoadCanceled();

    /**
     * Performs the load, returning on completion or cancellation.
     *
     * @throws IOException If the input could not be loaded.
     * @throws InterruptedException If the thread was interrupted.
     */
    void load() throws IOException, InterruptedException;

  }

  /**
   * A callback to be notified of {@link Loader} events.
   */
  public interface Callback<T extends Loadable> {

    /**
     * Called when a load has completed.
     * <p>
     * Note: There is guaranteed to be a memory barrier between {@link Loadable#load()} exiting and
     * this callback being called.
     *
     * @param loadable The loadable whose load has completed.
     * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the load ended.
     * @param loadDurationMs The duration of the load.
     */
    void onLoadCompleted(T loadable, long elapsedRealtimeMs, long loadDurationMs);

    /**
     * Called when a load has been canceled.
     * <p>
     * Note: If the {@link Loader} has not been released then there is guaranteed to be a memory
     * barrier between {@link Loadable#load()} exiting and this callback being called. If the
     * {@link Loader} has been released then this callback may be called before
     * {@link Loadable#load()} exits.
     *
     * @param loadable The loadable whose load has been canceled.
     * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the load was canceled.
     * @param loadDurationMs The duration of the load up to the point at which it was canceled.
     * @param released True if the load was canceled because the {@link Loader} was released. False
     *     otherwise.
     */
    void onLoadCanceled(T loadable, long elapsedRealtimeMs, long loadDurationMs, boolean released);

    /**
     * Called when a load encounters an error.
     *
     * <p>Note: There is guaranteed to be a memory barrier between {@link Loadable#load()} exiting
     * and this callback being called.
     *
     * @param loadable The loadable whose load has encountered an error.
     * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the error occurred.
     * @param loadDurationMs The duration of the load up to the point at which the error occurred.
     * @param error The load error.
     * @return The desired retry action. One of {@link Loader#RETRY}, {@link
     *     Loader#RETRY_RESET_ERROR_COUNT}, {@link Loader#DONT_RETRY} and {@link
     *     Loader#DONT_RETRY_FATAL}.
     */
    @RetryAction
    int onLoadError(T loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error);
  }

  /**
   * A callback to be notified when a {@link Loader} has finished being released.
   */
  public interface ReleaseCallback {

    /**
     * Called when the {@link Loader} has finished being released.
     */
    void onLoaderReleased();

  }

  /** Actions that can be taken in response to a load error. */
  @Retention(RetentionPolicy.SOURCE)
  @IntDef({RETRY, RETRY_RESET_ERROR_COUNT, DONT_RETRY, DONT_RETRY_FATAL})
  public @interface RetryAction {}

  public static final int RETRY = 0;
  public static final int RETRY_RESET_ERROR_COUNT = 1;
  public static final int DONT_RETRY = 2;
  public static final int DONT_RETRY_FATAL = 3;

  private final ExecutorService downloadExecutorService;

  private LoadTask<? extends Loadable> currentTask;
  private IOException fatalError;

  /**
   * @param threadName A name for the loader's thread.
   */
  public Loader(String threadName) {
    this.downloadExecutorService = Util.newSingleThreadExecutor(threadName);
  }

  /**
   * Starts loading a {@link Loadable}.
   * <p>
   * The calling thread must be a {@link Looper} thread, which is the thread on which the
   * {@link Callback} will be called.
   *
   * @param <T> The type of the loadable.
   * @param loadable The {@link Loadable} to load.
   * @param callback A callback to be called when the load ends.
   * @param defaultMinRetryCount The minimum number of times the load must be retried before
   *     {@link #maybeThrowError()} will propagate an error.
   * @throws IllegalStateException If the calling thread does not have an associated {@link Looper}.
   * @return {@link SystemClock#elapsedRealtime} when the load started.
   */
  public <T extends Loadable> long startLoading(T loadable, Callback<T> callback,
      int defaultMinRetryCount) {
    Looper looper = Looper.myLooper();
    Assertions.checkState(looper != null);
    long startTimeMs = SystemClock.elapsedRealtime();
    new LoadTask<>(looper, loadable, callback, defaultMinRetryCount, startTimeMs).start(0);
    return startTimeMs;
  }

  /**
   * Returns whether the {@link Loader} is currently loading a {@link Loadable}.
   */
  public boolean isLoading() {
    return currentTask != null;
  }

  /**
   * Cancels the current load. This method should only be called when a load is in progress.
   */
  public void cancelLoading() {
    currentTask.cancel(false);
  }

  /**
   * Releases the {@link Loader}. This method should be called when the {@link Loader} is no longer
   * required.
   */
  public void release() {
    release(null);
  }

  /**
   * Releases the {@link Loader}. This method should be called when the {@link Loader} is no longer
   * required.<commit_msg>Clear fatal errors in Loader#startLoading<commit_after>/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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.google.android.exoplayer2.upstream;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.ExecutorService;

/**
 * Manages the background loading of {@link Loadable}s.
 */
public final class Loader implements LoaderErrorThrower {

  /**
   * Thrown when an unexpected exception or error is encountered during loading.
   */
  public static final class UnexpectedLoaderException extends IOException {

    public UnexpectedLoaderException(Throwable cause) {
      super("Unexpected " + cause.getClass().getSimpleName() + ": " + cause.getMessage(), cause);
    }

  }

  /**
   * An object that can be loaded using a {@link Loader}.
   */
  public interface Loadable {

    /**
     * Cancels the load.
     */
    void cancelLoad();

    /**
     * Returns whether the load has been canceled.
     */
    boolean isLoadCanceled();

    /**
     * Performs the load, returning on completion or cancellation.
     *
     * @throws IOException If the input could not be loaded.
     * @throws InterruptedException If the thread was interrupted.
     */
    void load() throws IOException, InterruptedException;

  }

  /**
   * A callback to be notified of {@link Loader} events.
   */
  public interface Callback<T extends Loadable> {

    /**
     * Called when a load has completed.
     * <p>
     * Note: There is guaranteed to be a memory barrier between {@link Loadable#load()} exiting and
     * this callback being called.
     *
     * @param loadable The loadable whose load has completed.
     * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the load ended.
     * @param loadDurationMs The duration of the load.
     */
    void onLoadCompleted(T loadable, long elapsedRealtimeMs, long loadDurationMs);

    /**
     * Called when a load has been canceled.
     * <p>
     * Note: If the {@link Loader} has not been released then there is guaranteed to be a memory
     * barrier between {@link Loadable#load()} exiting and this callback being called. If the
     * {@link Loader} has been released then this callback may be called before
     * {@link Loadable#load()} exits.
     *
     * @param loadable The loadable whose load has been canceled.
     * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the load was canceled.
     * @param loadDurationMs The duration of the load up to the point at which it was canceled.
     * @param released True if the load was canceled because the {@link Loader} was released. False
     *     otherwise.
     */
    void onLoadCanceled(T loadable, long elapsedRealtimeMs, long loadDurationMs, boolean released);

    /**
     * Called when a load encounters an error.
     *
     * <p>Note: There is guaranteed to be a memory barrier between {@link Loadable#load()} exiting
     * and this callback being called.
     *
     * @param loadable The loadable whose load has encountered an error.
     * @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the error occurred.
     * @param loadDurationMs The duration of the load up to the point at which the error occurred.
     * @param error The load error.
     * @return The desired retry action. One of {@link Loader#RETRY}, {@link
     *     Loader#RETRY_RESET_ERROR_COUNT}, {@link Loader#DONT_RETRY} and {@link
     *     Loader#DONT_RETRY_FATAL}.
     */
    @RetryAction
    int onLoadError(T loadable, long elapsedRealtimeMs, long loadDurationMs, IOException error);
  }

  /**
   * A callback to be notified when a {@link Loader} has finished being released.
   */
  public interface ReleaseCallback {

    /**
     * Called when the {@link Loader} has finished being released.
     */
    void onLoaderReleased();

  }

  /** Actions that can be taken in response to a load error. */
  @Retention(RetentionPolicy.SOURCE)
  @IntDef({RETRY, RETRY_RESET_ERROR_COUNT, DONT_RETRY, DONT_RETRY_FATAL})
  public @interface RetryAction {}

  public static final int RETRY = 0;
  public static final int RETRY_RESET_ERROR_COUNT = 1;
  public static final int DONT_RETRY = 2;
  public static final int DONT_RETRY_FATAL = 3;

  private final ExecutorService downloadExecutorService;

  private LoadTask<? extends Loadable> currentTask;
  private IOException fatalError;

  /**
   * @param threadName A name for the loader's thread.
   */
  public Loader(String threadName) {
    this.downloadExecutorService = Util.newSingleThreadExecutor(threadName);
  }

  /**
   * Starts loading a {@link Loadable}.
   *
   * <p>The calling thread must be a {@link Looper} thread, which is the thread on which the {@link
   * Callback} will be called.
   *
   * @param <T> The type of the loadable.
   * @param loadable The {@link Loadable} to load.
   * @param callback A callback to be called when the load ends.
   * @param defaultMinRetryCount The minimum number of times the load must be retried before {@link
   *     #maybeThrowError()} will propagate an error.
   * @throws IllegalStateException If the calling thread does not have an associated {@link Looper}.
   * @return {@link SystemClock#elapsedRealtime} when the load started.
   */
  public <T extends Loadable> long startLoading(
      T loadable, Callback<T> callback, int defaultMinRetryCount) {
    Looper looper = Looper.myLooper();
    Assertions.checkState(looper != null);
    fatalError = null;
    long startTimeMs = SystemClock.elapsedRealtime();
    new LoadTask<>(looper, loadable, callback, defaultMinRetryCount, startTimeMs).start(0);
    return startTimeMs;
  }

  /**
   * Returns whether the {@link Loader} is currently loading a {@link Loadable}.
   */
  public boolean isLoading() {
    return currentTask != null;
  }

  /**
   * Cancels the current load. This method should only be called when a load is in progress.
   */
  public void cancelLoading() {
    currentTask.cancel(false);
  }

  /**
   * Releases the {@link Loader}. This method should be called when the {@link Loader} is no longer
   * required.
   */
  public void release() {
    release(null);
  }

  /**
   * Releases the {@link Loader}. This method should be called when the {@link Loader} is no longer
   * required.
{'fraction_non_alphanumeric': 0.08813629181836917, 'fraction_numerical': 0.002335646080923267, 'mean_word_length': 3.3586826347305387, 'pattern_counts': {'":': 2, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5713872', 'n_tokens_mistral': 4085, 'n_tokens_neox': 3987, 'n_words': 1547}