I want to get all contacts stored in phone and update them as per requirement.
http://www.silverlightshow.net/items/Windows-Phone-8-Contacts-Integration.aspx
This link shows to get contacts but I'm not getting all contacts. I'm only getting contacts that have been created using my app.
Is there any way I can get all contacts and change mobile numbers.
Thanks
From the link you provided (emphasis added):
With Windows Phone 8, Microsoft introduces a new concept of "custom
contact stores" [2]. In addition to the read-only access to the user's
contact list and the above demonstrated way to use a separate task for
creating new entries (both of which available in 7.x) we now are able
to write our own data to the people hub silently and without user
consent. However apps still cannot manipulate existing contacts that
originate from somewhere else. In this sense, the data that belongs to
an app is somewhat isolated from the rest.
This is by design, you can't edit contacts you didn't create.
try something like this
void GetContact()
{
cons = new Contacts();
//Identify the method that runs after the asynchronous search completes.
cons.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(ContactsSearchCompleted);
//Start the asynchronous search.
cons.SearchAsync(String.Empty, FilterKind.None, "Contacts Test #1");
}
private void ContactsSearchCompleted(object sender, ContactsSearchEventArgs e)
{
cons.SearchCompleted -= ContactsSearchCompleted;
//e.Results should be the list of contact, since there's no filter applyed in the search you shoul have all contact here
}
not this is a copy paste of an old not tested code of mine so you might have to change something
You cant' - stupid crappy MS don't even support contact import from vcard file. ALL MS want that you put every your data to their servers so they own it.
At first you should at Contact Capability
for wp8 add from WMAppManifest.xml
for wp8.1 add from Package.appxmanifest
Now define a class PhoneContact to store the data
public class PhoneContact {
public string Name { get; set; }
public string Number { get; set; }
public string Email { get; set; }
}
Create a ObservableCollection and Call the following action from constructor to read the contact list. N.B use the following namespace also
using Microsoft.Phone.UserData;
using System.Collections.ObjectModel;
ObservableCollection<PhoneContact> phoneContact;
public MainPage() {
InitializeComponent();
phoneContact = new ObservableCollection<PhoneContact>();
ReadPhoneContact();
}
void ReadPhoneContact(){
Contacts cnt = new Contacts();
cnt.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(Contacts_SearchCompleted);
cnt.SearchAsync(String.Empty, FilterKind.None, "Contacts Test #1");
}
After reading all contact fire the following event. you can read multiple contact number, email etc.
void Contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
foreach (var item in e.Results) {
var contact = new PhoneContact();
contact.Name = item.DisplayName;
foreach (var pn in item.PhoneNumbers)
contact.Number = string.IsNullOrEmpty(contact.Number) ? pn.PhoneNumber : (contact.Number + " , " + pn.PhoneNumber);
foreach (var ea in item.EmailAddresses)
contact.Email = string.IsNullOrEmpty(contact.Email) ? ea.EmailAddress : (contact.Email + " , " + ea.EmailAddress);
phoneContact.Add(contact);
}
}
Related
I have posted question regarding firebase two days ago:
Android Firebase - add authenticated user into database
I got help that I needed and that solved first problem. But now I have a new problem. I was googling for quite some time, there are some posts about this issue but nothing solved my problem. I din't want to spam the previous question so I posted a new one.
When I try reading inserted data from the firebase database I get this error:
Newtonsoft.Json.JsonSerializationException: Error converting value
"test#user.com" to type 'carServiceApp.My_Classes.Account'. Path
'email', line 1, position 24.
Here is the code:
private async Task LoadData()
{
FirebaseUser users = FirebaseAuth.GetInstance(loginActivity.app).CurrentUser;
id = users.Uid;
var firebase = new FirebaseClient(loginActivity.FirebaseURL);
var items = await firebase.Child("users").Child(id).OnceAsync<Account>();
foreach (var item in items)
{
Account user = new Account();
user.uid = item.Object.uid;
user.name = item.Object.name;
user.lastName = item.Object.lastName;
user.phone = item.Object.phone;
user.email = item.Object.email;
userInput_ime.Text = user.name;
userInput_prezime.Text = user.lastName;
userInput_broj.Text = user.phone;
userInput_email.Text = user.email;
}
}
This is firebase data:
-users
-jwAP2dYNzJeiF3QlmEIEQoruUkO2
email: "test#user.com"
lastName: "user"
name: "test"
phone: "12421"
uid: "jwAP2dYNzJeiF3QlmEIEQoruUkO2"
Interesting thing is that when I try reading data with this:
var items = await firebase.Child("users").OnceAsync<Account>();
This works fine (I get last inserted user) . But when I add 'uid' node, then I get error. I was trying to solve this for quite some time but I just can't figure it out. I guess that there is no problem with the account class because it works in the case without uid node but doesn't work when another child() method is added.
Other information (Account class code and the way of storing that data into the database) you can see in the link at the top.
Note: I tried adding constructor in Account class but that doesn't help.
Ok, so I didn't exactly find a solution for this problem nor do I really understand why was this happening but I have found a workaround. I believe it's not ideal solution and that it does not fix existing problem. Or maybe it was problem with me not understanding firebase logic but here is what I came up with.
So, considering that it was all working fine if I didn't specify that uid node it was obvious there was some problem with class and data in firebase, matching problem I guess. Anyway, I decided to have that last uid node so I can have specific user selected and also to have the same data in firebase as it was in case where it was all working. So, this is how I have inserted data into firebase:
var item = firebase.Child("users").Child(id).PostAsync<Account>(user);
This created users node and child node. And PostAsync method created one more node with random key.
So when I tried reading with this:
var data = await firebase.Child("users").Child(id).OnceAsync<Account>();
It worked without problem. Now firebase data looks like this:
users
JPKdQbwcXbhBatZ2ihBNLRauhV83
-LCXyLpvdfQ448KOPKUp
email: "spider#man.com"
lastName: "man"
name: "spider"
phone: "14412"
uid: "JPKdQbwcXbhBatZ2ihBNLRauhV83"
There is a bit of redundancy, I basically have two ID's, but I don't understand how to create my class so I can get that data any other way so I made it this way. It works fine.
If anyone has better solution, I will gladly change it. Cheers
This was suppose to be a comment, but this is just suppose to be an addition for anyone that needs help with this issue.
I know that this answer has been out there for a while but this still seems to be a running structural quirk with Firebase and the usage of their rules. I ran into this issue with a complex structure that looked kind of like this
-Orders
-9876trfghji (User ID)
-0
BusnID: "ty890oihg"
Name: "Some Name"
AddOns: Object
ItemData: Object(containing other objects)
UserID: "9876trfghji"
Note: In this case as well as the case with cordas, you will see that both of the final objects has a UserID or uid.
I also was running into the issue of class de-serialization of the object without having the actual User ID in the objects data when it was being sent back to the device.
The reason that you have a “redundant” usage of the user id is for a security measure with the Firebase rules. The first UserID with the structure above you are able to control the access to the information based off of the users id without having to have an extra validation clause in the rules. Currently as of this post the the rule below would protect the data based on the User ID.
“Orders” : {
"$uid":{
".read":"auth != null",
".write":"auth.uid == $uid"
}
}
this allows the user with only the authorized user id to write content but anyone that has valid credentials can view the data.
The second User ID has to be placed in the object because without it you would not be able to do a standard cast to the object because your object would not have all of the data it would need to create the object. Regardless of if you are using a package like GoogleGson or Newtonsoft.Json the object still isn't full.
There is how ever a work around for this problem besides re-entering the User ID into the object. With the object that I have above I decided to just re-enter the User ID in my personal code to save the time and hassle of manual creation.
Using the Firebase.Database NuGet package you can manually create the object. Here is an example of the object in cordas problem
public static void GetUser_Firebase(User user, FirebaseApp app)
{
FirebaseDatabase database = FirebaseDatabase.GetInstance(app);
DatabaseReference reference = database.GetReference($"/users/{user.UserID}");
//"Using for getting firebase information", $"/users/{user.UserID}"
reference.AddListenerForSingleValueEvent(new UserInfo_DataValue());
}
class UserInfo_DataValue : Java.Lang.Object, IValueEventListener
{
private string ID;
public UserInfo_DataValue(string uid)
{
this.ID = uid;
}
public void OnCancelled(DatabaseError error)
{
//"Failed To Get User Information For User "
}
public void OnDataChange(DataSnapshot snapshot)
{
Dictionary<string, string> Map = new Dictionary<string, string>();
var items = snapshot.Children?.ToEnumerable<DataSnapshot>(); // using Linq
foreach(DataSnapshot item in items)
{
try
{
Map.Add(item.Key, item.Value.ToString()); // item.value is a Java.Lang.Object
}
catch(Exception ex)
{
//"EXCEPTION WITH DICTIONARY MAP"
}
}
User toReturn = new User();
toReturn.UserID this.ID;
foreach (var item in Map)
{
switch (item.Key)
{
case "email":
toReturn.email = item.Value;
break;
case "lastName":
toReturn.lastName = item.Value;
break;
case "name":
toReturn.name = item.Value;
break;
case "phone":
toReturn.phone = item.Value;
break;
}
}
}
}
Update
There is something that I would like to mention that I left out when I was writing this and that is the usage of Firebase.Database NuGet package with the Gson NuGet package and the Newtonsoft.Json Library
If you decide to use the FIrebase.Database library just know that you will be working very close with the Java.Lang and the Java.Util libraries. Objects like Java.Lang.Object can be very difficult and time consuming to write the code needed to de-serialize the data, but don't fear Gson is here!
The Gson package if you allow it can take a large load of work off of your hands for class de-serialization if you allow it. Gson is a library that will allow you to do Java.Lang.Obj to json string de-serialization. I know it seems weird, hand it an object get back a string sounds counter intuitive I know but just bear with me.
Here is an example of how to us the Gson Library with the object in cordas problem.
public static void Get_User(User user, FirebaseApp app)
{
FirebaseDatabase database = FirebaseDatabase.GetInstance(app);
DatabaseReference reference = database.GetReference($"Users/{user.UserID}");
reference.AddListenerForSingleValueEvent(new User_DataValue(user, app));
//$"Trying to make call for user orders Users/{user.UserID}");
}
class User_DataValue : Java.Lang.Object, IValueEventListener
{
private User User;
private FirebaseApp app;
public UserOrderID_Init_DataValue(User user, FirebaseApp app)
{
this.User = user;
this.app = app;
}
public void OnCancelled(DatabaseError error)
{
//$"Failed To Get User Orders {error.Message}");
}
public void OnDataChange(DataSnapshot snapshot)
{
//"Data received for user orders");
var gson = new GsonBuilder().SetPrettyPrinting().Create();
var json = gson.ToJson(snapshot.Value); // Gson extention method obj -> string
Formatted_Output("Data received for user order json ", json);
User user = JsonConvert.DeserializeObject<User>(json); //Newtonsoft.Json extention method string -> object
//now the user is a fully populated object with very little work
}
For anyone that might run into this in the future I hope that this helps
currently I´m writing on a outlook plugin for syncing goolge contacts with outlook but I have to cover some special case:
When a contact gets deleted on google side, my application detects the missing contact and creates a new contact based on the contact info from the outlook one.
Is there a way to get an event or history from google that tells me a user deleted this contact(s)?
Edit 1:
Here is my code how I´m accessing the contacts (what is working FINE):
public GoogleAccessor()
{
var parameters = new OAuth2Parameters()
{
ClientId = CLIENTID,
ClientSecret = CLIENTSECRET,
RedirectUri = REDIRECTURI,
Scope = SCOPES
};
string url = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
//An own webbrowser for processing the access tokens
IAuthorizationCodeProvider authcodeProvider = new Presentation.BrowserAuthorizationCodeProvider(new Presentation.BrowserAuthentificatorVM());
parameters.AccessCode = authcodeProvider.GetAuthorizationCode(url);
if(parameters.AccessCode == null)
throw new GoogleOAuthException("AccesCode returned 'null' and failed!");
OAuthUtil.GetAccessToken(parameters);
this._contactsRequest = new ContactsRequest(new RequestSettings(APPLICATIONNAME, parameters) {AutoPaging = true});
}
public IList<IContact> GetAllMappedContacts()
{
Feed<Google.Contacts.Contact> f = _contactsRequest.GetContacts();
this._feedUri = new Uri(f.AtomFeed.Feed);
var photoList = new List<PhotoObject>();
foreach (var entry in f.Entries)
{
var photoObject = GetContactPhoto(entry);
if(photoObject != null)
photoList.Add(photoObject);
}
_googleMapper = new GoogleMapper(f.Entries);
return _googleMapper.MapToLocalContacts();;
}
The thing about syncing in general is that syncing is normally meant to work in one direction.
Source Data -> Data Flow -> Received Data.
In this instance, Outlook is your source data and Google is your received data. All information needs to come from your source. Since this is an Outlook add-in you are creating my suggestion would be to add a button to your add-in ribbon. You can call the button whatever ever you like (maybe "dontSyncButton"), but it's purpose is going to be Categorization of your contact.
Make it so that that when a contact is selected and then the button is clicked, the contact is given a special categorization (perhaps "Dont Sync").
Now give some logic to your code that executes the sync, and have that logic decide whether to sync the contact. Also, give some logic to tell the program to delete the contact out of Google for you if the contacts contains the special category. Semi-Pseudo Code below:
if(contact.Categories.ToString() == "Dont Sync")
{
//Don't Sync Contact
If(googleContact.Exists())
{
//Delete contact from Google if it exist
googleContact.Delete();
}
}
else
{
//Sync Contact
}
It would be nice if Outlook had many modifiable properties that weren't visible to users, but since it does not this is really one of the best options I can think of. I do this to sync contacts from a shared Outlook folder to personal ones and it has worked well so far.
Hope this helps!
I'm using the Tridion.OutboundEmail.ContentManagement API to retrieve and manage contact details.
Retrieving Contacts is working fine, as is pulling back the ExtendedDetails dictionary, but the Keywords TcmUriCollection is always empty.
[Test]
public void GetContacts_via_address_book()
{
var uri = new TcmUri(101, 2, TcmItemTypes.StaticAddressBook);
var addressBook = new StaticAddressBook(uri);
var contacts = addressBook.GetContacts();
foreach (var contact in contacts)
{
var firstName = contact.ExtendedDetails["NAME"].StringValue;
Assert.That(contact.EmailAddress, Is.Not.Empty); // PASS
Assert.That(firstName, Is.Not.Empty); // PASS
Assert.That(contact.Keywords.Count, Is.GreaterThan(0)); // FAIL
}
}
I've also tried the following method:
[Test]
public void GetContacts_via_filter()
{
var uri = new TcmUri(101, 2, TcmItemTypes.StaticAddressBook);
var addressBook = new StaticAddressBook(uri);
var filter = new ContactFilter(UserContext.Current);
var contacts = Contact.GetContacts(filter, addressBook);
foreach (var contact in contacts)
{
var firstName = contact.ExtendedDetails["NAME"].StringValue;
Assert.That(contact.EmailAddress, Is.Not.Empty); // PASS
Assert.That(firstName, Is.Not.Empty); // PASS
Assert.That(contact.Keywords.Count, Is.GreaterThan(0)); // FAIL
}
}
I can even add a keyword to a Contact's Keywords collection and save it, and it appears correctly in Tridion, but when I retrieve the same contact again, the collection is once again empty.
Does anyone have any experience with this API, and/or know what the problem is?
This is because Keywords are not loaded when you get a list of Contacts. Only a subset of the data is available, for performance reasons.
To solve this, you will need to re-load each Contact. Since Contacts are streamed from the database, you cannot do this inside of your loop. So you'll want to build the list of Contacts first and then loop over them and load them in full.
For more info and examples, please see my blog post on the subject:
http://pkjaer.wordpress.com/2011/12/01/looping-through-contacts/
Right now I'm using the the LyncClient.ContactManager.BeginSearch method to find contacts. However, I haven't been able to figure out how to get all the contacts. I've tried passing "*" and "%" as wild-card characters but that has not worked. Right now here is my function call.
_lyncClient.ContactManager.BeginSearch("*", SearchProviders.GlobalAddressList, SearchFields.DisplayName, SearchOptions.ContactsOnly, 400, SearchCallback, "Searching Contacts");
Lync contacts are organised into groups, so you need to start at the Groups level. Once you've got a group, you can then enumerate through it's Contacts
foreach(var group in _client.ContactManager.Groups)
{
foreach (var contact in group)
{
MessageBox.Show(contact.Uri);
}
}
This article is good for background, and more advanced features
Edit: Specifically, for the distribution groups expansion question, I think the sample here is flawed.
Instead of calling BeginExpand and waiting on the WaitHandle, provide a callback method to handle the Expand callback. So, instead of:
asyncOpResult = DGGroup.BeginExpand(null, null);
asyncOpResult.AsyncWaitHandle.WaitOne();
DGGroup.EndExpand(asyncOpResult);
try this:
...
asyncOpResult = DGGroup.BeginExpand(ExpandCallback, DGGroup);
...
public void ExpandCallback(IAsyncResult ar)
{
DistributionGroup DGGroup = (DistributionGroup)ar.AsyncState;
DGGroup.EndExpand(ar);
etc...
}
This works perfectly for me.
I ended up doing multiple searches for now to get all the contacts. I go through each letter of the alphabet to find them. The load time is quick enough and I'll just show a loading image on the grid for a little while when it fires up. This worked well for the 200 or so contacts we have though I would recommend Paul's solution for 150 or less. Here is what I did:
private static char[] Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
...
public void GetAllContacts()
{
int initialLetterIndex = 0;
_lyncClient.ContactManager.BeginSearch(
Alphabet[initialLetterIndex].ToString();
SearchProviders.GlobalAddressList,
SearchFields.FirstName,
SearchOptions.ContactsOnly,
300,
SearchAllCallback
new object[] { initialLetterIndex, new List<Contact>() }
);
}
private void SearchAllCallback(IAsyncResult result)
{
object[] parameters = (object[])result.AsyncState;
int letterIndex = (int)parameters[0] + 1;
List<Contact> contacts = (List<Contact>)parameters[1];
SearchResults results = _lyncClient.ContactManager.EndSearch(result);
contacts.AddRange(results.Contacts);
if (letterIndex < Alphabet.Length)
{
_lyncClient.ContactManager.BeginSearch(
Alphabet[letterIndex].ToString(),
SearchAllCallback,
new object[] { letterIndex, contacts }
);
}
else
{
//Now that we have all the contacts
//trigger an event with 'contacts' as the event arguments.
}
}
We have a large public contacts folder in Outlook called Global Contacts, I'd like to be able to search through it and return a number of results that match certain criteria, ideally wildcard-style.
E.g. if someone puts "je" in the 'name' textbox, it will return all contacts whose names contain 'je'. This may be coupled as an AND with a companyname textbox.
Most of the examples I've seen are either in VB, or are concerned with doing this form a web app - I'm doing a winforms app, and every machine has Outlook 2002 installed (yeah, I know, update long overdue).
Can anyone point me in the right direction? Some code would be nice as a place to start.
Cheers
I ended up doing this:
Microsoft.Office.Interop.Outlook._Application objOutlook; //declare Outlook application
objOutlook = new Microsoft.Office.Interop.Outlook.Application(); //create it
Microsoft.Office.Interop.Outlook._NameSpace objNS = objOutlook.Session; //create new session
Microsoft.Office.Interop.Outlook.MAPIFolder oAllPublicFolders; //what it says on the tin
Microsoft.Office.Interop.Outlook.MAPIFolder oPublicFolders; // as above
Microsoft.Office.Interop.Outlook.MAPIFolder objContacts; //as above
Microsoft.Office.Interop.Outlook.Items itmsFiltered; //the filtered items list
oPublicFolders = objNS.Folders["Public Folders"];
oAllPublicFolders = oPublicFolders.Folders["All Public Folders"];
objContacts = oAllPublicFolders.Folders["Global Contacts"];
itmsFiltered = objContacts.Items.Restrict(strFilter);//restrict the search to our filter terms
Then just looping through itmsFiltered to add it to an ObjectListView. Hopefully this will be of use to someone else looking to do the same - it took me a while to cobble this together from various sources.
to find contacts folder you can iterate items of olFolderContacts. Here is the code
using System;
using Microsoft.Office.Interop.Outlook;
using Application = Microsoft.Office.Interop.Outlook.Application;
namespace RyanCore
{
public class Loader
{
public static ContactsViewModel LoadModel(Application objOutlook)
{
var viewModel = new ContactsViewModel();
MAPIFolder fldContacts = objOutlook.Session.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
foreach (object obj in fldContacts.Items)
{
if (obj is _ContactItem)
{
var contact = (_ContactItem) obj;
viewModel.Contacts.Add(new Contact(contact.FirstName + " " + contact.LastName, contact.Email1Address));
}
else if (obj is DistListItem)
{
var distListItem = (DistListItem) obj;
var contactGroup = new ContactGroup(distListItem.Subject);
viewModel.Groups.Add(contactGroup);
for (Int32 i = 1; i <= distListItem.MemberCount; i++)
{
Recipient subMember = distListItem.GetMember(i);
contactGroup.Contacts.Add(new Contact(subMember.Name, subMember.AddressEntry.Address));
}
}
}
return viewModel;
}
}
}