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.nfc.tech;
  
  import android.nfc.ErrorCodes;
  import android.nfc.Tag;
  import android.nfc.TransceiveResult;
  import android.os.RemoteException;
  import android.util.Log;
  
  import java.io.IOException;
  
  /**
   * A base class for tag technologies that are built on top of transceive().
   */
  abstract class BasicTagTechnology implements TagTechnology {
      private static final String TAG = "NFC";
  
      final Tag mTag;
  
      boolean mIsConnected;
      int mSelectedTechnology;
  
      BasicTagTechnology(Tag tag, int tech) throws RemoteException {
          mTag = tag;
          mSelectedTechnology = tech;
      }
  
      @Override
      public Tag getTag() {
          return mTag;
      }
  
      /** Internal helper to throw IllegalStateException if the technology isn't connected */
      void checkConnected() {
         if ((mTag.getConnectedTechnology() != mSelectedTechnology) ||
                 (mTag.getConnectedTechnology() == -1)) {
             throw new IllegalStateException("Call connect() first!");
         }
      }
  
      @Override
      public boolean isConnected() {
          if (!mIsConnected) {
              return false;
          }
  
          try {
              return mTag.getTagService().isPresent(mTag.getServiceHandle());
          } catch (RemoteException e) {
              Log.e(TAG, "NFC service dead", e);
              return false;
          }
      }
  
      @Override
      public void connect() throws IOException {
          try {
              int errorCode = mTag.getTagService().connect(mTag.getServiceHandle(),
                      mSelectedTechnology);
  
              if (errorCode == ErrorCodes.SUCCESS) {
                  // Store this in the tag object
                  mTag.setConnectedTechnology(mSelectedTechnology);
                  mIsConnected = true;
              } else if (errorCode == ErrorCodes.ERROR_NOT_SUPPORTED) {
                  throw new UnsupportedOperationException("Connecting to " +
                          "this technology is not supported by the NFC " +
                          "adapter.");
              } else {
                  throw new IOException();
              }
          } catch (RemoteException e) {
              Log.e(TAG, "NFC service dead", e);
              throw new IOException("NFC service died");
          }
      }
  
      /** @hide */
      @Override
      public void reconnect() throws IOException {
          if (!mIsConnected) {
              throw new IllegalStateException("Technology not connected yet");
          }
  
          try {
              int errorCode = mTag.getTagService().reconnect(mTag.getServiceHandle());
  
              if (errorCode != ErrorCodes.SUCCESS) {
                  mIsConnected = false;
                  mTag.setTechnologyDisconnected();
                  throw new IOException();
              }
          } catch (RemoteException e) {
              mIsConnected = false;
              mTag.setTechnologyDisconnected();
              Log.e(TAG, "NFC service dead", e);
              throw new IOException("NFC service died");
          }
      }
  
      @Override
      public void close() throws IOException {
          try {
              /* Note that we don't want to physically disconnect the tag,
               * but just reconnect to it to reset its state
               */
              mTag.getTagService().resetTimeouts();
              mTag.getTagService().reconnect(mTag.getServiceHandle());
          } catch (RemoteException e) {
              Log.e(TAG, "NFC service dead", e);
          } finally {
              mIsConnected = false;
              mTag.setTechnologyDisconnected();
          }
      }
  
      /** Internal getMaxTransceiveLength() */
      int getMaxTransceiveLengthInternal() {
          try {
              return mTag.getTagService().getMaxTransceiveLength(mSelectedTechnology);
          } catch (RemoteException e) {
              Log.e(TAG, "NFC service dead", e);
              return 0;
          }
      }
      /** Internal transceive */
      byte[] transceive(byte[] data, boolean raw) throws IOException {
          checkConnected();
  
          try {
              TransceiveResult result = mTag.getTagService().transceive(mTag.getServiceHandle(),
                      data, raw);
              if (result == null) {
                  throw new IOException("transceive failed");
              } else {
                  return result.getResponseOrThrow();
              }
          } catch (RemoteException e) {
              Log.e(TAG, "NFC service dead", e);
              throw new IOException("NFC service died");
          }
      }
  }
  