Merge remote-tracking branch 'media-key/tizen'
[platform/core/csapi/tizenfx.git] / src / Tizen.Account.AccountManager / Tizen.Account.AccountManager / AccountService.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.Collections.Generic;
19
20 namespace Tizen.Account.AccountManager
21 {
22     /// <summary>
23     /// The AccountManager APIs is separated into two major sections:
24     /// 1. Registering an account provider while an application is installed. This information will be used for the Add account screen.
25     /// 2. Adding an account information when an application signs in successfully to share the account information to the Tizen system. This information will be shown in the Tizen settings account menu.
26     ///
27     /// The APIs of both of the sections consist of the following functionality:
28     /// <list>
29     /// <item> Create an account or account provider </item>
30     /// <item> Update an account or account provider(Only available for the creator) </item>
31     /// <item> Delete an account or account provider(Only available for the creator) </item>
32     /// <item> Read an account or account provider with some filter </item>
33     /// </list>
34     /// </summary>
35     /// <since_tizen> 3 </since_tizen>
36
37     public static class AccountService
38     {
39         /// <summary>
40         /// This is contact capability string.
41         /// </summary>
42         /// <since_tizen> 3 </since_tizen>
43         public static readonly string ContactCapability = "http://tizen.org/account/capability/contact";
44
45         /// <summary>
46         /// This is calendar capability string.
47         /// </summary>
48         /// <since_tizen> 3 </since_tizen>
49         public static readonly string CalendarCapability = "http://tizen.org/account/capability/calendar";
50
51         /// <summary>
52         /// This is email capability string.
53         /// </summary>
54         /// <since_tizen> 3 </since_tizen>
55         public static readonly string EmailCapability = "http://tizen.org/account/capability/email";
56
57         /// <summary>
58         /// This is photo capability string.
59         /// </summary>
60         /// <since_tizen> 3 </since_tizen>
61         public static readonly string PhotoCapability = "http://tizen.org/account/capability/photo";
62
63         /// <summary>
64         /// This is video capability string.
65         /// </summary>
66         /// <since_tizen> 3 </since_tizen>
67         public static readonly string VideoCapability = "http://tizen.org/account/capability/video";
68
69         /// <summary>
70         /// This is music capability string.
71         /// </summary>
72         /// <since_tizen> 3 </since_tizen>
73         public static readonly string MusicCapability = "http://tizen.org/account/capability/music";
74
75         /// <summary>
76         /// This is document capability string.
77         /// </summary>
78         /// <since_tizen> 3 </since_tizen>
79         public static readonly string DocumentCapability = "http://tizen.org/account/capability/document";
80
81         /// <summary>
82         /// This is message capability string.
83         /// </summary>
84         /// <since_tizen> 3 </since_tizen>
85         public static readonly string MessageCapability = "http://tizen.org/account/capability/message";
86
87         /// <summary>
88         /// This is game capability string.
89         /// </summary>
90         /// <since_tizen> 3 </since_tizen>
91         public static readonly string GameCapability = "http://tizen.org/account/capability/game";
92
93         /// <summary>
94         /// Retrieves all accounts details from the account database.
95         /// </summary>
96         /// <since_tizen> 3 </since_tizen>
97         /// <returns>List of Accounts</returns>
98         /// <privilege>http://tizen.org/privilege/account.read</privilege>
99         /// <exception cref="InvalidOperationException">In case of any DB error. </exception>
100         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
101         public static IEnumerable<Account> GetAccountsAsync()
102         {
103             List<Account> accounts = new List<Account>();
104             List<int> values = new List<int>();
105             Interop.Account.AccountCallback accountCallback = (IntPtr data, IntPtr userdata) =>
106             {
107                 Account account = new Account(data);
108                 values.Add(account.AccountId);
109                 account.Dispose();
110                 return true;
111             };
112
113             AccountError res = (AccountError)Interop.AccountService.AccountForeachAccountFromDb(accountCallback, IntPtr.Zero);
114             if (res != AccountError.None)
115             {
116                 throw AccountErrorFactory.CreateException(res, "Failed to AccountForeachAccountFromDb");
117             }
118
119             foreach (int i in values)
120             {
121                 Account account = AccountService.GetAccountById(i);
122                 accounts.Add(account);
123             }
124
125             return accounts;
126         }
127
128         /// <summary>
129         /// Retrieve an account with the account ID.
130         /// </summary>
131         /// <since_tizen> 3 </since_tizen>
132         /// <param name="accountId"> The account Id to be searched.</param>
133         /// <returns>Account instance with reference to the given id.</returns>
134         /// <privilege>http://tizen.org/privilege/account.read</privilege>
135         /// <exception cref="InvalidOperationException">In case of any DB error or record not found for given account id</exception>
136         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
137         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
138         public static Account GetAccountById(int accountId)
139         {
140             Account account = Account.CreateAccount();
141             IntPtr handle = account.Handle;
142             AccountError res = (AccountError)Interop.AccountService.QueryAccountById(accountId, out handle);
143             if (res != AccountError.None)
144             {
145                 throw AccountErrorFactory.CreateException(res, "Failed to get accounts from the database for account id: " + accountId);
146             }
147
148             account.Handle = handle;
149             return account;
150         }
151
152         /// <summary>
153         /// Retrieves all AccountProviders details from the account database.
154         /// </summary>
155         /// <since_tizen> 3 </since_tizen>
156         /// <returns>List of AccountProviders</returns>
157         /// <privilege>http://tizen.org/privilege/account.read</privilege>
158         /// <exception cref="InvalidOperationException">In case of any DB error</exception>
159         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
160         public static IEnumerable<AccountProvider> GetAccountProviders()
161         {
162             List<string> values = new List<string>();
163             List<AccountProvider> providers = new List<AccountProvider>();
164             Interop.AccountProvider.AccountProviderCallback accountCallback = (IntPtr handle, IntPtr data) =>
165             {
166                 AccountProvider provider = new AccountProvider(handle);
167                 values.Add(provider.AppId);
168                 provider.Dispose();
169                 return true;
170             };
171
172             AccountError res = (AccountError)Interop.AccountService.GetAllAccountproviders(accountCallback, IntPtr.Zero);
173             if (res != AccountError.None)
174             {
175                 Log.Warn(AccountErrorFactory.LogTag, "Failed to get account providers from the database");
176                 throw AccountErrorFactory.CreateException(res, "Failed to get account providers from the database");
177             }
178
179             foreach (string val in values)
180             {
181                 AccountProvider provider = GetAccountProviderByAppId(val);
182                 providers.Add(provider);
183             }
184
185             return providers;
186         }
187
188         /// <summary>
189         /// Retrieves the account provider information with application Id.
190         /// </summary>
191         /// <since_tizen> 3 </since_tizen>
192         /// <param name="appId">Application Id.</param>
193         /// <returns>The AccountProvider instance associated with the given application Id.</returns>
194         /// <privilege>http://tizen.org/privilege/account.read</privilege>
195         /// <exception cref="InvalidOperationException">In case of any DB error or record not found for given appid</exception>
196         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
197         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
198         public static AccountProvider GetAccountProviderByAppId(string appId)
199         {
200             IntPtr handle;
201             Interop.AccountProvider.Create(out handle);
202             AccountError err = (AccountError)Interop.AccountService.GetAccountProviderByAppId(appId, out handle);
203             if (err != AccountError.None)
204             {
205                 throw AccountErrorFactory.CreateException(err, "Failed to GetAccountProviderByAppId");
206             }
207
208             AccountProvider provider = new AccountProvider(handle);
209             return provider;
210         }
211
212         /// <summary>
213         /// Retrieves all the account providers information with feature.
214         /// </summary>
215         /// <since_tizen> 3 </since_tizen>
216         /// <param name="feature">The capability value to search for account providers.</param>
217         /// <returns>Retrieves AccountProviders information with the capability name.</returns>
218         /// <privilege>http://tizen.org/privilege/account.read</privilege>
219         /// <exception cref="InvalidOperationException">In case of any DB error or record not found for given feature</exception>
220         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
221         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
222         public static IEnumerable<AccountProvider> GetAccountProvidersByFeature(string feature)
223         {
224             List<string> values = new List<string>();
225             List<AccountProvider> providers = new List<AccountProvider>();
226             Interop.AccountProvider.AccountProviderCallback providerCallback = (IntPtr handle, IntPtr data) =>
227             {
228                 AccountProvider provider = new AccountProvider(handle);
229                 values.Add(provider.AppId);
230                 provider.Dispose();
231                 return true;
232             };
233
234             AccountError err = (AccountError)Interop.AccountService.GetAccountProviderByFeature(providerCallback, feature, IntPtr.Zero);
235             if (err != AccountError.None)
236             {
237                 throw AccountErrorFactory.CreateException(err, "Failed to GetAccountProviderByFeature");
238             }
239
240             foreach (string val in values)
241             {
242                 AccountProvider provider = GetAccountProviderByAppId(val);
243                 providers.Add(provider);
244             }
245
246             return providers;
247         }
248
249         /// <summary>
250         /// Inserts into the Database with the new account Infomration.
251         /// </summary>
252         /// <since_tizen> 3 </since_tizen>
253         /// <param name="account">New Account instance to be added.</param>
254         /// <privilege>http://tizen.org/privilege/account.read</privilege>
255         /// <privilege>http://tizen.org/privilege/account.write </privilege>
256         /// <exception cref="InvalidOperationException">In case of any DB error</exception>
257         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
258         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
259         /// <exception cref="OutOfMemoryException"> In case of OutOfMemory error.</exception>
260         public static int AddAccount(Account account)
261         {
262             if (account == null)
263             {
264                 throw AccountErrorFactory.CreateException(AccountError.InvalidParameter, "Failed to AddAccount");
265             }
266
267             int id = -1;
268             AccountError err = (AccountError)Interop.AccountService.AddAccount(account.Handle, out id);
269             if (err != AccountError.None)
270             {
271                 throw AccountErrorFactory.CreateException(err, "Failed to AddAccount");
272             }
273
274             return id;
275         }
276
277         /// <summary>
278         /// Updates the account details to the account database.
279         /// </summary>
280         /// <since_tizen> 3 </since_tizen>
281         /// <param name="account">account instance to be updated.</param>
282         /// <privilege>http://tizen.org/privilege/account.read</privilege>
283         /// <privilege>http://tizen.org/privilege/account.write </privilege>
284         /// <exception cref="InvalidOperationException">In case of any DB error </exception>
285         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
286         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
287         /// <exception cref="OutOfMemoryException"> In case of OutOfMemory error.</exception>
288         public static void UpdateAccount(Account account)
289         {
290             if (account == null)
291             {
292                 throw AccountErrorFactory.CreateException(AccountError.InvalidParameter, "Failed to UpdateAccount");
293             }
294
295             AccountError err = (AccountError)Interop.AccountService.UpdateAccountToDBById(account.Handle, account.AccountId);
296             if (err != AccountError.None)
297             {
298                 throw AccountErrorFactory.CreateException(err, "Failed to UpdateAccount");
299             }
300         }
301
302         /// <summary>
303         /// Deletes the account information from the Database.
304         /// </summary>
305         /// <since_tizen> 3 </since_tizen>
306         /// <param name="account">Account instance to be deleted from the database.</param>
307         /// <privilege>http://tizen.org/privilege/account.read</privilege>
308         /// <privilege>http://tizen.org/privilege/account.write </privilege>
309         /// <exception cref="InvalidOperationException">In case of any DB error </exception>
310         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
311         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
312         public static void DeleteAccount(Account account)
313         {
314             if (account == null)
315             {
316                 throw AccountErrorFactory.CreateException(AccountError.InvalidParameter, "Failed to DeleteAccount");
317             }
318
319             AccountError err = (AccountError)Interop.AccountService.DeleteAccountById(account.AccountId);
320             if (err != AccountError.None)
321             {
322                 throw AccountErrorFactory.CreateException(err, "Failed to delete the account by Id: " + account.AccountId);
323             }
324         }
325
326         /// <summary>
327         /// Deletes an account from the account database by user name.
328         /// </summary>
329         /// <since_tizen> 3 </since_tizen>
330         /// <param name="userName">The user name of the account to delete.</param>
331         /// <param name="packageName">The package name of the account to delete.</param>
332         /// <privilege>http://tizen.org/privilege/account.read</privilege>
333         /// <privilege>http://tizen.org/privilege/account.write </privilege>
334         /// <exception cref="InvalidOperationException">In case of any DB error</exception>
335         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
336         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
337         public static void DeleteAccount(string userName, string packageName)
338         {
339             AccountError err = (AccountError)Interop.AccountService.DeleteAccountByUser(userName, packageName);
340             if (err != AccountError.None)
341             {
342                 throw AccountErrorFactory.CreateException(err, "Failed to delete the account by userName: " + userName);
343             }
344         }
345
346         /// <summary>
347         /// Deletes an account from the account database by package name.
348         /// </summary>
349         /// <since_tizen> 3 </since_tizen>
350         /// <param name="packageName">The package name of the account to delete.</param>
351         /// <privilege>http://tizen.org/privilege/account.read</privilege>
352         /// <privilege>http://tizen.org/privilege/account.write </privilege>
353         /// <exception cref="InvalidOperationException">In case of any DB error</exception>
354         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
355         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
356         public static void DeleteAccount(string packageName)
357         {
358             AccountError err = (AccountError)Interop.AccountService.DeleteAccountByPackage(packageName);
359             if (err != AccountError.None)
360             {
361                 throw AccountErrorFactory.CreateException(err, "Failed to delete the account by package name: " + packageName);
362             }
363
364         }
365
366         /// <summary>
367         /// Retrieves all accounts with the given user name.
368         /// </summary>
369         /// <since_tizen> 3 </since_tizen>
370         /// <param name="userName">The user name to search .</param>
371         /// <returns>Accounts list matched with the user name</returns>
372         /// <privilege>http://tizen.org/privilege/account.read</privilege>
373         /// <exception cref="InvalidOperationException">In case of any DB error or record not found for given username</exception>
374         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
375         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
376         public static IEnumerable<Account> GetAccountsByUserName(string userName)
377         {
378             List<Account> accounts = new List<Account>();
379             List<int> values = new List<int>();
380             Interop.Account.AccountCallback accountCallback = (IntPtr handle, IntPtr data) =>
381             {
382                 Account account = new Account(handle);
383                 values.Add(account.AccountId);
384                 account.Dispose();
385                 return true;
386             };
387
388             AccountError err = (AccountError)Interop.AccountService.QueryAccountByUserName(accountCallback, userName, IntPtr.Zero);
389             if (err != AccountError.None)
390             {
391                 throw AccountErrorFactory.CreateException(err, "Failed to GetAccountByUserName");
392             }
393
394             foreach (int i in values)
395             {
396                 Account account = AccountService.GetAccountById(i);
397                 accounts.Add(account);
398             }
399
400             return accounts;
401         }
402
403         /// <summary>
404         /// Retrieves all accounts with the given package name.
405         /// </summary>
406         /// <since_tizen> 3 </since_tizen>
407         /// <param name="packageName"> The package name to Search</param>
408         /// <returns>Accounts list matched with the package name</returns>
409         /// <privilege>http://tizen.org/privilege/account.read</privilege>
410         /// <exception cref="InvalidOperationException">In case of any DB error or record not found for given package name</exception>
411         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
412         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
413         public static IEnumerable<Account> GetAccountsByPackageName(string packageName)
414         {
415             List<Account> accounts = new List<Account>();
416             List<int> values = new List<int>();
417             Interop.Account.AccountCallback accountCallback = (IntPtr handle, IntPtr data) =>
418             {
419                 Account account = new Account(handle);
420                 values.Add(account.AccountId);
421                 account.Dispose();
422                 return true;
423             };
424
425             AccountError err = (AccountError)Interop.AccountService.QueryAccountByPackageName(accountCallback, packageName, IntPtr.Zero);
426             if (err != AccountError.None)
427             {
428                 throw AccountErrorFactory.CreateException(err, "Failed to GetAccountByPackageName");
429             }
430
431             foreach (int i in values)
432             {
433                 Account account = AccountService.GetAccountById(i);
434                 accounts.Add(account);
435             }
436
437             return accounts;
438         }
439
440         /// <summary>
441         /// Retrieves all accounts with the given cpability type.
442         /// </summary>
443         /// <since_tizen> 3 </since_tizen>
444         /// <param name="type"> Capability type</param>
445         /// <returns>Accounts list matched with the capability type</returns>
446         /// <privilege>http://tizen.org/privilege/account.read</privilege>
447         /// <exception cref="InvalidOperationException">In case of any DB error or record not found for given capability type</exception>
448         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
449         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
450         public static IEnumerable<Account> GetAccountsByCapabilityType(string type)
451         {
452             List<Account> accounts = new List<Account>();
453             List<int> values = new List<int>();
454             Interop.Account.AccountCallback accountCallback = (IntPtr handle, IntPtr data) =>
455             {
456                 Account account = new Account(handle);
457                 values.Add(account.AccountId);
458                 account.Dispose();
459                 return true;
460             };
461
462             AccountError err = (AccountError)Interop.AccountService.GetAccountByCapabilityType(accountCallback, type, IntPtr.Zero);
463             if (err != AccountError.None)
464             {
465                 throw AccountErrorFactory.CreateException(err, "Failed to GetAccountByCapabilityType");
466             }
467
468             foreach (int i in values)
469             {
470                 Account account = AccountService.GetAccountById(i);
471                 accounts.Add(account);
472             }
473
474             return accounts;
475         }
476
477         /// <summary>
478         /// Retrieves all capabilities with the given account
479         /// </summary>
480         /// <since_tizen> 3 </since_tizen>
481         /// <param name="accountId">account instance</param>
482         /// <returns>Capabilities list as Dictionary of Capability type and State.</returns>
483         /// <privilege>http://tizen.org/privilege/account.read</privilege>
484         /// <exception cref="InvalidOperationException">In case of any DB error or record not found for given account id</exception>
485         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
486         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
487         public static Dictionary<string, CapabilityState> GetCapabilitiesById(int accountId)
488         {
489             Dictionary<string, CapabilityState> capabilities = new Dictionary<string, CapabilityState>();
490             Interop.Account.AccountCapabilityCallback capabilityCallback = (string type, int capabilityState, IntPtr data) =>
491             {
492                 capabilities.Add(type, (CapabilityState)capabilityState);
493                 return true;
494             };
495
496             AccountError err = (AccountError)Interop.AccountService.QueryAccountCapabilityById(capabilityCallback, accountId, IntPtr.Zero);
497             if (err != AccountError.None)
498             {
499                 throw AccountErrorFactory.CreateException(err, "Failed to GetAllCapabilitiesById");
500             }
501
502             return capabilities;
503         }
504
505         /// <summary>
506         /// Gets the count of accounts in the account database.
507         /// </summary>
508         /// <since_tizen> 3 </since_tizen>
509         /// <returns>The number of accounts in the database</returns>
510         /// <privilege>http://tizen.org/privilege/account.read</privilege>
511         /// <exception cref="InvalidOperationException">In case of any DB error </exception>
512         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
513         public static int GetAccountsCount()
514         {
515             int count = 0;
516             AccountError err = (AccountError)Interop.AccountService.GetAccountCount(out count);
517             if (err != AccountError.None)
518             {
519                 throw AccountErrorFactory.CreateException(err, "Failed to GetAccountCount");
520             }
521
522             return count;
523         }
524
525         /// <summary>
526         /// Updates the sync status of the given account.
527         /// </summary>
528         /// <since_tizen> 3 </since_tizen>
529         /// <param name="account"> Account for which sync status needs to be updated</param>
530         /// <param name="status">Sync State</param>
531         /// <privilege>http://tizen.org/privilege/account.read</privilege>
532         /// <privilege>http://tizen.org/privilege/account.write</privilege>
533         /// <exception cref="InvalidOperationException">In case of any DB error </exception>
534         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
535         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
536         public static void UpdateSyncStatusById(Account account, AccountSyncState status)
537         {
538             AccountError err = (AccountError)Interop.AccountService.UpdateAccountSyncStatusById(account.AccountId, (int)status);
539             if (err != AccountError.None)
540             {
541                 throw AccountErrorFactory.CreateException(err, "Failed to UpdateSyncStatusById");
542             }
543         }
544
545         private static readonly Interop.AccountService.SubscribeCallback s_accountUpdatedCallback = (string eventType, int accountId, IntPtr userData) =>
546         {
547             AccountSubscriberEventArgs eventArgs = new AccountSubscriberEventArgs(eventType, accountId);
548             s_accountUpdated?.Invoke(null, eventArgs);
549             return true;
550         };
551
552         private static Interop.AccountService.SafeAccountSubscriberHandle s_subscriberHandle;
553
554         private static event EventHandler<AccountSubscriberEventArgs> s_accountUpdated;
555         /// <summary>
556         /// ContentUpdated event is triggered when the media item info from DB changes.
557         /// </summary>
558         /// <since_tizen> 3 </since_tizen>
559         /// <remarks>
560         /// ContentUpdate event is triggered if the MediaInformaion updated/deleted or new Inforamtion is Inserted.
561         /// </remarks>
562         /// <param name="sender"></param>
563         /// <param name="e">A ContentUpdatedEventArgs object that contains information about the update operation.</param>
564         /// <privilege>http://tizen.org/privilege/account.read</privilege>
565         /// <exception cref="InvalidOperationException">In case of any DB error </exception>
566         /// <exception cref="ArgumentException"> In case of invalid parameter</exception>
567         /// <exception cref="UnauthorizedAccessException"> In case of privilege not defined.</exception>
568         public static event EventHandler<AccountSubscriberEventArgs> AccountUpdated
569         {
570             add
571             {
572                 if (s_accountUpdated == null)
573                 {
574                     if (s_subscriberHandle == null)
575                     {
576                         Interop.AccountService.CreateAccountSubscriber(out s_subscriberHandle);
577                     }
578
579                     AccountError ret = (AccountError)Interop.AccountService.RegisterSubscriber(s_subscriberHandle, s_accountUpdatedCallback, IntPtr.Zero);
580
581                     if (ret != AccountError.None)
582                     {
583                         throw AccountErrorFactory.CreateException(ret, "Error in callback handling");
584                     }
585                 }
586
587                 s_accountUpdated += value;
588             }
589
590             remove
591             {
592                 s_accountUpdated -= value;
593                 if (s_accountUpdated == null)
594                 {
595                     AccountError ret = (AccountError)Interop.AccountService.UnregisterSubscriber(s_subscriberHandle);
596                     if (ret != AccountError.None)
597                     {
598                         throw AccountErrorFactory.CreateException(ret, "Error in callback handling");
599                     }
600                     s_subscriberHandle = null;
601                 }
602             }
603         }
604
605     }
606 }