content: /*
   * 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 android.net.metrics;
  
  import android.annotation.IntDef;
  import android.annotation.NonNull;
  import android.annotation.SystemApi;
  import android.annotation.TestApi;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.util.SparseArray;
  
  import com.android.internal.util.MessageUtils;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  
  /**
   * An event recorded by NetworkMonitor when sending a probe for finding captive portals.
   * {@hide}
   */
  @SystemApi
  @TestApi
  public final class ValidationProbeEvent implements IpConnectivityLog.Event {
  
      public static final int PROBE_DNS       = 0;
      public static final int PROBE_HTTP      = 1;
      public static final int PROBE_HTTPS     = 2;
      public static final int PROBE_PAC       = 3;
      public static final int PROBE_FALLBACK  = 4;
      public static final int PROBE_PRIVDNS   = 5;
  
      public static final int DNS_FAILURE = 0;
      public static final int DNS_SUCCESS = 1;
  
      private static final int FIRST_VALIDATION  = 1 << 8;
      private static final int REVALIDATION      = 2 << 8;
  
      /** @hide */
      @IntDef(value = {DNS_FAILURE, DNS_SUCCESS})
      @Retention(RetentionPolicy.SOURCE)
      public @interface ReturnCode {}
  
      /** @hide */
      public final long durationMs;
      // probeType byte format (MSB to LSB):
      // byte 0: unused
      // byte 1: unused
      // byte 2: 0 = UNKNOWN, 1 = FIRST_VALIDATION, 2 = REVALIDATION
      // byte 3: PROBE_* constant
      /** @hide */
      public final int probeType;
      /** @hide */
      public final @ReturnCode int returnCode;
  
      private ValidationProbeEvent(long durationMs, int probeType, int returnCode) {
          this.durationMs = durationMs;
          this.probeType = probeType;
          this.returnCode = returnCode;
      }
  
      private ValidationProbeEvent(Parcel in) {
          durationMs = in.readLong();
          probeType = in.readInt();
          returnCode = in.readInt();
      }
  
      /**
       * Utility to create an instance of {@link ValidationProbeEvent}.
       */
      public static final class Builder {
          private long mDurationMs;
          private int mProbeType;
          private int mReturnCode;
  
          /**
           * Set the duration of the probe in milliseconds.
           */
          @NonNull
          public Builder setDurationMs(long durationMs) {
              mDurationMs = durationMs;
              return this;
          }
  
          /**
           * Set the probe type based on whether it was the first validation.
           */
          @NonNull
          public Builder setProbeType(int probeType, boolean firstValidation) {
              mProbeType = makeProbeType(probeType, firstValidation);
              return this;
          }
  
          /**
           * Set the return code of the probe.
           */
          @NonNull
          public Builder setReturnCode(int returnCode) {
              mReturnCode = returnCode;
              return this;
          }
  
          /**
           * Create a new {@link ValidationProbeEvent}.
           */
          @NonNull
          public ValidationProbeEvent build() {
              return new ValidationProbeEvent(mDurationMs, mProbeType, mReturnCode);
          }
      }
  
      /** @hide */
      @Override
      public void writeToParcel(Parcel out, int flags) {
          out.writeLong(durationMs);
          out.writeInt(probeType);
          out.writeInt(returnCode);
      }
  
      /** @hide */
      @Override
      public int describeContents() {
          return 0;
      }
  
      /** @hide */
      public static final @android.annotation.NonNull Parcelable.Creator<ValidationProbeEvent> CREATOR
          = new Parcelable.Creator<ValidationProbeEvent>() {
          public ValidationProbeEvent createFromParcel(Parcel in) {
              return new ValidationProbeEvent(in);
          }
  
          public ValidationProbeEvent[] newArray(int size) {
              return new ValidationProbeEvent[size];
          }
      };
  
      private static int makeProbeType(int probeType, boolean firstValidation) {
          return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION);
      }
  
      /**
       * Get the name of a probe specified by its probe type.
       */
      public static @NonNull String getProbeName(int probeType) {
          return Decoder.constants.get(probeType & 0xff, "PROBE_???");
      }
  
      private static @NonNull String getValidationStage(int probeType) {
          return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
      }
  
      @Override
      public String toString() {
          return String.format("ValidationProbeEvent(%s:%d %s, %dms)",
                  getProbeName(probeType), returnCode, getValidationStage(probeType), durationMs);
      }
  
      @Override
      public boolean equals(Object obj) {
          if (obj == null || !(obj.getClass().equals(ValidationProbeEvent.class))) return false;
          final ValidationProbeEvent other = (ValidationProbeEvent) obj;
          return durationMs == other.durationMs
                  && probeType == other.probeType
                  && returnCode == other.returnCode;
      }
  
      final static class Decoder {
          static final SparseArray<String> constants = MessageUtils.findMessageNames(
                  new Class[]{ValidationProbeEvent.class},
                  new String[]{"PROBE_", "FIRST_", "REVALIDATION"});
      }
  }
  