piątek, 4 stycznia 2013

Z dokumentacji WP8 (1)

Dokumentacja dla najnowszego Windows Phone 8 SDK znajduje się na stronie Windows Phone development. Pomijając dobrze znane już nowe elementy nagłaśniane przy różnych eventach tj. BUILD czy Jump Start, wynotowałem sobie bardziej wysublimowane informacje. Na przykład dużą ciekawostką jest sam VOIP. Nie widziałem z tego jeszcze żadnej prezentacji. Temat okazuje się dość złożony - tworzy się aplikację foreground, komponent WinRT z logiką, 4 agentów…  API do strumieniowania audio jest częścią Win32 API … Co ciekawe strumieniowanie video w C# z kolei jest trywialne. Całość to lawirowanie między elementami w kodzie zarządzanym, WinRT API i kodem stricte natywnym.

Garbage collection

  • The garbage collection heap in Windows Phone 8 has three generations, not two generations as it does in Windows Phone OS 7.1.

  • In Windows Phone 8, the garbage collector has a large object heap (LOH).

  • Background garbage collection is not available in Windows Phone 8.

  • The phone's resource manager invokes a garbage collection when an app approaches the memory cap and will terminate the app if it exceeds the memory cap.

  • The runtime's auto-tuned garbage collection triggers can be impacted by an app's forced garbage collections.

  • In Windows Phone 8, the performance of per-thread allocation by the garbage collector is improved.

Dane

Use “ms-appx:///” when addressing the installation folder with APIs that are in the Windows namespace. For all other APIs, use “appdata:/”.

Use “ms-appdata:///local/” to address the root of the local folder with APIs that are in the Windows namespace. For all other APIs, use “isostore:/” to address the root of the local folder.

Folder PlatformData – PhotoChooserTask

Aplikacje VoIP

When an incoming call arrives for a VoIP app, the built-in phone experience is shown, and the VoIP app appears integrated into the phone.

A Windows Phone VoIP app is comprised of several components that run in one of two processes, and one component that runs outside of any process. The first process is the foreground process that displays the app UI. The second process is a background process that does most of the work of creating, connecting, and managing incoming and outgoing calls.

IC619146

In addition to providing the UI, the foreground app sets up the push notification channel on which incoming calls arrive. It also launches the background process and uses the out-of-process server to pass commands to the components in the background, such as requesting that a call be ended.

The four background agents that a VoIP app uses. These agents are written using managed code and are launched to indicate that a new phase of a VoIP call has begun. In general, these agents have very little code, and just pass the state of the call in to one of the following components that do most of the work.

  • VoipHttpIncomingCallTask. Launched when a new incoming call arrives on the push notification channel. It lets the Windows Phone Runtime assembly know that it should create a new call.

  • VoipForegroundLifetimeAgent. Launched by the foreground app and runs as long as the app is in the foreground. It bootstraps the background process and keeps its process alive so that outgoing calls can be created quickly.

  • VoipCallInProgressAgent. Launched when a call becomes active. It signals the app that it has been allocated more CPU cycles so it can encode and decode audio and video.

  • VoipKeepAliveTask. Runs periodically, every 6 hours by default, whether or not the foreground app is running. This gives the app an opportunity to ping the VoIP service to indicate that the app is still installed on the device. When the user uninstalls the app, this agent no longer runs and the service knows not to send incoming call on the app’s push notification channel.

Windows Phone Runtime assembly - an assembly that does most of the work of connecting and managing VoIP calls using the VoipCallCoordinator and VoipPhoneCall objects. Because this is a Windows Phone Runtime assembly instead of managed, it can call the native APIs to use for audio and video processing.

Native core assembly - many VoIP app developers support multiple platforms, and often have a core library written in C or C++.

