content: /*
   * Copyright (C) 2017 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.wifi.aware;
  
  import android.net.NetworkSpecifier;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.util.Log;
  
  import libcore.util.HexEncoding;
  
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.util.Arrays;
  import java.util.HashSet;
  import java.util.Set;
  import java.util.StringJoiner;
  
  /**
   * A network specifier object used to represent the capabilities of an network agent. A collection
   * of multiple WifiAwareNetworkSpecifier objects whose matching critiera (satisfiedBy) is an OR:
   * a match on any of the network specifiers in the collection is a match.
   *
   * This class is not intended for use in network requests.
   *
   * @hide
   */
  public class WifiAwareAgentNetworkSpecifier extends NetworkSpecifier implements Parcelable {
      private static final String TAG = "WifiAwareAgentNs";
  
      private static final boolean VDBG = false; // STOPSHIP if true
  
      private Set<ByteArrayWrapper> mNetworkSpecifiers = new HashSet<>();
      private MessageDigest mDigester;
  
      public WifiAwareAgentNetworkSpecifier() {
          initialize();
      }
  
      public WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier ns) {
          initialize();
          mNetworkSpecifiers.add(convert(ns));
      }
  
      public WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier[] nss) {
          initialize();
          for (WifiAwareNetworkSpecifier ns : nss) {
              mNetworkSpecifiers.add(convert(ns));
          }
      }
  
      public boolean isEmpty() {
          return mNetworkSpecifiers.isEmpty();
      }
  
      @Override
      public int describeContents() {
          return 0;
      }
  
      @Override
      public void writeToParcel(Parcel dest, int flags) {
          dest.writeArray(mNetworkSpecifiers.toArray());
      }
  
      public static final @android.annotation.NonNull Creator<WifiAwareAgentNetworkSpecifier> CREATOR =
              new Creator<WifiAwareAgentNetworkSpecifier>() {
                  @Override
                  public WifiAwareAgentNetworkSpecifier createFromParcel(Parcel in) {
                      WifiAwareAgentNetworkSpecifier agentNs = new WifiAwareAgentNetworkSpecifier();
                      Object[] objs = in.readArray(null);
                      for (Object obj : objs) {
                          agentNs.mNetworkSpecifiers.add((ByteArrayWrapper) obj);
                      }
                      return agentNs;
                  }
  
                  @Override
                  public WifiAwareAgentNetworkSpecifier[] newArray(int size) {
                      return new WifiAwareAgentNetworkSpecifier[size];
                  }
              };
  
      @Override
      public int hashCode() {
          return mNetworkSpecifiers.hashCode();
      }
  
      @Override
      public boolean equals(Object obj) {
          if (obj == this) {
              return true;
          }
          if (!(obj instanceof WifiAwareAgentNetworkSpecifier)) {
              return false;
          }
          return mNetworkSpecifiers.equals(((WifiAwareAgentNetworkSpecifier) obj).mNetworkSpecifiers);
      }
  
      @Override
      public String toString() {
          StringJoiner sj = new StringJoiner(",");
          for (ByteArrayWrapper baw: mNetworkSpecifiers) {
              sj.add(baw.toString());
          }
          return sj.toString();
      }
  
      @Override
      public boolean satisfiedBy(NetworkSpecifier other) {
          if (!(other instanceof WifiAwareAgentNetworkSpecifier)) {
              return false;
          }
          WifiAwareAgentNetworkSpecifier otherNs = (WifiAwareAgentNetworkSpecifier) other;
  
          // called as old.satifiedBy(new): satisfied if old contained in new
          for (ByteArrayWrapper baw: mNetworkSpecifiers) {
              if (!otherNs.mNetworkSpecifiers.contains(baw)) {
                  return false;
              }
          }
  
          return true;
      }
  
      public boolean satisfiesAwareNetworkSpecifier(WifiAwareNetworkSpecifier ns) {
          if (VDBG) Log.v(TAG, "satisfiesAwareNetworkSpecifier: ns=" + ns);
          ByteArrayWrapper nsBytes = convert(ns);
          return mNetworkSpecifiers.contains(nsBytes);
      }
  
      @Override
      public void assertValidFromUid(int requestorUid) {
          throw new SecurityException(
                  "WifiAwareAgentNetworkSpecifier should not be used in network requests");
      }
  
      @Override
      public NetworkSpecifier redact() {
          return null;
      }
  
      private void initialize() {
          try {
              mDigester = MessageDigest.getInstance("SHA-256");
          } catch (NoSuchAlgorithmException e) {
              Log.e(TAG, "Can not instantiate a SHA-256 digester!? Will match nothing.");
              return;
          }
      }
  
      private ByteArrayWrapper convert(WifiAwareNetworkSpecifier ns) {
          if (mDigester == null) {
              return null;
          }
  
          Parcel parcel = Parcel.obtain();
          ns.writeToParcel(parcel, 0);
          byte[] bytes = parcel.marshall();
  
          mDigester.reset();
          mDigester.update(bytes);
          return new ByteArrayWrapper(mDigester.digest());
      }
  
      private static class ByteArrayWrapper implements Parcelable {
          private byte[] mData;
  
          ByteArrayWrapper(byte[] data) {
              mData = data;
          }
  
          @Override
          public int hashCode() {
              return Arrays.hashCode(mData);
          }
  
          @Override
          public boolean equals(Object obj) {
              if (obj == this) {
                  return true;
              }
              if (!(obj instanceof ByteArrayWrapper)) {
                  return false;
              }
              return Arrays.equals(((ByteArrayWrapper) obj).mData, mData);
          }
  
          @Override
          public int describeContents() {
              return 0;
          }
  
          @Override
          public void writeToParcel(Parcel dest, int flags) {
              dest.writeBlob(mData);
          }
  
          public static final @android.annotation.NonNull Creator<ByteArrayWrapper> CREATOR =
                  new Creator<ByteArrayWrapper>() {
                      @Override
                      public ByteArrayWrapper createFromParcel(Parcel in) {
                          return new ByteArrayWrapper(in.readBlob());
                      }
  
                      @Override
                      public ByteArrayWrapper[] newArray(int size) {
                          return new ByteArrayWrapper[size];
                      }
                  };
  
          @Override
          public String toString() {
              return new String(HexEncoding.encode(mData));
          }
      }
  }
  