content: /*
   * Copyright (C) 2013 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.print;
  
  import android.annotation.IntDef;
  import android.annotation.IntRange;
  import android.annotation.NonNull;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.text.TextUtils;
  import com.android.internal.util.Preconditions;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  
  /**
   * This class encapsulates information about a document for printing
   * purposes. This meta-data is used by the platform and print services,
   * components that interact with printers. For example, this class
   * contains the number of pages contained in the document it describes and
   * this number of pages is shown to the user allowing him/her to select
   * the range to print. Also a print service may optimize the printing
   * process based on the content type, such as document or photo.
   * <p>
   * Instances of this class are created by the printing application and
   * passed to the {@link PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished(
   * PrintDocumentInfo, boolean) PrintDocumentAdapter.LayoutResultCallback.onLayoutFinished(
   * PrintDocumentInfo, boolean)} callback after successfully laying out the
   * content which is performed in {@link PrintDocumentAdapter#onLayout(PrintAttributes,
   * PrintAttributes, android.os.CancellationSignal, PrintDocumentAdapter.LayoutResultCallback,
   * android.os.Bundle) PrintDocumentAdapter.onLayout(PrintAttributes,
   * PrintAttributes, android.os.CancellationSignal,
   * PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle)}.
   * </p>
   * <p>
   * An example usage looks like this:
   * <pre>
   *
   * . . .
   *
   * public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
   *         CancellationSignal cancellationSignal, LayoutResultCallback callback,
   *         Bundle metadata) {
   *
   *        // Assume the app defined a LayoutResult class which contains
   *        // the layout result data and that the content is a document.
   *        LayoutResult result = doSomeLayoutWork();
   *
   *        PrintDocumentInfo info = new PrintDocumentInfo
   *                .Builder("printed_file.pdf")
   *                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
   *                .setPageCount(result.getPageCount())
   *                .build();
   *
   *       callback.onLayoutFinished(info, result.getContentChanged());
   *   }
   *
   *   . . .
   *
   * </pre>
   * </p>
   */
  public final class PrintDocumentInfo implements Parcelable {
  
      /**
       * Constant for unknown page count.
       */
      public static final int PAGE_COUNT_UNKNOWN = -1;
  
      /** @hide */
      @Retention(RetentionPolicy.SOURCE)
      @IntDef(prefix = { "CONTENT_TYPE_" }, value = {
              CONTENT_TYPE_UNKNOWN,
              CONTENT_TYPE_DOCUMENT,
              CONTENT_TYPE_PHOTO
      })
      public @interface ContentType {
      }
  
      /**
       * Content type: unknown.
       */
      public static final int CONTENT_TYPE_UNKNOWN = -1;
  
      /**
       * Content type: document.
       * <p>
       * A print service may use normal paper to print the content instead
       * of dedicated photo paper. Also it may use a lower quality printing
       * process as the content is not as sensitive to print quality variation
       * as a photo is.
       * </p>
       */
      public static final int CONTENT_TYPE_DOCUMENT = 0;
  
      /**
       * Content type: photo.
       * <p>
       * A print service may use dedicated photo paper to print the content
       * instead of normal paper. Also it may use a higher quality printing
       * process as the content is more sensitive to print quality variation
       * than a document.
       * </p>
       */
      public static final int CONTENT_TYPE_PHOTO = 1;
  
      private @NonNull String mName;
      private @IntRange(from = -1) int mPageCount;
      private int mContentType;
      private long mDataSize;
  
      /**
       * Creates a new instance.
       */
      private PrintDocumentInfo() {
          /* do nothing */
      }
  
      /**
       * Creates a new instance.
       *
       * @param prototype from which to clone.
       */
      private PrintDocumentInfo(@NonNull PrintDocumentInfo prototype) {
          mName = prototype.mName;
          mPageCount = prototype.mPageCount;
          mContentType = prototype.mContentType;
          mDataSize = prototype.mDataSize;
      }
  
      /**
       * Creates a new instance.
       *
       * @param parcel Data from which to initialize.
       */
      private PrintDocumentInfo(Parcel parcel) {
          mName = Preconditions.checkStringNotEmpty(parcel.readString());
          mPageCount = parcel.readInt();
          Preconditions.checkArgument(mPageCount == PAGE_COUNT_UNKNOWN || mPageCount > 0);
          mContentType = parcel.readInt();
          mDataSize = Preconditions.checkArgumentNonnegative(parcel.readLong());
      }
  
      /**
       * Gets the document name. This name may be shown to
       * the user.
       *
       * @return The document name.
       */
      public @NonNull String getName() {
          return mName;
      }
  
      /**
       * Gets the total number of pages.
       *
       * @return The number of pages.
       *
       * @see #PAGE_COUNT_UNKNOWN
       */
      public @IntRange(from = -1) int getPageCount() {
          return mPageCount;
      }
  
      /**
       * Gets the content type.
       *
       * @return The content type.
       *
       * @see #CONTENT_TYPE_UNKNOWN
       * @see #CONTENT_TYPE_DOCUMENT
       * @see #CONTENT_TYPE_PHOTO
       */
      public int getContentType() {
          return mContentType;
      }
  
      /**
       * Gets the document data size in bytes.
       *
       * @return The data size.
       */
      public @IntRange(from = 0) long getDataSize() {
          return mDataSize;
      }
  
      /**
       * Sets the document data size in bytes.
       *
       * @param dataSize The data size.
       *
       * @hide
       */
      public void setDataSize(@IntRange(from = 0) long dataSize) {
          mDataSize = dataSize;
      }
  
      @Override
      public int describeContents() {
          return 0;
      }
  
      @Override
      public void writeToParcel(Parcel parcel, int flags) {
          parcel.writeString(mName);
          parcel.writeInt(mPageCount);
          parcel.writeInt(mContentType);
          parcel.writeLong(mDataSize);
      }
  
      @Override
      public int hashCode() {
          final int prime = 31;
          int result = 1;
          result = prime * result + ((mName != null) ? mName.hashCode() : 0);
          result = prime * result + mContentType;
          result = prime * result + mPageCount;
          result = prime * result + (int) mDataSize;
          result = prime * result + (int) (mDataSize >> 32);
          return result;
      }
  
      @Override
      public boolean equals(Object obj) {
          if (this == obj) {
              return true;
          }
          if (obj == null) {
              return false;
          }
          if (getClass() != obj.getClass()) {
              return false;
          }
          PrintDocumentInfo other = (PrintDocumentInfo) obj;
          if (!TextUtils.equals(mName, other.mName)) {
              return false;
          }
          if (mContentType != other.mContentType) {
              return false;
          }
          if (mPageCount != other.mPageCount) {
              return false;
          }
          if (mDataSize != other.mDataSize) {
              return false;
          }
          return true;
      }
  
      @Override
      public String toString() {
          StringBuilder builder = new StringBuilder();
          builder.append("PrintDocumentInfo{");
          builder.append("name=").append(mName);
          builder.append(", pageCount=").append(mPageCount);
          builder.append(", contentType=").append(contentTypeToString(mContentType));
          builder.append(", dataSize=").append(mDataSize);
          builder.append("}");
          return builder.toString();
      }
  
      private String contentTypeToString(int contentType) {
          switch (contentType) {
              case CONTENT_TYPE_DOCUMENT: {
                  return "CONTENT_TYPE_DOCUMENT";
              }
              case CONTENT_TYPE_PHOTO: {
                  return "CONTENT_TYPE_PHOTO";
              }
              default: {
                  return "CONTENT_TYPE_UNKNOWN";
              }
          }
      }
  
      /**
       * Builder for creating a {@link PrintDocumentInfo}.
       */
      public static final class Builder {
          private final PrintDocumentInfo mPrototype;
  
          /**
           * Constructor.
           * 
           * <p>
           * The values of the relevant properties are initialized with defaults.
           * Please refer to the documentation of the individual setters for
           * information about the default values.
           * </p>
           *
           * @param name The document name which may be shown to the user and
           * is the file name if the content it describes is saved as a PDF.
           * Cannot be empty. 
           */
          public Builder(@NonNull String name) {
              if (TextUtils.isEmpty(name)) {
                  throw new IllegalArgumentException("name cannot be empty");
              }
              mPrototype = new PrintDocumentInfo();
              mPrototype.mName = name;
          }
  
          /**
           * Sets the total number of pages.
           * <p>
           * <strong>Default: </strong> {@link #PAGE_COUNT_UNKNOWN}
           * </p>
           *
           * @param pageCount The number of pages. Must be greater than or equal to zero or
           *            {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
           * @return This builder.
           */
          public @NonNull Builder setPageCount(@IntRange(from = -1) int pageCount) {
              if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) {
                  throw new IllegalArgumentException("pageCount"
                          + " must be greater than or equal to zero or"
                          + " DocumentInfo#PAGE_COUNT_UNKNOWN");
              }
              mPrototype.mPageCount = pageCount;
              return this;
          }
  
          /**
           * Sets the content type.
           * <p>
           * <strong>Default: </strong> {@link #CONTENT_TYPE_DOCUMENT}
           * </p>
           *
           * @param type The content type.
           * @return This builder.
           * @see #CONTENT_TYPE_UNKNOWN
           * @see #CONTENT_TYPE_DOCUMENT
           * @see #CONTENT_TYPE_PHOTO
           */
          public @NonNull Builder setContentType(@ContentType int type) {
              mPrototype.mContentType = type;
              return this;
          }
  
          /**
           * Creates a new {@link PrintDocumentInfo} instance.
           *
           * @return The new instance.
           */
          public @NonNull PrintDocumentInfo build() {
              // Zero pages is the same as unknown as in this case
              // we will have to ask for all pages and look a the
              // wiritten PDF file for the page count.
              if (mPrototype.mPageCount == 0) {
                  mPrototype.mPageCount = PAGE_COUNT_UNKNOWN;
              }
              return new PrintDocumentInfo(mPrototype);
          }
      }
  
      public static final @android.annotation.NonNull Parcelable.Creator<PrintDocumentInfo> CREATOR =
              new Creator<PrintDocumentInfo>() {
          @Override
          public PrintDocumentInfo createFromParcel(Parcel parcel) {
              return new PrintDocumentInfo(parcel);
          }
  
          @Override
          public PrintDocumentInfo[] newArray(int size) {
              return new PrintDocumentInfo[size];
          }
      };
  }
  