Odbieranie rozmowy

  1. The first time the user launches your VoIP app, you create a push notification channel.
  2. To initiate a new incoming call, the VoIP cloud service sends a push notification to the URI for your app’s push notification channel.
  3. The operating system launches your app’s VoipHttpIncomingCallTask agent.
    • The incoming call agent loads the app’s Windows Phone Runtime assembly, if it’s not already loaded.
    • The incoming call agent gets the push notification payload from its MessageBody property, and then passes it in to the Windows Phone Runtime assembly, calling a custom method named something like OnIncomingCallReceived.

    • In OnIncomingCallReceived, your Windows Phone Runtime assembly VoipCallCoordinator.RequestNewIncomingCall, passing in information from the push notification payload such as the calling party’s name and the URI of a contact picture for the caller. This information allows the phone to display the built-in phone UI to the user.

    • The VoipCallCoordinator.RequestNewIncomingCall method returns a VoipPhoneCall object that represents the requested call. Your Windows Phone Runtime assembly should store this object so that it can be used from other methods, and then register handlers for the call object’s AnswerRequested and RejectRequested events.

    • In the AnswerRequested event handler, you can contact your cloud service to let it know that a new call has begun, for example, to indicate that billing for the call should begin. Then, you should call NotifyCallActive to let the system know that the call is now active.

    • If the RejectRequested event handler is called, you know that the call has been rejected and you have 10 seconds to clean up any resources before the operating system will terminate your process, assuming one of the other VoIP background agents isn’t still running.

  4. After you have called NotifyCallActive, the operating system will launch your VoipCallInProgressAgent. When this agent runs, you know that your background process has been allocated more CPU for audio encoding and decoding.

    • Load your Windows Phone Runtime assembly, if it’s not already loaded.

    • In the Windows Phone Runtime assembly, if you haven’t already done so, register handlers for the MuteRequested, UnmuteRequested, and AudioEndpointChanged events.

    • Register event handlers for the EndRequested, HoldRequested, ResumeRequested events of the VoipPhoneCall object you stored while the incoming call agent was running. If you want to, you can register for all of the VoipPhoneCall events when the object is first created.

    • Hook up your incoming video stream to the MediaElement in your foreground app. For a detailed walkthrough of setting up your video stream, see How to implement video streaming for VoIP calls for Windows Phone 8.

    • As your Windows Phone Runtime assembly receives events for changes in the call state, such as HoldRequested or ResumeRequested, take the appropriate action, such as suspending or resuming the streaming of video.

    • When the user presses a button in your UI to end the call, your foreground app calls a method in your Windows Phone Runtime assembly to end the call, which will set the call object to null and then call NotifyCallEnded. You should also do this in EndRequested which is raised when the operating system ends the call, such as when the user answers a VoIP call from a different VoIP app or if the user answers a second cellular call while already on a cellular call and a VoIP call.

Nawiązywanie rozmowy

  1. When your foreground app is launched:
    • Call Launch() to launch your background process. This causes the operating system to spawn the background process for your app and call the OnLaunched() method of the VoipForegroundLifetimeAgent agent. The foreground lifetime agent will be kept alive as long as your app runs in the foreground.

    • From the VoipForegroundLifetimeAgent, load your Windows Phone Runtime assembly if it is not already loaded.

    • Use custom events to let the foreground app know that the background process is ready, and that all assemblies have been loaded. Then, create a reference to your Windows Phone Runtime assembly in the foreground app.

  2. After the user selects a contact to call and then presses the Call button in your app:
    • Call a custom method on your Windows Phone Runtime assembly, named something like MakeOutgoingCall.

    • In MakeOutgoingCall, call the RequestNewOutgoingCall method and then pass the name of the person being called so that it can be displayed in the minimized phone UI.

  3. The RequestNewOutgoingCall method returns a VoipPhoneCall object that represents the requested call. Your Windows Phone Runtime assembly should store this object so that it can be used from other methods, and then it registers handlers for the call object’s AnswerRequested and RejectRequested events.

  4. You should call NotifyCallActive to let the system know that the call is now active.

  5. The operating system will launch VoipCallInProgressAgent. When this agent runs, you know that your background process has been allocated more CPU for audio encoding and decoding. While the VoipCallInProgressAgent is running:

    • Load your Windows Phone Runtime assembly, if it’s not already loaded.

    • In the Windows Phone Runtime assembly, if you haven’t already done so, register handlers for the MuteRequested, UnmuteRequested, and AudioEndpointChanged events.

    • Register event handlers for the EndRequested, HoldRequested, ResumeRequested events of the VoipPhoneCall object that you stored while the incoming call agent was running. If you want to, you can register for all of the VoipPhoneCall events when the object is first created.

    • Hook up your incoming video stream to the MediaElement in your foreground app. For a detailed walkthrough of setting up your video stream, see How to implement video streaming for VoIP calls for Windows Phone 8.

    • When the user presses a button in your UI to end the call, your foreground app calls a method in your Windows Phone Runtime assembly to end the call, which should set the call object to null and then call NotifyCallEnded. You should also do this in EndRequested which is raised when the operating system ends the call, such as when the user answers a VoIP call from a different VoIP app or if the user answers a second cellular call while already on a cellular call and a VoIP call.

