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.FloatRange;
  import android.annotation.IntDef;
  import android.annotation.IntRange;
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.annotation.StringRes;
  import android.annotation.TestApi;
  import android.annotation.UnsupportedAppUsage;
  import android.content.pm.PackageManager;
  import android.content.res.Resources;
  import android.os.Bundle;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.service.print.PrintJobInfoProto;
  
  import com.android.internal.util.Preconditions;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.util.Arrays;
  
  /**
   * This class represents the description of a print job. The print job
   * state includes properties such as its id, print attributes used for
   * generating the content, and so on. Note that the print jobs state may
   * change over time and this class represents a snapshot of this state.
   */
  public final class PrintJobInfo implements Parcelable {
  
      /** @hide */
      @IntDef(prefix = { "STATE_" }, value = {
              STATE_CREATED,
              STATE_QUEUED,
              STATE_STARTED,
              STATE_BLOCKED,
              STATE_COMPLETED,
              STATE_FAILED,
              STATE_CANCELED
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface State {
      }
  
      /**
       * Constant for matching any print job state.
       *
       * @hide
       */
      public static final int STATE_ANY = -1;
  
      /**
       * Constant for matching any print job state.
       *
       * @hide
       */
      public static final int STATE_ANY_VISIBLE_TO_CLIENTS = -2;
  
      /**
       * Constant for matching any active print job state.
       *
       * @hide
       */
      public static final int STATE_ANY_ACTIVE = -3;
  
      /**
       * Constant for matching any scheduled, i.e. delivered to a print
       * service, print job state.
       *
       * @hide
       */
      public static final int STATE_ANY_SCHEDULED = -4;
  
      /**
       * Print job state: The print job is being created but not yet
       * ready to be printed.
       * <p>
       * Next valid states: {@link #STATE_QUEUED}
       * </p>
       */
      public static final int STATE_CREATED = PrintJobInfoProto.STATE_CREATED;
  
      /**
       * Print job state: The print jobs is created, it is ready
       * to be printed and should be processed.
       * <p>
       * Next valid states: {@link #STATE_STARTED}, {@link #STATE_FAILED},
       * {@link #STATE_CANCELED}
       * </p>
       */
      public static final int STATE_QUEUED = PrintJobInfoProto.STATE_QUEUED;
  
      /**
       * Print job state: The print job is being printed.
       * <p>
       * Next valid states: {@link #STATE_COMPLETED}, {@link #STATE_FAILED},
       * {@link #STATE_CANCELED}, {@link #STATE_BLOCKED}
       * </p>
       */
      public static final int STATE_STARTED = PrintJobInfoProto.STATE_STARTED;
  
      /**
       * Print job state: The print job is blocked.
       * <p>
       * Next valid states: {@link #STATE_FAILED}, {@link #STATE_CANCELED},
       * {@link #STATE_STARTED}
       * </p>
       */
      public static final int STATE_BLOCKED = PrintJobInfoProto.STATE_BLOCKED;
  
      /**
       * Print job state: The print job is successfully printed.
       * This is a terminal state.
       * <p>
       * Next valid states: None
       * </p>
       */
      public static final int STATE_COMPLETED = PrintJobInfoProto.STATE_COMPLETED;
  
      /**
       * Print job state: The print job was printing but printing failed.
       * <p>
       * Next valid states: {@link #STATE_CANCELED}, {@link #STATE_STARTED}
       * </p>
       */
      public static final int STATE_FAILED = PrintJobInfoProto.STATE_FAILED;
  
      /**
       * Print job state: The print job is canceled.
       * This is a terminal state.
       * <p>
       * Next valid states: None
       * </p>
       */
      public static final int STATE_CANCELED = PrintJobInfoProto.STATE_CANCELED;
  
      /** The unique print job id. */
      private PrintJobId mId;
  
      /** The human readable print job label. */
      private String mLabel;
  
      /** The unique id of the printer. */
      private PrinterId mPrinterId;
  
      /** The name of the printer - internally used */
      private String mPrinterName;
  
      /** The state of the print job. */
      private int mState;
  
      /** The id of the app that created the job. */
      private int mAppId;
  
      /** Optional tag assigned by a print service.*/
      private String mTag;
  
      /** The wall time when the print job was created. */
      private long mCreationTime;
  
      /** How many copies to print. */
      private int mCopies;
  
      /** The pages to print */
      private PageRange[] mPageRanges;
  
      /** The print job attributes size. */
      private PrintAttributes mAttributes;
  
      /** Information about the printed document. */
      private PrintDocumentInfo mDocumentInfo;
  
      /** The progress made on printing this job or -1 if not set. */
      private float mProgress;
  
      /** A short string describing the status of this job. */
      private @Nullable CharSequence mStatus;
  
      /** A string resource describing the status of this job. */
      private @StringRes int mStatusRes;
      private @Nullable CharSequence mStatusResAppPackageName;
  
      /** Advanced printer specific options. */
      private Bundle mAdvancedOptions;
  
      /** Whether we are trying to cancel this print job. */
      private boolean mCanceling;
  
      /** @hide*/
      public PrintJobInfo() {
          mProgress = -1;
      }
  
      /** @hide */
      public PrintJobInfo(PrintJobInfo other) {
          mId = other.mId;
          mLabel = other.mLabel;
          mPrinterId = other.mPrinterId;
          mPrinterName = other.mPrinterName;
          mState = other.mState;
          mAppId = other.mAppId;
          mTag = other.mTag;
          mCreationTime = other.mCreationTime;
          mCopies = other.mCopies;
          mPageRanges = other.mPageRanges;
          mAttributes = other.mAttributes;
          mDocumentInfo = other.mDocumentInfo;
          mProgress = other.mProgress;
          mStatus = other.mStatus;
          mStatusRes = other.mStatusRes;
          mStatusResAppPackageName = other.mStatusResAppPackageName;
          mCanceling = other.mCanceling;
          mAdvancedOptions = other.mAdvancedOptions;
      }
  
      private PrintJobInfo(@NonNull Parcel parcel) {
          mId = parcel.readParcelable(null);
          mLabel = parcel.readString();
          mPrinterId = parcel.readParcelable(null);
          mPrinterName = parcel.readString();
          mState = parcel.readInt();
          mAppId = parcel.readInt();
          mTag = parcel.readString();
          mCreationTime = parcel.readLong();
          mCopies = parcel.readInt();
          Parcelable[] parcelables = parcel.readParcelableArray(null);
          if (parcelables != null) {
              mPageRanges = new PageRange[parcelables.length];
              for (int i = 0; i < parcelables.length; i++) {
                  mPageRanges[i] = (PageRange) parcelables[i];
              }
          }
          mAttributes = (PrintAttributes) parcel.readParcelable(null);
          mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null);
          mProgress = parcel.readFloat();
          mStatus = parcel.readCharSequence();
          mStatusRes = parcel.readInt();
          mStatusResAppPackageName = parcel.readCharSequence();
          mCanceling = (parcel.readInt() == 1);
          mAdvancedOptions = parcel.readBundle();
  
          if (mAdvancedOptions != null) {
              Preconditions.checkArgument(!mAdvancedOptions.containsKey(null));
          }
      }
  
      /**
       * Gets the unique print job id.
       *
       * @return The id.
       */
      public @Nullable PrintJobId getId() {
          return mId;
      }
  
      /**
       * Sets the unique print job id.
       *
       * @param id The job id.
       *
       * @hide
       */
      public void setId(@NonNull PrintJobId id) {
          this.mId = id;
      }
  
      /**
       * Gets the human readable job label.
       *
       * @return The label.
       */
      public @NonNull String getLabel() {
          return mLabel;
      }
  
      /**
       * Sets the human readable job label.
       *
       * @param label The label.
       *
       * @hide
       */
      public void setLabel(@NonNull String label) {
          mLabel = label;
      }
  
      /**
       * Gets the unique target printer id.
       *
       * @return The target printer id.
       */
      public @Nullable PrinterId getPrinterId() {
          return mPrinterId;
      }
  
      /**
       * Sets the unique target printer id.
       *
       * @param printerId The target printer id.
       *
       * @hide
       */
      public void setPrinterId(@NonNull PrinterId printerId) {
          mPrinterId = printerId;
      }
  
      /**
       * Gets the name of the target printer.
       *
       * @return The printer name.
       *
       * @hide
       */
      public @Nullable String getPrinterName() {
          return mPrinterName;
      }
  
      /**
       * Sets the name of the target printer.
       *
       * @param printerName The printer name.
       *
       * @hide
       */
      public void setPrinterName(@NonNull String printerName) {
          mPrinterName = printerName;
      }
  
      /**
       * Gets the current job state.
       *
       * @return The job state.
       *
       * @see #STATE_CREATED
       * @see #STATE_QUEUED
       * @see #STATE_STARTED
       * @see #STATE_COMPLETED
       * @see #STATE_BLOCKED
       * @see #STATE_FAILED
       * @see #STATE_CANCELED
       */
      public @State int getState() {
          return mState;
      }
  
      /**
       * Sets the current job state.
       *
       * @param state The job state.
       *
       * @hide
       */
      public void setState(int state) {
          mState = state;
      }
  
      /**
       * Sets the progress of the print job.
       *
       * @param progress the progress of the job
       *
       * @hide
       */
      public void setProgress(@FloatRange(from=0.0, to=1.0) float progress) {
          Preconditions.checkArgumentInRange(progress, 0, 1, "progress");
  
          mProgress = progress;
      }
  
      /**
       * Sets the status of the print job.
       *
       * @param status the status of the job, can be null
       *
       * @hide
       */
      public void setStatus(@Nullable CharSequence status) {
          mStatusRes = 0;
          mStatusResAppPackageName = null;
  
          mStatus = status;
      }
  
      /**
       * Sets the status of the print job.
       *
       * @param status The new status as a string resource
       * @param appPackageName App package name the resource belongs to
       *
       * @hide
       */
      public void setStatus(@StringRes int status, @NonNull CharSequence appPackageName) {
          mStatus = null;
  
          mStatusRes = status;
          mStatusResAppPackageName = appPackageName;
      }
  
      /**
       * Sets the owning application id.
       *
       * @return The owning app id.
       *
       * @hide
       */
      public int getAppId() {
          return mAppId;
      }
  
      /**
       * Sets the owning application id.
       *
       * @param appId The owning app id.
       *
       * @hide
       */
      public void setAppId(int appId) {
          mAppId = appId;
      }
  
      /**
       * Gets the optional tag assigned by a print service.
       *
       * @return The tag.
       *
       * @hide
       */
      public String getTag() {
          return mTag;
      }
  
      /**
       * Sets the optional tag assigned by a print service.
       *
       * @param tag The tag.
       *
       * @hide
       */
      public void setTag(String tag) {
          mTag = tag;
      }
  
      /**
       * Gets the wall time in millisecond when this print job was created.
       *
       * @return The creation time in milliseconds.
       */
      public long getCreationTime() {
          return mCreationTime;
      }
  
      /**
       * Sets the wall time in milliseconds when this print job was created.
       *
       * @param creationTime The creation time in milliseconds.
       *
       * @hide
       */
      public void setCreationTime(long creationTime) {
          if (creationTime < 0) {
              throw new IllegalArgumentException("creationTime must be non-negative.");
          }
          mCreationTime = creationTime;
      }
  
      /**
       * Gets the number of copies.
       *
       * @return The number of copies or zero if not set.
       */
      public @IntRange(from = 0) int getCopies() {
          return mCopies;
      }
  
      /**
       * Sets the number of copies.
       *
       * @param copyCount The number of copies.
       *
       * @hide
       */
      public void setCopies(int copyCount) {
          if (copyCount < 1) {
              throw new IllegalArgumentException("Copies must be more than one.");
          }
          mCopies = copyCount;
      }
  
      /**
       * Gets the included pages.
       *
       * @return The included pages or <code>null</code> if not set.
       */
      public @Nullable PageRange[] getPages() {
          return mPageRanges;
      }
  
      /**
       * Sets the included pages.
       *
       * @param pageRanges The included pages.
       *
       * @hide
       */
      public void setPages(PageRange[] pageRanges) {
          mPageRanges = pageRanges;
      }
  
      /**
       * Gets the print job attributes.
       *
       * @return The attributes.
       */
      public @NonNull PrintAttributes getAttributes() {
          return mAttributes;
      }
  
      /**
       * Sets the print job attributes.
       *
       * @param attributes The attributes.
       *
       * @hide
       */
      public void setAttributes(PrintAttributes attributes) {
          mAttributes = attributes;
      }
  
      /**
       * Gets the info describing the printed document.
       *
       * @return The document info.
       *
       * @hide
       */
      @UnsupportedAppUsage
      public PrintDocumentInfo getDocumentInfo() {
          return mDocumentInfo;
      }
  
      /**
       * Sets the info describing the printed document.
       *
       * @param info The document info.
       *
       * @hide
       */
      public void setDocumentInfo(PrintDocumentInfo info) {
          mDocumentInfo = info;
      }
  
      /**
       * Gets whether this print is being cancelled.
       *
       * @return True if the print job is being cancelled.
       *
       * @hide
       */
      public boolean isCancelling() {
          return mCanceling;
      }
  
      /**
       * Sets whether this print is being cancelled.
       *
       * @param cancelling True if the print job is being cancelled.
       *
       * @hide
       */
      public void setCancelling(boolean cancelling) {
          mCanceling = cancelling;
      }
  
      /**
       * If the print job is actively processed, i.e. the device needs to stay on.
       *
       * @hide
       */
      public boolean shouldStayAwake() {
          return mCanceling || mState == STATE_STARTED || mState == STATE_QUEUED;
      }
  
      /**
       * Gets whether this job has a given advanced (printer specific) print
       * option.
       *
       * @param key The option key.
       * @return Whether the option is present.
       */
      public boolean hasAdvancedOption(String key) {
          return mAdvancedOptions != null && mAdvancedOptions.containsKey(key);
      }
  
      /**
       * Gets the value of an advanced (printer specific) print option.
       *
       * @param key The option key.
       * @return The option value.
       */
      public String getAdvancedStringOption(String key) {
          if (mAdvancedOptions != null) {
              return mAdvancedOptions.getString(key);
          }
          return null;
      }
  
      /**
       * Gets the value of an advanced (printer specific) print option.
       *
       * @param key The option key.
       * @return The option value.
       */
      public int getAdvancedIntOption(String key) {
          if (mAdvancedOptions != null) {
              return mAdvancedOptions.getInt(key);
          }
          return 0;
      }
  
      /**
       * Gets the advanced options.
       *
       * @return The advanced options.
       *
       * @hide
       */
      @UnsupportedAppUsage
      public Bundle getAdvancedOptions() {
          return mAdvancedOptions;
      }
  
      /**
       * Sets the advanced options.
       *
       * @param options The advanced options.
       *
       * @hide
       */
      public void setAdvancedOptions(Bundle options) {
          mAdvancedOptions = options;
      }
  
      @Override
      public int describeContents() {
          return 0;
      }
  
      @Override
      public void writeToParcel(Parcel parcel, int flags) {
          parcel.writeParcelable(mId, flags);
          parcel.writeString(mLabel);
          parcel.writeParcelable(mPrinterId, flags);
          parcel.writeString(mPrinterName);
          parcel.writeInt(mState);
          parcel.writeInt(mAppId);
          parcel.writeString(mTag);
          parcel.writeLong(mCreationTime);
          parcel.writeInt(mCopies);
          parcel.writeParcelableArray(mPageRanges, flags);
          parcel.writeParcelable(mAttributes, flags);
          parcel.writeParcelable(mDocumentInfo, 0);
          parcel.writeFloat(mProgress);
          parcel.writeCharSequence(mStatus);
          parcel.writeInt(mStatusRes);
          parcel.writeCharSequence(mStatusResAppPackageName);
          parcel.writeInt(mCanceling ? 1 : 0);
          parcel.writeBundle(mAdvancedOptions);
      }
  
      @Override
      public String toString() {
          StringBuilder builder = new StringBuilder();
          builder.append("PrintJobInfo{");
          builder.append("label: ").append(mLabel);
          builder.append(", id: ").append(mId);
          builder.append(", state: ").append(stateToString(mState));
          builder.append(", printer: " + mPrinterId);
          builder.append(", tag: ").append(mTag);
          builder.append(", creationTime: " + mCreationTime);
          builder.append(", copies: ").append(mCopies);
          builder.append(", attributes: " + (mAttributes != null
                  ? mAttributes.toString() : null));
          builder.append(", documentInfo: " + (mDocumentInfo != null
                  ? mDocumentInfo.toString() : null));
          builder.append(", cancelling: " + mCanceling);
          builder.append(", pages: " + (mPageRanges != null
                  ? Arrays.toString(mPageRanges) : null));
          builder.append(", hasAdvancedOptions: " + (mAdvancedOptions != null));
          builder.append(", progress: " + mProgress);
          builder.append(", status: " + (mStatus != null
                  ? mStatus.toString() : null));
          builder.append(", statusRes: " + mStatusRes);
          builder.append(", statusResAppPackageName: " + (mStatusResAppPackageName != null
                  ? mStatusResAppPackageName.toString() : null));
          builder.append("}");
          return builder.toString();
      }
  
      /** @hide */
      public static String stateToString(int state) {
          switch (state) {
              case STATE_CREATED: {
                  return "STATE_CREATED";
              }
              case STATE_QUEUED: {
                  return "STATE_QUEUED";
              }
              case STATE_STARTED: {
                  return "STATE_STARTED";
              }
              case STATE_BLOCKED: {
                  return "STATE_BLOCKED";
              }
              case STATE_FAILED: {
                  return "STATE_FAILED";
              }
              case STATE_COMPLETED: {
                  return "STATE_COMPLETED";
              }
              case STATE_CANCELED: {
                  return "STATE_CANCELED";
              }
              default: {
                  return "STATE_UNKNOWN";
              }
          }
      }
  
      /**
       * Get the progress that has been made printing this job.
       *
       * @return the print progress or -1 if not set
       * @hide
       */
      @TestApi
      public float getProgress() {
          return mProgress;
      }
  
      /**
       * Get the status of this job.
       *
       * @param pm Package manager used to resolve the string
       *
       * @return the status of this job or null if not set
       * @hide
       */
      @TestApi
      public @Nullable CharSequence getStatus(@NonNull PackageManager pm) {
          if (mStatusRes == 0) {
              return mStatus;
          } else {
              try {
                  return pm.getResourcesForApplication(mStatusResAppPackageName.toString())
                          .getString(mStatusRes);
              } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
                  return null;
              }
          }
      }
  
      /**
       * Builder for creating a {@link PrintJobInfo}.
       */
      public static final class Builder {
          private final PrintJobInfo mPrototype;
  
          /**
           * Constructor.
           *
           * @param prototype Prototype to use as a starting point.
           * Can be <code>null</code>.
           */
          public Builder(@Nullable PrintJobInfo prototype) {
              mPrototype = (prototype != null)
                      ? new PrintJobInfo(prototype)
                      : new PrintJobInfo();
          }
  
          /**
           * Sets the number of copies.
           *
           * @param copies The number of copies.
           */
          public void setCopies(@IntRange(from = 1) int copies) {
              mPrototype.mCopies = copies;
          }
  
          /**
           * Sets the print job attributes.
           *
           * @param attributes The attributes.
           */
          public void setAttributes(@NonNull PrintAttributes attributes) {
              mPrototype.mAttributes = attributes;
          }
  
          /**
           * Sets the included pages.
           *
           * @param pages The included pages.
           */
          public void setPages(@NonNull PageRange[] pages) {
              mPrototype.mPageRanges = pages;
          }
  
          /**
           * Sets the progress of the print job.
           *
           * @param progress the progress of the job
           * @hide
           */
          public void setProgress(@FloatRange(from=0.0, to=1.0) float progress) {
              Preconditions.checkArgumentInRange(progress, 0, 1, "progress");
  
              mPrototype.mProgress = progress;
          }
  
          /**
           * Sets the status of the print job.
           *
           * @param status the status of the job, can be null
           * @hide
           */
          public void setStatus(@Nullable CharSequence status) {
              mPrototype.mStatus = status;
          }
  
          /**
           * Puts an advanced (printer specific) option.
           *
           * @param key The option key.
           * @param value The option value.
           */
          public void putAdvancedOption(@NonNull String key, @Nullable String value) {
              Preconditions.checkNotNull(key, "key cannot be null");
  
              if (mPrototype.mAdvancedOptions == null) {
                  mPrototype.mAdvancedOptions = new Bundle();
              }
              mPrototype.mAdvancedOptions.putString(key, value);
          }
  
          /**
           * Puts an advanced (printer specific) option.
           *
           * @param key The option key.
           * @param value The option value.
           */
          public void putAdvancedOption(@NonNull String key, int value) {
              if (mPrototype.mAdvancedOptions == null) {
                  mPrototype.mAdvancedOptions = new Bundle();
              }
              mPrototype.mAdvancedOptions.putInt(key, value);
          }
  
          /**
           * Creates a new {@link PrintJobInfo} instance.
           *
           * @return The new instance.
           */
          public @NonNull PrintJobInfo build() {
              return mPrototype;
          }
      }
  
      public static final @android.annotation.NonNull Parcelable.Creator<PrintJobInfo> CREATOR =
              new Creator<PrintJobInfo>() {
          @Override
          public PrintJobInfo createFromParcel(Parcel parcel) {
              return new PrintJobInfo(parcel);
          }
  
          @Override
          public PrintJobInfo[] newArray(int size) {
              return new PrintJobInfo[size];
          }
      };
  }
  