content: /*
   * Copyright (C) 2010 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;
  
  import android.os.Parcel;
  import android.os.Parcelable;
  import com.klinker.android.logger.Log;
  
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  
  /**
   * A class representing the capabilities of a link
   *
   * @hide
   */
  public class LinkCapabilities implements Parcelable {
      private static final String TAG = "LinkCapabilities";
      private static final boolean DBG = false;
  
      /**
       * The Map of Keys to Values
       */
      private HashMap<Integer, String> mCapabilities;
  
  
      /**
       * The set of keys defined for a links capabilities.
       * <p/>
       * Keys starting with RW are read + write, i.e. the application
       * can request for a certain requirement corresponding to that key.
       * Keys starting with RO are read only, i.e. the the application
       * can read the value of that key from the socket but cannot request
       * a corresponding requirement.
       * <p/>
       * TODO: Provide a documentation technique for concisely and precisely
       * define the syntax for each value string associated with a key.
       */
      public static final class Key {
          /**
           * No constructor
           */
          private Key() {
          }
  
          /**
           * An integer representing the network type.
           *
           * @see ConnectivityManager
           */
          public final static int RO_NETWORK_TYPE = 1;
  
          /**
           * Desired minimum forward link (download) bandwidth for the
           * in kilobits per second (kbps). Values should be strings such
           * "50", "100", "1500", etc.
           */
          public final static int RW_DESIRED_FWD_BW = 2;
  
          /**
           * Required minimum forward link (download) bandwidth, in
           * per second (kbps), below which the socket cannot function.
           * Values should be strings such as "50", "100", "1500", etc.
           */
          public final static int RW_REQUIRED_FWD_BW = 3;
  
          /**
           * Available forward link (download) bandwidth for the socket.
           * This value is in kilobits per second (kbps).
           * Values will be strings such as "50", "100", "1500", etc.
           */
          public final static int RO_AVAILABLE_FWD_BW = 4;
  
          /**
           * Desired minimum reverse link (upload) bandwidth for the socket
           * in kilobits per second (kbps).
           * Values should be strings such as "50", "100", "1500", etc.
           * <p/>
           * This key is set via the needs map.
           */
          public final static int RW_DESIRED_REV_BW = 5;
  
          /**
           * Required minimum reverse link (upload) bandwidth, in kilobits
           * per second (kbps), below which the socket cannot function.
           * If a rate is not specified, the default rate of kbps will be
           * Values should be strings such as "50", "100", "1500", etc.
           */
          public final static int RW_REQUIRED_REV_BW = 6;
  
          /**
           * Available reverse link (upload) bandwidth for the socket.
           * This value is in kilobits per second (kbps).
           * Values will be strings such as "50", "100", "1500", etc.
           */
          public final static int RO_AVAILABLE_REV_BW = 7;
  
          /**
           * Maximum latency for the socket, in milliseconds, above which
           * socket cannot function.
           * Values should be strings such as "50", "300", "500", etc.
           */
          public final static int RW_MAX_ALLOWED_LATENCY = 8;
  
          /**
           * Interface that the socket is bound to. This can be a virtual
           * interface (e.g. VPN or Mobile IP) or a physical interface
           * (e.g. wlan0 or rmnet0).
           * Values will be strings such as "wlan0", "rmnet0"
           */
          public final static int RO_BOUND_INTERFACE = 9;
  
          /**
           * Physical interface that the socket is routed on.
           * This can be different from BOUND_INTERFACE in cases such as
           * VPN or Mobile IP. The physical interface may change over time
           * if seamless mobility is supported.
           * Values will be strings such as "wlan0", "rmnet0"
           */
          public final static int RO_PHYSICAL_INTERFACE = 10;
      }
  
      /**
       * Role informs the LinkSocket about the data usage patterns of your
       * application.
       * <p/>
       * {@code Role.DEFAULT} is the default role, and is used whenever
       * a role isn't set.
       */
      public static final class Role {
          /**
           * No constructor
           */
          private Role() {
          }
  
          // examples only, discuss which roles should be defined, and then
          // code these to match
  
          /**
           * Default Role
           */
          public static final String DEFAULT = "default";
          /**
           * Bulk down load
           */
          public static final String BULK_DOWNLOAD = "bulk.download";
          /**
           * Bulk upload
           */
          public static final String BULK_UPLOAD = "bulk.upload";
  
          /**
           * VoIP Application at 24kbps
           */
          public static final String VOIP_24KBPS = "voip.24k";
          /**
           * VoIP Application at 32kbps
           */
          public static final String VOIP_32KBPS = "voip.32k";
  
          /**
           * Video Streaming at 480p
           */
          public static final String VIDEO_STREAMING_480P = "video.streaming.480p";
          /**
           * Video Streaming at 720p
           */
          public static final String VIDEO_STREAMING_720I = "video.streaming.720i";
  
          /**
           * Video Chat Application at 360p
           */
          public static final String VIDEO_CHAT_360P = "video.chat.360p";
          /**
           * Video Chat Application at 480p
           */
          public static final String VIDEO_CHAT_480P = "video.chat.480i";
      }
  
      /**
       * Constructor
       */
      public LinkCapabilities() {
          mCapabilities = new HashMap<Integer, String>();
      }
  
      /**
       * Copy constructor.
       *
       * @param source
       */
      public LinkCapabilities(LinkCapabilities source) {
          if (source != null) {
              mCapabilities = new HashMap<Integer, String>(source.mCapabilities);
          } else {
              mCapabilities = new HashMap<Integer, String>();
          }
      }
  
      /**
       * Create the {@code LinkCapabilities} with values depending on role type.
       *
       * @param applicationRole a {@code LinkSocket.Role}
       * @return the {@code LinkCapabilities} associated with the applicationRole, empty if none
       */
      public static LinkCapabilities createNeedsMap(String applicationRole) {
          if (DBG) log("createNeededCapabilities(applicationRole) EX");
          return new LinkCapabilities();
      }
  
      /**
       * Remove all capabilities
       */
      public void clear() {
          mCapabilities.clear();
      }
  
      /**
       * Returns whether this map is empty.
       */
      public boolean isEmpty() {
          return mCapabilities.isEmpty();
      }
  
      /**
       * Returns the number of elements in this map.
       *
       * @return the number of elements in this map.
       */
      public int size() {
          return mCapabilities.size();
      }
  
      /**
       * Given the key return the capability string
       *
       * @param key
       * @return the capability string
       */
      public String get(int key) {
          return mCapabilities.get(key);
      }
  
      /**
       * Store the key/value capability pair
       *
       * @param key
       * @param value
       */
      public void put(int key, String value) {
          mCapabilities.put(key, value);
      }
  
      /**
       * Returns whether this map contains the specified key.
       *
       * @param key to search for.
       * @return {@code true} if this map contains the specified key,
       * {@code false} otherwise.
       */
      public boolean containsKey(int key) {
          return mCapabilities.containsKey(key);
      }
  
      /**
       * Returns whether this map contains the specified value.
       *
       * @param value to search for.
       * @return {@code true} if this map contains the specified value,
       * {@code false} otherwise.
       */
      public boolean containsValue(String value) {
          return mCapabilities.containsValue(value);
      }
  
      /**
       * Returns a set containing all of the mappings in this map. Each mapping is
       * an instance of {@link Map.Entry}. As the set is backed by this map,
       * changes in one will be reflected in the other.
       *
       * @return a set of the mappings.
       */
      public Set<Entry<Integer, String>> entrySet() {
          return mCapabilities.entrySet();
      }
  
      /**
       * @return the set of the keys.
       */
      public Set<Integer> keySet() {
          return mCapabilities.keySet();
      }
  
      /**
       * @return the set of values
       */
      public Collection<String> values() {
          return mCapabilities.values();
      }
  
      /**
       * Implement the Parcelable interface
       *
       * @hide
       */
      public int describeContents() {
          return 0;
      }
  
      /**
       * Convert to string for debugging
       */
      @Override
      public String toString() {
          StringBuilder sb = new StringBuilder();
          sb.append("{");
          boolean firstTime = true;
          for (Entry<Integer, String> entry : mCapabilities.entrySet()) {
              if (firstTime) {
                  firstTime = false;
              } else {
                  sb.append(",");
              }
              sb.append(entry.getKey());
              sb.append(":\"");
              sb.append(entry.getValue());
              sb.append("\"");
              return mCapabilities.toString();
          }
          return sb.toString();
      }
  
      /**
       * Implement the Parcelable interface.
       *
       * @hide
       */
      public void writeToParcel(Parcel dest, int flags) {
          dest.writeInt(mCapabilities.size());
          for (Entry<Integer, String> entry : mCapabilities.entrySet()) {
              dest.writeInt(entry.getKey().intValue());
              dest.writeString(entry.getValue());
          }
      }
  
      /**
       * Implement the Parcelable interface.
       *
       * @hide
       */
      public static final Creator<LinkCapabilities> CREATOR =
              new Creator<LinkCapabilities>() {
                  public LinkCapabilities createFromParcel(Parcel in) {
                      LinkCapabilities capabilities = new LinkCapabilities();
                      int size = in.readInt();
                      while (size-- != 0) {
                          int key = in.readInt();
                          String value = in.readString();
                          capabilities.mCapabilities.put(key, value);
                      }
                      return capabilities;
                  }
  
                  public LinkCapabilities[] newArray(int size) {
                      return new LinkCapabilities[size];
                  }
              };
  
      /**
       * Debug logging
       */
      protected static void log(String s) {
          Log.d(TAG, s);
      }
  }
  