ChatterBox VoIP Sample App

Audio streaming for VoIP calls for Windows Phone 8

Windows Phone 8 includes a subset of the Windows Audio Session API (WASAPI) to enable VoIP applications to capture and render audio streams. Your application will use the WASAPI interface IAudioRenderClient for rendering audio and IAudioCaptureClient for capturing audio. These interfaces can be used on the phone in much the same as you would use them in a Windows application. The biggest difference from Windows has to do with the way routing between different audio endpoints is managed.

  • The application is responsible for converting received audio data to PCM before rendering.

  • Captured audio is returned in PCM format. The application is responsible for encoding this to any other format if this is needed for network transmission.

  • The application is responsible for implementing any echo cancellation, noise reduction, or gain control in software.

  • There are no built-in Audio/Video sync mechanisms.

  • Applications have access to only a single microphone input stream. Dual microphones for use in noise suppression or other audio processing are not supported.

How to implement video streaming for VoIP calls for Windows Phone 8

The VoipForegroundLifetimeAgent is launched and its OnLaunched() method is called when your foreground application calls Launch(). In OnLaunched(), create a new instance of the MediaStreamer class specifying an string identifying the stream in the constructor. In the XAML for your foreground application, add a MediaElement in which the video will be displayed. Set the Source property using the following Uri scheme to hook it up to your MediaStreamer: “ms-media-stream-id:MediaStreamer-[streamer ID]”.

protected override void OnLaunched()
{
  MediaStreamer ms = MediaStreamerFactory.CreateMediaStreamer("123");
  string sourceRGBA = @"http://fabrikam.com/Frame_RGBA_320_240.bin";
  RAWMediaStreamSource mss = new RAWMediaStreamSource();
  mss.SetVideoStream(sourceRGBA, 320, 240, "RGBA", 30 * TimeSpan.TicksPerSecond, false);
  ms.SetSource(mss);
}

<MediaElement Source="ms-media-stream-id:MediaStreamer-123"/>

Proximity

When your proximity app is switched to the background, for example, when you answer a call, all published messages and subscriptions are suspended.

The underlying socket that is established for NFC is unprotected. The data channel is not encrypted by default. To encrypt the data being passed over this socket, and thereby reduce the risk of tampering, you can use the value of the SessionKey property on the StreamSocket as a symmetric key. This can be used in a cryptographic library, such as System.Security.Cryptography.AesManaged. This key is known only to the devices that are in proximity to each other.

Reconnect on Windows Phone 8 is supported only for Bluetooth and TCP/IP (Wi-Fi) connections. Your apps will reconnect without tapping the phones together again. If a Windows Phone 8 device attempts to reconnect with a Windows 8 device, it will fail because this reconnect operation is not supported on Windows 8.

Bluetooth

