Merge "Revert "Revert "Update for less arguments in hidl toBinder."""
diff --git a/Android.mk b/Android.mk
index 8179748..d05feb5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -230,6 +230,7 @@
 	core/java/android/nfc/INfcCardEmulation.aidl \
 	core/java/android/nfc/INfcFCardEmulation.aidl \
 	core/java/android/nfc/INfcUnlockHandler.aidl \
+	core/java/android/nfc/INfcDta.aidl \
 	core/java/android/nfc/ITagRemovedCallback.aidl \
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index f991efe..6801618 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -29,6 +29,7 @@
 import android.nfc.INfcFCardEmulation;
 import android.nfc.INfcUnlockHandler;
 import android.nfc.ITagRemovedCallback;
+import android.nfc.INfcDta;
 import android.os.Bundle;
 
 /**
@@ -40,7 +41,7 @@
     INfcCardEmulation getNfcCardEmulationInterface();
     INfcFCardEmulation getNfcFCardEmulationInterface();
     INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
-
+    INfcDta getNfcDtaInterface(in String pkg);
     int getState();
     boolean disable(boolean saveState);
     boolean enable();
diff --git a/core/java/android/nfc/INfcDta.aidl b/core/java/android/nfc/INfcDta.aidl
new file mode 100644
index 0000000..4cc5927
--- /dev/null
+++ b/core/java/android/nfc/INfcDta.aidl
@@ -0,0 +1,34 @@
+ /*
+  * Copyright (C) 2017 NXP Semiconductors
+  *
+  * 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;
+
+import android.os.Bundle;
+
+/**
+ * {@hide}
+ */
+interface INfcDta {
+
+    void enableDta();
+    void disableDta();
+    boolean enableServer(String serviceName, int serviceSap, int miu,
+            int rwSize,int testCaseId);
+    void disableServer();
+    boolean enableClient(String serviceName, int miu, int rwSize,
+            int testCaseId);
+    void disableClient();
+    boolean registerMessageService(String msgServiceName);
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 783c25a..fab494a 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,8 +16,6 @@
 
 package android.nfc;
 
-import java.util.HashMap;
-
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
@@ -42,6 +40,7 @@
 import android.util.Log;
 
 import java.io.IOException;
+import java.util.HashMap;
 
 /**
  * Represents the local NFC adapter.
@@ -626,6 +625,23 @@
     }
 
     /**
+     * Returns the binder interface to the NFC-DTA test interface.
+     * @hide
+     */
+    public INfcDta getNfcDtaInterface() {
+        if (mContext == null) {
+            throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+                    + " NFC extras APIs");
+        }
+        try {
+            return sService.getNfcDtaInterface(mContext.getPackageName());
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return null;
+        }
+    }
+
+    /**
      * NFC service dead - attempt best effort recovery
      * @hide
      */
