[NFC][Non-ACR] Fix NFC Csharp TC failed issue (#1849)
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Nfc / Tizen.Network.Nfc / NfcTag.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Runtime.InteropServices;
19 using System.Collections.Generic;
20 using System.Threading.Tasks;
21
22 namespace Tizen.Network.Nfc
23 {
24     /// <summary>
25     /// The class for managing the Tag information.
26     /// </summary>
27     /// <since_tizen> 3 </since_tizen>
28     public class NfcTag : IDisposable
29     {
30         private bool disposed = false;
31         private IntPtr _tagHandle = IntPtr.Zero;
32         int _requestId = 0;
33
34         Dictionary<int, TaskCompletionSource<byte[]>> _transceiveTaskSource = new Dictionary<int, TaskCompletionSource<byte[]>>();
35         Interop.Nfc.TagTransceiveCompletedCallback _nativeTransceiveCallback;
36
37         Dictionary<int, TaskCompletionSource<NfcError>> _voidTaskSource = new Dictionary<int, TaskCompletionSource<NfcError>>();
38         Interop.Nfc.VoidCallback _nativeVoidCallback;
39
40         Dictionary<int, TaskCompletionSource<NfcNdefMessage>> _readNdefTaskSource = new Dictionary<int, TaskCompletionSource<NfcNdefMessage>>();
41         Interop.Nfc.TagReadCompletedCallback _nativeTagReadCallback;
42
43         /// <summary>
44         /// Constructor of NfcTag
45         /// </summary>
46         public NfcTag()
47         {
48             // A method is need to convert delegate to pass unmanaged layer through Interop call
49             // If we do not convert explicitly it, implicitly convert was occurred
50             // and temporal delegate was created. and it could be released by GC
51             _nativeTransceiveCallback = TransceiveCompletedCallback;
52             _nativeVoidCallback = VoidCallback;
53             _nativeTagReadCallback = ReadNdefCallback;
54         }
55
56         /// <summary>
57         /// The type of the NFC tag.
58         /// </summary>
59         /// <since_tizen> 3 </since_tizen>
60         public NfcTagType Type
61         {
62             get
63             {
64                 int type;
65                 int ret = Interop.Nfc.Tag.GetType(_tagHandle, out type);
66                 if (ret != (int)NfcError.None)
67                 {
68                     Log.Error(Globals.LogTag, "Failed to get tag type, Error - " + (NfcError)ret);
69                 }
70                 return (NfcTagType)type;
71             }
72         }
73
74         /// <summary>
75         /// Whether the given NFC tag supports the NDEF messages.
76         /// </summary>
77         /// <since_tizen> 3 </since_tizen>
78         public bool IsSupportNdef
79         {
80             get
81             {
82                 bool isSupport;
83                 int ret = Interop.Nfc.Tag.IsSupportNdef(_tagHandle, out isSupport);
84                 if (ret != (int)NfcError.None)
85                 {
86                     Log.Error(Globals.LogTag, "Failed to get support state, Error - " + (NfcError)ret);
87                 }
88                 return isSupport;
89
90             }
91         }
92
93         /// <summary>
94         /// The maximum NDEF message size that can be stored in the NFC tag.
95         /// </summary>
96         /// <since_tizen> 3 </since_tizen>
97         public uint MaximumNdefSize
98         {
99             get
100             {
101                 uint maxSize;
102                 int ret = Interop.Nfc.Tag.GetMaximumNdefSize(_tagHandle, out maxSize);
103                 if (ret != (int)NfcError.None)
104                 {
105                     Log.Error(Globals.LogTag, "Failed to get max ndef size, Error - " + (NfcError)ret);
106                 }
107                 return maxSize;
108             }
109         }
110
111         /// <summary>
112         /// The size of the NDEF message stored in the tag.
113         /// </summary>
114         /// <since_tizen> 3 </since_tizen>
115         public uint NdefSize
116         {
117             get
118             {
119                 uint ndefSize;
120                 int ret = Interop.Nfc.Tag.GetNdefSize(_tagHandle, out ndefSize);
121                 if (ret != (int)NfcError.None)
122                 {
123                     Log.Error(Globals.LogTag, "Failed to get ndef size, Error - " + (NfcError)ret);
124                 }
125                 return ndefSize;
126             }
127         }
128
129         internal NfcTag(IntPtr handle)
130         {
131             _tagHandle = handle;
132             _nativeTransceiveCallback = TransceiveCompletedCallback;
133             _nativeVoidCallback = VoidCallback;
134             _nativeTagReadCallback = ReadNdefCallback;
135         }
136
137         /// <summary>
138         /// NfcTag destructor.
139         /// </summary>
140         ~NfcTag()
141         {
142             Dispose(false);
143         }
144
145         /// <summary>
146         /// Dispose
147         /// </summary>
148         /// <since_tizen> 3 </since_tizen>
149         public void Dispose()
150         {
151             Dispose(true);
152             GC.SuppressFinalize(this);
153         }
154
155         private void Dispose(bool disposing)
156         {
157             if (disposed)
158                 return;
159
160             if (disposing)
161             {
162                 // Free managed objects.
163             }
164             //Free unmanaged objects
165             disposed = true;
166         }
167
168         /// <summary>
169         /// Retrieves all the tag information.
170         /// </summary>
171         /// <since_tizen> 3 </since_tizen>
172         /// <returns>The list of the NfcTagInformation objects.</returns>
173         /// <privilege>http://tizen.org/privilege/nfc</privilege>
174         /// <exception cref="NotSupportedException">Thrown when the NFC is not supported.</exception>
175         /// <exception cref="InvalidOperationException">Thrown when the method fails due to an invalid operation.</exception>
176         public IEnumerable<NfcTagInformation> ForeachInformation()
177         {
178             List<NfcTagInformation> infoList = new List<NfcTagInformation>();
179             Interop.Nfc.TagInformationCallback callback = (IntPtr key, IntPtr infoValue, int valueSize, IntPtr userData) =>
180             {
181                 if (key != IntPtr.Zero && infoValue != IntPtr.Zero)
182                 {
183                     NfcTagInformation tagInfo = new NfcTagInformation(Marshal.PtrToStringAnsi(key), new byte[valueSize]);
184
185                     Marshal.Copy(infoValue, tagInfo.InformationValue, 0, valueSize);
186
187                     infoList.Add(tagInfo);
188
189                     return true;
190                 }
191                 return false;
192             };
193
194             int ret = Interop.Nfc.Tag.ForeachInformation(_tagHandle, callback, IntPtr.Zero);
195             if (ret != (int)NfcError.None)
196             {
197                 Log.Error(Globals.LogTag, "Failed to get all Tag information, Error - " + (NfcError)ret);
198                 NfcErrorFactory.ThrowNfcException(ret);
199             }
200
201             return infoList;
202         }
203
204         /// <summary>
205         /// Transceives the data of the raw format card.
206         /// </summary>
207         /// <since_tizen> 3 </since_tizen>
208         /// <param name="buffer">The binary data for a parameter or additional commands.</param>
209         /// <privilege>http://tizen.org/privilege/nfc</privilege>
210         /// <exception cref="NotSupportedException">Thrown when the NFC is not supported.</exception>
211         /// <exception cref="ArgumentException">Thrown when the method fails due to an invalid parameter.</exception>
212         /// <exception cref="InvalidOperationException">Thrown when the the method fails due to an invalid operation.</exception>
213         public Task<byte[]> TransceiveAsync(byte[] buffer)
214         {
215             int requestId = 0;
216             var task = new TaskCompletionSource<byte[]>();
217             lock (this)
218             {
219                 requestId = _requestId++;
220                 _transceiveTaskSource[requestId] = task;
221             }
222
223             int ret = Interop.Nfc.Tag.Transceive(_tagHandle, buffer, buffer.Length, _nativeTransceiveCallback, (IntPtr)requestId);
224             if (ret != (int)NfcError.None)
225             {
226                 Log.Error(Globals.LogTag, "Failed to transceive data, Error - " + (NfcError)ret);
227                 _transceiveTaskSource.Remove(requestId);
228                 NfcErrorFactory.ThrowNfcException(ret);
229             }
230             return task.Task;
231         }
232
233         /// <summary>
234         /// Reads the NDEF formatted data from the NFC tag.
235         /// </summary>
236         /// <since_tizen> 3 </since_tizen>
237         /// <privilege>http://tizen.org/privilege/nfc</privilege>
238         /// <exception cref="NotSupportedException">Thrown when the NFC is not supported.</exception>
239         /// <exception cref="InvalidOperationException">Thrown when the method fails due to an invalid operation.</exception>
240         public Task<NfcNdefMessage> ReadNdefMessageAsync()
241         {
242             int requestId = 0;
243             var task = new TaskCompletionSource<NfcNdefMessage>();
244
245             lock (this)
246             {
247                 requestId = _requestId++;
248                 _readNdefTaskSource[requestId] = task;
249             }
250
251             int ret = Interop.Nfc.Tag.ReadNdef(_tagHandle, _nativeTagReadCallback, (IntPtr)requestId);
252             if (ret != (int)NfcError.None)
253             {
254                 Log.Error(Globals.LogTag, "Failed to read ndef message, Error - " + (NfcError)ret);
255                 _readNdefTaskSource.Remove(requestId);
256                 NfcErrorFactory.ThrowNfcException(ret);
257             }
258             return task.Task;
259         }
260
261         /// <summary>
262         /// Writes the NDEF formatted data.
263         /// </summary>
264         /// <since_tizen> 3 </since_tizen>
265         /// <param name="ndefMessage">The NfcNdefMessage object.</param>
266         /// <privilege>http://tizen.org/privilege/nfc</privilege>
267         /// <exception cref="NotSupportedException">Thrown when the NFC is not supported.</exception>
268         /// <exception cref="ArgumentException">Thrown when the method fails due to an invalid parameter.</exception>
269         /// <exception cref="InvalidOperationException">Thrown when the method fails due to an invalid operation.</exception>
270         public Task<NfcError> WriteNdefMessageAsync(NfcNdefMessage ndefMessage)
271         {
272             int requestId = 0;
273             var task = new TaskCompletionSource<NfcError>();
274
275             lock (this)
276             {
277                 requestId = _requestId++;
278                 _voidTaskSource[requestId] = task;
279             }
280
281             int ret = Interop.Nfc.Tag.WriteNdef(_tagHandle, ndefMessage.GetHandle(), _nativeVoidCallback, (IntPtr)requestId);
282
283             if (ret != (int)NfcError.None)
284             {
285                 Log.Error(Globals.LogTag, "Failed to write ndef message, Error - " + (NfcError)ret);
286                 _voidTaskSource.Remove(requestId);
287                 NfcErrorFactory.ThrowNfcException(ret);
288             }
289
290             return task.Task;
291         }
292
293         /// <summary>
294         /// Formats the detected tag that can store the NDEF message.
295         /// </summary>
296         /// <since_tizen> 3 </since_tizen>
297         /// <param name="keyValue">The key value that may need to format the tag.</param>
298         /// <privilege>http://tizen.org/privilege/nfc</privilege>
299         /// <exception cref="NotSupportedException">Thrown when the NFC is not supported.</exception>
300         /// <exception cref="ArgumentException">Thrown when method fails due to an invalid parameter.</exception>
301         /// <exception cref="InvalidOperationException">Thrown when the method fails due to an invalid operation.</exception>
302         public Task<NfcError> FormatNdefMessageAsync(byte[] keyValue)
303         {
304             int requestId = 0;
305             var task = new TaskCompletionSource<NfcError>();
306
307             lock (this)
308             {
309                 requestId = _requestId++;
310                 _voidTaskSource[requestId] = task;
311             }
312
313             int ret = Interop.Nfc.Tag.FormatNdef(_tagHandle, keyValue, keyValue.Length, _nativeVoidCallback, (IntPtr)requestId);
314             if (ret != (int)NfcError.None)
315             {
316                 Log.Error(Globals.LogTag, "Failed to format ndef message, Error - " + (NfcError)ret);
317                 _voidTaskSource.Remove(requestId);
318                 NfcErrorFactory.ThrowNfcException(ret);
319             }
320
321             return task.Task;
322         }
323
324         void TransceiveCompletedCallback(int result, IntPtr resultData, int dataSize, IntPtr userData)
325         {
326             int requestId = (int)userData;
327             if (_transceiveTaskSource.ContainsKey(requestId))
328             {
329                 if (result == (int)NfcError.None)
330                 {
331                     byte[] resultBuffer = new byte[dataSize];
332                     Marshal.Copy(resultData, resultBuffer, 0, dataSize);
333                     _transceiveTaskSource[requestId].TrySetResult(resultBuffer);
334                 }
335                 _transceiveTaskSource.Remove(requestId);
336             }
337             return;
338         }
339
340         void VoidCallback(int result, IntPtr userData)
341         {
342             int requestId = (int)userData;
343             if (_voidTaskSource.ContainsKey(requestId))
344             {
345                 _voidTaskSource[requestId].TrySetResult((NfcError)result);
346                 _voidTaskSource.Remove(requestId);
347             }
348         }
349
350         bool ReadNdefCallback(int result, IntPtr ndefMessage, IntPtr userData)
351         {
352             bool ret = false;
353             int requestId = (int)userData;
354             if (_readNdefTaskSource.ContainsKey(requestId))
355             {
356                 if (result == (int)NfcError.None)
357                 {
358                     var ndefMsg = new NfcNdefMessage(ndefMessage);
359                     _readNdefTaskSource[requestId].TrySetResult(ndefMsg);
360                     ret = true;
361                 }
362                 _readNdefTaskSource.Remove(requestId);
363             }
364             return ret;
365         }
366     }
367 }