Windows Phone 8 supports Bluetooth 3.1. This is an improved version of Bluetooth that automates the pairing process between Windows Phone 8 and Bluetooth devices, such as phone headsets, car audio systems, speaker docks, and NFC pairing. The following Bluetooth user profiles are supported.

  • Advanced Audio Distribution Profile (A2DP 1.2)

  • Audio/Video Remote Control Profile (AVRCP 1.4

  • Hands Free Profile (HFP 1.5)

  • Phone Book Access Profile (PBAP 1.1)

  • Object Push Profile (OPP 1.1)

  • Out of Band (OOB) and Near Field Communications (NFC)

PeerFinder.AlternateIdentities["Bluetooth:Paired"] = "";

Enumerate all paired devices. The PeerInformation.ServiceName will be empty in this case. For many devices, the Bluetooth port over which to communicate is hard coded, so you can use that directly in the ConnectAsync call. If the device is advertising a service, then you can enumerate using the paired option but call ConnectAsync with the GUID of the service you want to use. 

PeerFinder.AlternateIdentities["Bluetooth:SDP"] = "<SDP service guid>";

Find devices using the Service discovery protocol (SDP) that are advertising a service with the given GUID. If any devices are found, the PeerInformation.ServiceName will be equal to the GUID you specified.

If you enumerate by "Bluetooth:Paired", the PeerInformation.ServiceName field will be empty.  It is only populated when you enumerate using "Bluetooth:SDP".

Bluetooth peer-to-peer (P2P) advertisement isn’t enabled if you start, stop, and then restart PeerFinder. Send your app to the background and then bring it to the foreground.

Data Sense API

Installing the Data Sense app and Tile on phones is optional for mobile operators. As a result, users of your app might not have the Data Sense app on their phones. Without the app, users can't enter their data limits.

When users’ data limits are unknown, you can still use the Data Sense API to determine whether they're using a Wi-Fi connection, or roaming. However you can't use the Data Sense API to determine whether they're approaching their data limit, or over their data limit.

You can’t use the Simulation Dashboard to test your Data Sense code by changing the network type from cellular to Wi-Fi or reverse. The Simulation Dashboard does not change the values of the properties that the Data Sense API uses.

When a Wi-Fi connection for which the phone has connection information becomes available, the phone automatically switches from a cellular connection to the Wi-Fi connection. You don’t need to write code to disconnect and reconnect when a Wi-Fi connection becomes available.

Launching, resuming & multitasking

You can use APIs from the Windows.Phone.Management.Deployment namespace to see if other apps from your publisher ID are installed on a phone. If they’re installed, you can also use this API to launch them.

IEnumerable<Package> apps = Windows.Phone.Management.Deployment.InstallationManager.FindPackagesForCurrentPublisher();
apps.First().Launch(string.Empty);

You can use the Launcher.LaunchUriAsync(Uri) method to launch built-in apps via URI. From the user’s standpoint, this works like Launchers for Windows Phone. But this method allows you to launch some built-in apps that you can’t launch with a Launcher. Unlike a Launcher, this feature can be used by native code.

As with a user-initiated launch, the user can still tap the back button to return to your app.

Fast app resume for Windows Phone 8 - zarządzanie stosem nawigacyjnym, wybieramy między resetowaniem stanu a jego przywracaniem

Fast Resume Backstack Sample

Fast Application Switching is supported on lower-memory devices.

For Windows Phone 8 apps, memory and execution time policies are enforced while debugging.

Like Windows 8, Windows Phone 8 uses LaunchFileAsync to launch a file and LaunchUriAsync to launch a URI. However, the way Windows Phone XAML apps receive a file or URI is different. Also, Windows Phone does not have a “default” Store app.

File associations are also used to determine which file types apps can read from an SD card using the external storage APIs.

Sometimes Internet Explorer overrides file associations: it launches the built-in media player to handle all music and video file types. Specifically, any file that has an audio/ or video/ content type. For example, your app can handle a (non-reserved) music and video file when it is launched from an email attachment. But if the same file is launched from Internet Explorer, the built-in media player will handle the file.

You can associate a maximum of 20 file extensions with each file association. If your app reads files from the SD card, you must also specify the ContentType attribute to describe the type of file.

/FileTypeAssociation?fileToken=89819279-4fe0-4531-9f57-d633f0949a19

Upon launch, map the incoming deep link URI to an app page that can handle the file. If you have multiple pages to handle multiple file types, use a custom URI mapper and the GetSharedFileName method to check the file type before mapping the URI.

SharedStorageAccessManager

Kafelki

Adding Windows Phone 8 Tile functionality to Windows Phone OS 7.1 apps

If you plan to maintain an app that targets Windows Phone OS 7.1, you can use reflection to access Windows Phone 8 APIs that showcase the new Tile functionality. This way, if your Windows Phone OS 7.1 app runs on a phone that supports Windows Phone 8 Tile features, those customers will have access to the new Tile features.

You create and update Windows Phone 8 Tiles in your Windows Phone OS 7.1 app in the same way as a Windows Phone 8 app. The one difference is that you must first update the small, medium, and (optionally) wide default Tile with a local image. On the next update, you can use a local or remote image as usual.

<AppExtra xmlns="" AppPlatformVersion="8.0">
    <Extra Name="Tiles"/>
</AppExtra>

Implementacja za pomocą refleksji.

Lock screen

A user can set your app as the default lock screen background image provider in the phone lock screen settings screen before your app has had a chance to set up the image. For this reason, you should include a default lock screen background image at the root of your main project's XAP package. Name the image DefaultLockScreen.jpg.

Camera & photos

The lens feature can do more than launch an app from the built-in camera. Rich media lenses incorporate data from the local folder or the web to provide a richer and deeper way of engaging with images they have captured. A rich media lens can save a JPG image to the media library to represent each rich media item that it has captured. When viewing that image from the built-in photo viewer, it’s marked with a captured by caption. Then, from the app bar, users can relaunch the rich media experience by tapping the open link.

IC622576

Rich media lenses differ from a traditional camera app because they save additional information about the image in the app’s local folder.

Don’t use the rich media open link for traditional photo editing, which is limited to only bit manipulations on the JPG file that’s in the camera roll. Rich media extensibility is intended for apps that do “rich editing” using additional information that it has about the photo. For example, allowing the user to choose a different photo from a “time shifted” capture, when additional photos are stored in the app’s local folder, would be considered rich editing. Use the open link only when the user can increase their experience of the photo by viewing it inside your app. For traditional photo editing, such as bit manipulations, cropping, brightening, rotating, etc., use the edit or apps link

<Extension ExtensionName="Photos_Rich_Media_Edit"
           ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5632}"
           TaskID="_default" />