diff --git a/core/java/android/nfc/dta/NfcDta.java b/core/java/android/nfc/dta/NfcDta.java
new file mode 100644
index 0000000..8801662
--- /dev/null
+++ b/core/java/android/nfc/dta/NfcDta.java
@@ -0,0 +1,167 @@
+/*
+ * 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.nfc.dta;
+
+import android.content.Context;
+import android.nfc.INfcDta;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * This class provides the primary API for DTA operations.
+ * @hide
+ */
+public final class NfcDta {
+    private static final String TAG = "NfcDta";
+
+    private static INfcDta sService;
+    private static HashMap<Context, NfcDta> sNfcDtas = new HashMap<Context, NfcDta>();
+
+    private final Context mContext;
+
+    private NfcDta(Context context, INfcDta service) {
+        mContext = context.getApplicationContext();
+        sService = service;
+    }
+
+    /**
+     * Helper to get an instance of this class.
+     *
+     * @param adapter A reference to an NfcAdapter object.
+     * @return
+     */
+    public static synchronized NfcDta getInstance(NfcAdapter adapter) {
+        if (adapter == null) throw new NullPointerException("NfcAdapter is null");
+        Context context = adapter.getContext();
+        if (context == null) {
+            Log.e(TAG, "NfcAdapter context is null.");
+            throw new UnsupportedOperationException();
+        }
+
+        NfcDta manager = sNfcDtas.get(context);
+        if (manager == null) {
+            INfcDta service = adapter.getNfcDtaInterface();
+            if (service == null) {
+                Log.e(TAG, "This device does not implement the INfcDta interface.");
+                throw new UnsupportedOperationException();
+            }
+            manager = new NfcDta(context, service);
+            sNfcDtas.put(context, manager);
+        }
+        return manager;
+    }
+
+    /**
+     * Enables DTA mode
+     *
+     * @return true/false if enabling was successful
+     */
+    public boolean enableDta() {
+        try {
+            sService.enableDta();
+        } catch (RemoteException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Disables DTA mode
+     *
+     * @return true/false if disabling was successful
+     */
+    public boolean disableDta() {
+        try {
+            sService.disableDta();
+        } catch (RemoteException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Enables Server
+     *
+     * @return true/false if enabling was successful
+     */
+    public boolean enableServer(String serviceName, int serviceSap, int miu,
+            int rwSize, int testCaseId) {
+        try {
+            return sService.enableServer(serviceName, serviceSap, miu, rwSize, testCaseId);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Disables Server
+     *
+     * @return true/false if disabling was successful
+     */
+    public boolean disableServer() {
+        try {
+            sService.disableServer();
+        } catch (RemoteException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Enables Client
+     *
+     * @return true/false if enabling was successful
+     */
+    public boolean enableClient(String serviceName, int miu, int rwSize,
+            int testCaseId) {
+        try {
+            return sService.enableClient(serviceName, miu, rwSize, testCaseId);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Disables client
+     *
+     * @return true/false if disabling was successful
+     */
+    public boolean disableClient() {
+        try {
+            sService.disableClient();
+        } catch (RemoteException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Registers Message Service
+     *
+     * @return true/false if registration was successful
+     */
+    public boolean registerMessageService(String msgServiceName) {
+        try {
+            return sService.registerMessageService(msgServiceName);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java
index c747b84..4c3f7e7 100644
--- a/telephony/java/android/telephony/MbmsDownloadManager.java
+++ b/telephony/java/android/telephony/MbmsDownloadManager.java
@@ -211,9 +211,9 @@
     private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
 
     private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null);
-    private final IMbmsDownloadManagerCallback mCallback;
+    private final MbmsDownloadManagerCallback mCallback;
 
-    private MbmsDownloadManager(Context context, IMbmsDownloadManagerCallback callback, int subId) {
+    private MbmsDownloadManager(Context context, MbmsDownloadManagerCallback callback, int subId) {
         mContext = context;
         mCallback = callback;
         mSubscriptionId = subId;
@@ -221,12 +221,12 @@
 
     /**
      * Create a new MbmsDownloadManager using the system default data subscription ID.
-     * See {@link #create(Context, IMbmsDownloadManagerCallback, int)}
+     * See {@link #create(Context, MbmsDownloadManagerCallback, int)}
      *
      * @hide
      */
     public static MbmsDownloadManager create(Context context,
-            IMbmsDownloadManagerCallback listener)
+            MbmsDownloadManagerCallback listener)
             throws MbmsException {
         return create(context, listener, SubscriptionManager.getDefaultSubscriptionId());
     }
@@ -247,7 +247,7 @@
      * @hide
      */
     public static MbmsDownloadManager create(Context context,
-            IMbmsDownloadManagerCallback listener, int subscriptionId)
+            MbmsDownloadManagerCallback listener, int subscriptionId)
             throws MbmsException {
         MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, subscriptionId);
         mdm.bindAndInitialize();
@@ -261,11 +261,22 @@
                     public void onServiceConnected(ComponentName name, IBinder service) {
                         IMbmsDownloadService downloadService =
                                 IMbmsDownloadService.Stub.asInterface(service);
+                        int result;
                         try {
-                            downloadService.initialize(mSubscriptionId, mCallback);
+                            result = downloadService.initialize(mSubscriptionId, mCallback);
                         } catch (RemoteException e) {
                             Log.e(LOG_TAG, "Service died before initialization");
                             return;
+                        } catch (RuntimeException e) {
+                            Log.e(LOG_TAG, "Runtime exception during initialization");
+                            mCallback.error(
+                                    MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                                    e.toString());
+                            return;
+                        }
+                        if (result != MbmsException.SUCCESS) {
+                            mCallback.error(result, "Error returned during initialization");
+                            return;
                         }
                         mService.set(downloadService);
                     }
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index 5b3503a..911f83f 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -51,10 +51,10 @@
     private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
 
     /** @hide */
-    private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback listener,
+    private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback callback,
                     int subscriptionId) {
         mContext = context;
-        mCallbackToApp = listener;
+        mCallbackToApp = callback;
         mSubscriptionId = subscriptionId;
     }
 
@@ -66,14 +66,14 @@
      * during the initialization or binding process.
      *
      * @param context The {@link Context} to use.
-     * @param listener A callback object on which you wish to receive results of asynchronous
+     * @param callback A callback object on which you wish to receive results of asynchronous
      *                 operations.
      * @param subscriptionId The subscription ID to use.
      */
     public static MbmsStreamingManager create(Context context,
-            MbmsStreamingManagerCallback listener, int subscriptionId)
+            MbmsStreamingManagerCallback callback, int subscriptionId)
             throws MbmsException {
-        MbmsStreamingManager manager = new MbmsStreamingManager(context, listener, subscriptionId);
+        MbmsStreamingManager manager = new MbmsStreamingManager(context, callback, subscriptionId);
         manager.bindAndInitialize();
         return manager;
     }
@@ -83,9 +83,9 @@
      * See {@link #create(Context, MbmsStreamingManagerCallback, int)}.
      */
     public static MbmsStreamingManager create(Context context,
-            MbmsStreamingManagerCallback listener)
+            MbmsStreamingManagerCallback callback)
             throws MbmsException {
-        return create(context, listener, SubscriptionManager.getDefaultSubscriptionId());
+        return create(context, callback, SubscriptionManager.getDefaultSubscriptionId());
     }
 
     /**
@@ -195,11 +195,22 @@
                     public void onServiceConnected(ComponentName name, IBinder service) {
                         IMbmsStreamingService streamingService =
                                 IMbmsStreamingService.Stub.asInterface(service);
+                        int result;
                         try {
-                            streamingService.initialize(mCallbackToApp, mSubscriptionId);
+                            result = streamingService.initialize(mCallbackToApp, mSubscriptionId);
                         } catch (RemoteException e) {
                             Log.e(LOG_TAG, "Service died before initialization");
                             return;
+                        } catch (RuntimeException e) {
+                            Log.e(LOG_TAG, "Runtime exception during initialization");
+                            mCallbackToApp.error(
+                                    MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                                    e.toString());
+                            return;
+                        }
+                        if (result != MbmsException.SUCCESS) {
+                            mCallbackToApp.error(result, "Error returned during initialization");
+                            return;
                         }
                         mService.set(streamingService);
                     }
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index 3617165..339ff39 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -356,7 +356,7 @@
                 intent.getParcelableExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO);
         File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context,
                 serviceInfo.getServiceId());
-        List<Uri> filesInUse =
+        final List<Uri> filesInUse =
                 intent.getParcelableArrayListExtra(MbmsDownloadManager.EXTRA_TEMP_FILES_IN_USE);
         File[] filesToDelete = tempFileDir.listFiles(new FileFilter() {
             @Override
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index 1a64189..c49f8a9 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -50,10 +50,15 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({REASON_BY_USER_REQUEST, REASON_END_OF_SESSION, REASON_FREQUENCY_CONFLICT,
             REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE,
-            REASON_LEFT_MBMS_BROADCAST_AREA})
+            REASON_LEFT_MBMS_BROADCAST_AREA, REASON_NONE})
     public @interface StreamingStateChangeReason {}
 
     /**
+     * Indicates that the middleware does not have a reason to provide for the state change.
+     */
+    public static final int REASON_NONE = 0;
+
+    /**
      * State changed due to a call to {@link #stopStreaming()} or
      * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, StreamingServiceCallback)}
      */
@@ -167,7 +172,7 @@
      *
      * This may throw a {@link MbmsException} with the error code
      * {@link MbmsException#ERROR_MIDDLEWARE_LOST}
-     * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+     * May also throw an {@link IllegalStateException}
      */
     public void dispose() throws MbmsException {
         if (mService == null) {
@@ -179,6 +184,8 @@
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "Remote process died");
             throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
+        } catch (IllegalArgumentException e) {
+            throw new IllegalStateException("StreamingService state inconsistent with middleware");
         } finally {
             mService = null;
         }
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
index 0a76f32..dfcc5f7 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -28,7 +28,7 @@
  */
 interface IMbmsDownloadService
 {
-    void initialize(int subId, IMbmsDownloadManagerCallback listener);
+    int initialize(int subId, IMbmsDownloadManagerCallback listener);
 
     int getFileServices(int subId, in List<String> serviceClasses);
 
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
index 04a53cb..4dd4292 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -26,7 +26,7 @@
  */
 interface IMbmsStreamingService
 {
-    void initialize(IMbmsStreamingManagerCallback listener, int subId);
+    int initialize(IMbmsStreamingManagerCallback listener, int subId);
 
     int getStreamingServices(int subId, in List<String> serviceClasses);
 
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index d725d9f..edd5858 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -36,16 +36,21 @@
     /**
      * Initialize the download service for this app and subId, registering the listener.
      *
-     * Exceptions should not be thrown through this method -- this method is called from within a
-     * {@link android.content.ServiceConnection} defined by the framework, so apps have no way of
-     * catching them. Call {@link IMbmsDownloadManagerCallback#error(int, String)} instead.
+     * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}, which
+     * will be intercepted and passed to the app as
+     * {@link android.telephony.mbms.MbmsException.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE}
+     *
+     * May return any value from {@link android.telephony.mbms.MbmsException.InitializationErrors}
+     * or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via
+     * {@link IMbmsDownloadManagerCallback#error(int, String)}.
      *
      * @param listener The callback to use to communicate with the app.
      * @param subscriptionId The subscription ID to use.
      */
     @Override
-    public void initialize(int subscriptionId,
+    public int initialize(int subscriptionId,
             IMbmsDownloadManagerCallback listener) throws RemoteException {
+        return 0;
     }
 
     /**
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index f072c46..585d5b9 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -33,17 +33,21 @@
     /**
      * Initialize streaming service for this app and subId, registering the listener.
      *
-     * Exceptions should not be thrown through this method -- this method is called from within a
-     * {@link android.content.ServiceConnection} defined by the framework, so apps have no way of
-     * catching them. Call {@link IMbmsStreamingManagerCallback#error(int, String)} instead.
+     * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}, which
+     * will be intercepted and passed to the app as
+     * {@link android.telephony.mbms.MbmsException.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE}
+     *
+     * May return any value from {@link android.telephony.mbms.MbmsException.InitializationErrors}
+     * or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via
+     * {@link IMbmsStreamingManagerCallback#error(int, String)}.
      *
      * @param listener The callback to use to communicate with the app.
      * @param subscriptionId The subscription ID to use.
      */
     @Override
-    public void initialize(IMbmsStreamingManagerCallback listener, int subscriptionId)
+    public int initialize(IMbmsStreamingManagerCallback listener, int subscriptionId)
             throws RemoteException {
-        return;
+        return 0;
     }
 
     /**