content: package com.genymobile.scrcpy;
  
  import android.util.Log;
  
  import java.io.FileDescriptor;
  import java.io.FileOutputStream;
  import java.io.OutputStream;
  import java.io.PrintStream;
  
  /**
   * Log both to Android logger (so that logs are visible in "adb logcat") and standard output/error (so that they are visible in the terminal
   * directly).
   */
  public final class Ln {
  
      private static final String TAG = "scrcpy";
      private static final String PREFIX = "[server] ";
  
      private static final PrintStream CONSOLE_OUT = new PrintStream(new FileOutputStream(FileDescriptor.out));
      private static final PrintStream CONSOLE_ERR = new PrintStream(new FileOutputStream(FileDescriptor.err));
  
      enum Level {
          VERBOSE, DEBUG, INFO, WARN, ERROR
      }
  
      private static Level threshold = Level.INFO;
  
      private Ln() {
          // not instantiable
      }
  
      public static void disableSystemStreams() {
          PrintStream nullStream = new PrintStream(new NullOutputStream());
          System.setOut(nullStream);
          System.setErr(nullStream);
      }
  
      /**
       * Initialize the log level.
       * <p>
       * Must be called before starting any new thread.
       *
       * @param level the log level
       */
      public static void initLogLevel(Level level) {
          threshold = level;
      }
  
      public static boolean isEnabled(Level level) {
          return level.ordinal() >= threshold.ordinal();
      }
  
      public static void v(String message) {
          if (isEnabled(Level.VERBOSE)) {
              Log.v(TAG, message);
              CONSOLE_OUT.print(PREFIX + "VERBOSE: " + message + '\n');
          }
      }
  
      public static void d(String message) {
          if (isEnabled(Level.DEBUG)) {
              Log.d(TAG, message);
              CONSOLE_OUT.print(PREFIX + "DEBUG: " + message + '\n');
          }
      }
  
      public static void i(String message) {
          if (isEnabled(Level.INFO)) {
              Log.i(TAG, message);
              CONSOLE_OUT.print(PREFIX + "INFO: " + message + '\n');
          }
      }
  
      public static void w(String message, Throwable throwable) {
          if (isEnabled(Level.WARN)) {
              Log.w(TAG, message, throwable);
              CONSOLE_ERR.print(PREFIX + "WARN: " + message + '\n');
              if (throwable != null) {
                  throwable.printStackTrace(CONSOLE_ERR);
              }
          }
      }
  
      public static void w(String message) {
          w(message, null);
      }
  
      public static void e(String message, Throwable throwable) {
          if (isEnabled(Level.ERROR)) {
              Log.e(TAG, message, throwable);
              CONSOLE_ERR.print(PREFIX + "ERROR: " + message + '\n');
              if (throwable != null) {
                  throwable.printStackTrace(CONSOLE_ERR);
              }
          }
      }
  
      public static void e(String message) {
          e(message, null);
      }
  
      static class NullOutputStream extends OutputStream {
          @Override
          public void write(byte[] b) {
              // ignore
          }
  
          @Override
          public void write(byte[] b, int off, int len) {
              // ignore
          }
  
          @Override
          public void write(int b) {
              // ignore
          }
      }
  }
  