/MainPage.xaml?Action=RichMediaEdit&token=%7Bed8b7de8-6cf9-454e-afe4-abb60ef75160%7D

Photo Extensibility Sample

The Microsoft.Devices.PhotoCamera class gives you the ability to programmatically capture photos in your app. You can use this class to specify the photo resolution and flash settings, and trigger autofocus. For advanced photo capture, the Windows.Phone.Media.Capture.PhotoCaptureDevice class provides an extended set of capabilities and better performance. Use this class to control photo properties such as ISO, exposure compensation, and manual focus position (when available on the phone).

Advanced photo capture for Windows Phone 8  (WinRT)

Windows.Foundation.Size res = SupportedResolutions[0];
this.captureDevice = await PhotoCaptureDevice.OpenAsync(CameraSensorLocation.Back, res);

The initial preview resolution is automatically assigned based on the initial capture resolution and the screen resolution of the phone. Later on, you can set the resolution with the SetCaptureResolutionAsync and SetPreviewResolutionAsync methods. To find out which resolutions are available on the phone, use the GetAvailableCaptureResolutions and GetAvailablePreviewResolutions methods.

Cameras on Windows Phone are optional, so all apps need to check the phone to see if a camera exists. You can use the static property PhotoCaptureDevice.AvailableSensorLocations to check for cameras.

CameraCaptureSequence seq;
seq = cam.CreateCaptureSequence(1);

In this release, the Windows.Phone.Media.Capture.CameraCaptureSequence class supports only single-frame capture.

When capturing photos, you can use the KnownCameraGeneralProperties and the KnownCameraPhotoProperties methods to specify camera and photo settings. Use the SetProperty method to set properties that affect all frames in the capture sequence. Not all properties are supported by each phone. Use the GetSupportedPropertyValues or the GetSupportedPropertyRange method to determine which property values you can use.

// Set camera properties.
cam.SetProperty(KnownCameraPhotoProperties.FlashMode, FlashState.On);
cam.SetProperty(KnownCameraGeneralProperties.PlayShutterSoundOnCapture, true);
cam.SetProperty(KnownCameraGeneralProperties.AutoFocusRange, AutoFocusRange.Infinity);

You can also set properties on an individual frame.

// Set the frame properties.
seq.Frames[0].DesiredProperties[KnownCameraPhotoProperties.SceneMode]
   = CameraSceneMode.Portrait;

The DesiredProperties property is like a “wish list.” Each phone is limited in the number and combinations of properties that it can apply to frames; properties specified with DesiredProperties are not guaranteed. To see which properties were actually used after the capture, use the frame’s AppliedProperties property.

MemoryStream captureStream1 = new MemoryStream();

// Assign the capture stream.
seq.Frames[0].CaptureStream = captureStream1.AsOutputStream();

Use the ThumbnailStream property if you want to display a thumbnail image of the frame after it has been captured.

// Prepare the capture sequence.
await cam.PrepareCaptureSequenceAsync(seq);

Windows Phone 8 provides additional capture methods that you can use with native code.

Advanced capture properties for Windows Phone 8

Capturing video for Windows Phone

The System.Windows.Media.CaptureSource class, used in conjunction the FileSink class, give your app the ability to programmatically record video. For advanced video and encoding settings, the Windows.Phone.Media.Capture.AudioVideoCaptureDevice class provides an extended set of capabilities and better performance. Use this class to control video properties such as encoding settings, torch power, system mute, and manual focus position.

Photo extensibility for Windows Phone

Photo Viewer

IC619198

3 - Extend the photo edit picker (Windows Phone 8 only): Your app can be launched from the edit link and allow the user to edit their photo.

4 - Extend the photo edit picker (Windows Phone 8 only): Your app can be launched from the edit link and allow the user to edit their photo.

Photo Extensibility Sample

Auto-upload apps for Windows Phone 8

Apps that provide auto-upload functionality register for the auto-upload extension and launch to an auto-upload settings page when launched from the Settings app. To perform uploads, an auto-upload app must use a resource-intensive background agent, using the ResourceIntensiveTask class. Unlike other background agents, resource-intensive agents for auto-upload apps do not expire.

Apps that provide auto-upload functionality launch to a settings page when they are launched from the Settings app. In the Settings app, the photos+camera settings page lists an apps link at the bottom of the page. That link launches the auto-upload apps page.

IC600184

<Extension ExtensionName="Photos_Auto_Upload"
           ConsumerID = "{5B04B775-356B-4AA0-AAF8-6491FFEA5632}"
           TaskID="_default"/>

When the deep link URI contains the keyword ConfigurePhotosUploadSettings, launch your app to a settings page on which a user can configure the auto upload.

When you create a resource-intensive agent for your auto-upload app, do not set an expiration time for the task. This will ensure that the agent doesn’t expire if your app hasn’t been opened for 14 days.

Before your app can perform automatic uploads, it will need to provide a way for users to enter their user credentials to the photo storage web service. Your foreground app can use the settings page for this task, but you don’t have to use the same page. For storing user credentials, we recommend encrypting them with the ProtectedData class.

You background agent is responsible for monitoring the media library, and for keeping track of what photos need to be uploaded. It also needs to track upload status so that it can resume an upload if the phone loses connectivity.

Custom contact store

Custom properties are not displayed on the contact card in the People hub, but can be accessed programmatically from your app. The contact store APIs also provide a mechanism for you to enumerate changes between your custom contact store on the phone and a contact store you maintain in a cloud service in order to synchronize the two stores.

The custom contact store APIs only provide access to the contacts created by your app. If your app needs read-access to the phone’s contact store or calendar, there are different APIs that you should use.

Each Windows Phone app can have a single contact store. You open the store by calling CreateOrOpenAsync. The store will be created when you call this method, if it doesn’t already exist. The overloaded version of this method accepts a member of the ContactStoreSystemAccessMode enumeration and a member of the ContactStoreApplicationAccessMode enumeration, which specify how much access the system and other apps have to your contact store. ContactStoreSystemAccessMode.ReadOnly indicates that only your app can modify your contacts. ContactStoreSystemAccessMode.ReadWrite means that the phone can modify your contacts through its built-in contacts experience. ContactStoreApplicationAccessMode.LimitedReadOnly means that other apps can read only the display name and the profile picture of your contacts. ContactStoreApplicationAccessMode.ReadOnly means that other apps can read all of the properties of your contacts. The default settings are ContactStoreSystemAccessMode.ReadOnly and ContactStoreApplicationAccessMode.LimitedReadOnly.

ContactStore store = await ContactStore.CreateOrOpenAsync(
    ContactStoreSystemAccessMode.ReadWrite,
    ContactStoreApplicationAccessMode.ReadOnly);

The StoredContact object has built-in properties for several common pieces of contact data, such as given name and family name. Each contact also has a field that contains a local ID, which is dynamically assigned by the operating system, and a field for storing a remote ID that can be set by your app. You can use the remote and local IDs to associate contacts in your app’s contact store on the phone with a remote contact store in the cloud.

In addition to the fields that are provided by the StoredContact object, you can add more properties by calling GetExtendedPropertiesAsync. This returns a dictionary of key value pairs that you can populate with contact data. You can use the fields of the KnownContactProperties class for key values if you want the fields to be consistent with the phone’s internal contact property names. Or you can specify any arbitrary string as a key.


async public void AddContact(string remoteId, string givenName, string familyName, string email, string codeName)
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();

    StoredContact contact = new StoredContact(store);

    RemoteIdHelper remoteIDHelper = new RemoteIdHelper();
    contact.RemoteId = await remoteIDHelper.GetTaggedRemoteId(store, remoteId);

    contact.GivenName = givenName;
    contact.FamilyName = familyName;

    IDictionary<string, object> props = await contact.GetPropertiesAsync();
    props.Add(KnownContactProperties.Email, email);

    IDictionary<string, object> extprops = await contact.GetExtendedPropertiesAsync();
    extprops.Add("Codename", codeName);

    await contact.SaveAsync();

}

You can update a contact by retrieving it from the store, modifying its properties, and then saving it again. The following code example uses FindContactByRemoteIdAsync to retrieve a contact using its remote ID. You can also call FindContactByLocalIdAsync to retrieve a contact by local ID.


async private void UpdateContact(string remoteId, string givenName, string familyName, string email, string codeName)
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();

    RemoteIdHelper remoteIDHelper = new RemoteIdHelper();
    string taggedRemoteId = await remoteIDHelper.GetTaggedRemoteId(store, remoteId);
    StoredContact contact = await store.FindContactByRemoteIdAsync(taggedRemoteId);

    if (contact != null)
    {
        contact.GivenName = givenName;
        contact.FamilyName = familyName;

        IDictionary<string, object> props = await contact.GetPropertiesAsync();
        props[KnownContactProperties.Email] = email;

        IDictionary<string, object> extprops = await contact.GetExtendedPropertiesAsync();
        extprops["Codename"] = codeName;

        await contact.SaveAsync();
    }
}

Delete a contact by calling DeleteContactAsync and passing in the local ID of the contact to be deleted. If you want to delete a contact based on the remote ID, call FindContactByRemoteIdAsync then use the value of the Id property to call DeleteContactAsync.

async private void DeleteContact(string id)
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();
    await store.DeleteContactAsync(id);  
}

You can query for all contacts in the store by calling CreateContactQuery. The no-argument version of the method returns the default set of fields for each contact, and uses the default ordering. Call GetContactsAsync on the returned ContactQueryResult object to retrieve the list of returned contacts.

async private void DefaultQuery()
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();
    ContactQueryResult result = store.CreateContactQuery();
    IReadOnlyList<StoredContact> contacts = await result.GetContactsAsync();

    ContactListBox.ItemsSource = contacts;

}

If there is a subset of the KnownContactProperties that you know you will need to access, you can create a new ContactQueryOptions and then add property names to the DesiredFields vector to specify that they should be fetched when the query is made.

You can also set OrderBy to change the field used to order the results, but it is recommended that you use the default ordering because that will provide a consistent user experience across apps.

async private void QueryWithDesiredFields()
{
    ContactStore store = await ContactStore.CreateOrOpenAsync();

    ContactQueryOptions options = new ContactQueryOptions();
    options.DesiredFields.Add(KnownContactProperties.Email);

    ContactQueryResult result = store.CreateContactQuery(options);
    IReadOnlyList<StoredContact> contacts = await result.GetContactsAsync();

    ContactListBox.ItemsSource = contacts;
}

If your cloud-based contact store does not use IDs that are guaranteed to be unique, you can add the following class to your project that will help you add a unique tag to your IDs before you save a contact to the store. It will also help you remove the unique tag from the ID after you have retrieved it from the store so that you can get your original remote ID back.

vCard is a standard file format used for electronic business cards. The ContactInformation class exposes the ParseVcardAsync method, which asynchronously parses the vCard at the specified URI, and then returns a populated ContactInformation object.

task<StoredContact^> SaveFromVcard(ContactStore^ store, String^ uriToVcard)
{
    // Invoke the parser on the passed-in URI.
    return create_task(ContactInformation::ParseVcardAsync(ref new Uri(uriToVcard)))
    .then([=] (ContactInformation^ info) -> StoredContact^
    {
        // When that's done, wrap a stored contact around it, save.
        auto contact = ref new StoredContact(store, info);
        create_task(contact->SaveAsync()).get();

        return contact;
    });
}

Brak komentarzy: