diff --git a/.gitignore b/.gitignore
index cb201f6..f26fbb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
bin
Bin
obj
+packages
TestResults
.DS_Store
_ReSharper.*
@@ -13,4 +14,8 @@ _ReSharper.*
*~
*.swp
*.pidb
-*.userprefs
\ No newline at end of file
+*.userprefs
+*.dotCover
+*.user
+*.ide
+*.DotSettings
diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config
new file mode 100644
index 0000000..67f8ea0
--- /dev/null
+++ b/.nuget/NuGet.Config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.nuget/NuGet.exe b/.nuget/NuGet.exe
new file mode 100644
index 0000000..f1cec45
Binary files /dev/null and b/.nuget/NuGet.exe differ
diff --git a/.nuget/NuGet.targets b/.nuget/NuGet.targets
new file mode 100644
index 0000000..83fe906
--- /dev/null
+++ b/.nuget/NuGet.targets
@@ -0,0 +1,136 @@
+
+
+
+ $(MSBuildProjectDirectory)\..\
+
+
+ false
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+ $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
+ $([System.IO.Path]::Combine($(ProjectDir), "packages.config"))
+
+
+
+
+ $(SolutionDir).nuget
+ packages.config
+
+
+
+
+ $(NuGetToolsPath)\NuGet.exe
+ @(PackageSource)
+
+ "$(NuGetExePath)"
+ mono --runtime=v4.0.30319 $(NuGetExePath)
+
+ $(TargetDir.Trim('\\'))
+
+ -RequireConsent
+ -NonInteractive
+
+ "$(SolutionDir) "
+ "$(SolutionDir)"
+
+
+ $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)
+ $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
+
+
+
+ RestorePackages;
+ $(BuildDependsOn);
+
+
+
+
+ $(BuildDependsOn);
+ BuildPackage;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Details.md b/Details.md
new file mode 100644
index 0000000..2bf49dc
--- /dev/null
+++ b/Details.md
@@ -0,0 +1,107 @@
+Xamarin.Mobile is an API for accessing common platform features, such as
+reading the user's address book and using the camera, across iOS,
+Android, and Windows Phone.
+
+The goal of Xamarin.Mobile is to decrease the amount of
+platform-specific code needed to perform common tasks in multiplatform
+apps, making development simpler and faster.
+
+Xamarin.Mobile is currently a preview release and is subject to API
+changes.
+
+**Note:** The Windows Phone 7.1 version of the library requires the
+Microsoft.Bcl.Async NuGet package. You'll need to restore this package
+to use the samples or download this package to any WP7 app using
+Xamarin.Mobile.
+
+## Examples
+
+To access the address book (requires `READ_CONTACTS` permissions
+on Android):
+
+```csharp
+using Xamarin.Contacts;
+// ...
+
+var book = new Xamarin.Contacts.AddressBook ();
+// new AddressBook (this); on Android
+if (!await book.RequestPermission()) {
+ Console.WriteLine ("Permission denied by user or manifest");
+ return;
+}
+
+foreach (Contact contact in book.OrderBy (c => c.LastName)) {
+ Console.WriteLine ("{0} {1}", contact.FirstName, contact.LastName);
+}
+```
+
+To get the user's location (requires `ACCESS_COARSE_LOCATION` and
+`ACCESS_FINE_LOCATION` permissions on Android):
+
+```csharp
+using Xamarin.Geolocation;
+// ...
+
+var locator = new Geolocator { DesiredAccuracy = 50 };
+// new Geolocator (this) { ... }; on Android
+
+Position position = await locator.GetPositionAsync (timeout: 10000);
+
+Console.WriteLine ("Position Status: {0}", position.Timestamp);
+Console.WriteLine ("Position Latitude: {0}", position.Latitude);
+Console.WriteLine ("Position Longitude: {0}", position.Longitude);
+```
+
+To take a photo:
+
+```csharp
+using Xamarin.Media;
+// ...
+
+var picker = new MediaPicker ();
+if (!picker.IsCameraAvailable)
+ Console.WriteLine ("No camera!");
+else {
+ try {
+ MediaFile file = await picker.TakePhotoAsync (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+ });
+
+ Console.WriteLine (file.Path);
+ } catch (OperationCanceledException) {
+ Console.WriteLine ("Canceled");
+ }
+}
+```
+
+On Android (requires `WRITE_EXTERNAL_STORAGE` permissions):
+
+```csharp
+using Xamarin.Media;
+// ...
+
+protected override void OnCreate (Bundle bundle)
+{
+ var picker = new MediaPicker (this);
+ if (!picker.IsCameraAvailable)
+ Console.WriteLine ("No camera!");
+ else {
+ var intent = picker.GetTakePhotoUI (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+ });
+ StartActivityForResult (intent, 1);
+ }
+}
+
+protected override async void OnActivityResult (int requestCode, Result resultCode, Intent data)
+{
+ // User canceled
+ if (resultCode == Result.Canceled)
+ return;
+
+ MediaFile file = await data.GetMediaFileExtraAsync (this);
+ Console.WriteLine (file.Path);
+}
+```
\ No newline at end of file
diff --git a/GettingStarted.md b/GettingStarted.md
new file mode 100644
index 0000000..fe7d845
--- /dev/null
+++ b/GettingStarted.md
@@ -0,0 +1,123 @@
+## Examples
+
+### Contacts
+To access the address book (requires `READ_CONTACTS` permissions
+on Android):
+
+```csharp
+using Xamarin.Contacts;
+// ...
+
+var book = new Xamarin.Contacts.AddressBook ();
+book.RequestPermission().ContinueWith (t => {
+ if (!t.Result) {
+ Console.WriteLine ("Permission denied by user or manifest");
+ return;
+ }
+
+ foreach (Contact contact in book.OrderBy (c => c.LastName)) {
+ Console.WriteLine ("{0} {1}", contact.FirstName, contact.LastName);
+ }
+}, TaskScheduler.FromCurrentSynchronizationContext());
+```
+
+### Geolocation
+
+To get the user's location (requires `ACCESS_COARSE_LOCATION` and
+`ACCESS_FINE_LOCATION` permissions on Android):
+
+```csharp
+using Xamarin.Geolocation;
+// ...
+
+var locator = new Geolocator { DesiredAccuracy = 50 };
+// new Geolocator (this) { ... }; on Android
+locator.GetPositionAsync (timeout: 10000).ContinueWith (t => {
+ Console.WriteLine ("Position Status: {0}", t.Result.Timestamp);
+ Console.WriteLine ("Position Latitude: {0}", t.Result.Latitude);
+ Console.WriteLine ("Position Longitude: {0}", t.Result.Longitude);
+}, TaskScheduler.FromCurrentSynchronizationContext());
+```
+
+NOTE: On iOS 8.0+ you must set either `NSLocationWhenInUseUsageDescription` or `NSLocationAlwaysUsageDescription` in your `Info.plist` file so that Xamarin.Mobile will request the appropriate permission from the user.
+
+### Media
+
+`MediaPicker` allows you to invoke the native UI to take or select photos or video. Given
+that there is this UI interaction, the code (while simpler than doing it manually) will not
+be completely cross-platform.
+
+To take a photo on iOS, Windows Phone or WinRT:
+
+```csharp
+using Xamarin.Media;
+// ...
+
+var picker = new MediaPicker();
+picker.PickPhotoAsync().ContinueWith (t => {
+ MediaFile file = t.Result;
+ Console.WriteLine (file.Path);
+}, TaskScheduler.FromCurrentSynchronizationContext());
+```
+
+On Android and optionally on iOS, you control the UI.
+
+To take a photo on Android (requires `WRITE_EXTERNAL_STORAGE` permissions):
+
+```csharp
+using Xamarin.Media;
+// ...
+
+protected override void OnCreate (Bundle bundle)
+{
+ var picker = new MediaPicker (this);
+ if (!picker.IsCameraAvailable)
+ Console.WriteLine ("No camera!");
+ else {
+ var intent = picker.GetTakePhotoUI (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+ });
+ StartActivityForResult (intent, 1);
+ }
+}
+
+protected override void OnActivityResult (int requestCode, Result resultCode, Intent data)
+{
+ // User canceled
+ if (resultCode == Result.Canceled)
+ return;
+
+ data.GetMediaFileExtraAsync (this).ContinueWith (t => {
+ Console.WriteLine (t.Result.Path);
+ }, TaskScheduler.FromCurrentSynchronizationContext());
+}
+```
+
+To take a photo on iOS controlling the UI:
+
+```csharp
+using Xamarin.Media;
+// ...
+
+var picker = new MediaPicker();
+MediaPickerController controller = picker.GetTakePhotoUI (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+});
+
+// On iPad, you'll use UIPopoverController to present the controller
+PresentViewController (controller, true, null);
+
+controller.GetResultAsync().ContinueWith (t => {
+ // Dismiss the UI yourself
+ controller.DismissViewController (true, () => {
+ MediaFile file = t.Result;
+ });
+
+}, TaskScheduler.FromCurrentSynchronizationContext());
+```
+#####Note to iOS 8 Developers
+Showing a `MediaPicker` in response to a `UIActionSheet.Clicked` event will cause unexpected behavior on iOS 8. Apps should be updated to conditionally use an `UIAlertController` with a style of `UIAlertControllerStyle.ActionSheet.` See the iOS sample for more info.
+
+
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..b778464
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,174 @@
+# Apache License
+Version 2.0, January 2004
+[http://www.apache.org/licenses/](http://www.apache.org/licenses/)
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
\ No newline at end of file
diff --git a/MonoDroid/MonoMobile.Example/Activity1.cs b/MonoDroid/MonoMobile.Example/Activity1.cs
deleted file mode 100644
index 7f4e0d1..0000000
--- a/MonoDroid/MonoMobile.Example/Activity1.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using System;
-
-using Android.App;
-using Android.Content;
-using Android.Locations;
-using Android.Runtime;
-using Android.Views;
-using Android.Widget;
-using Android.OS;
-using MonoMobile.Extensions;
-
-namespace MonoMobile.Example
-{
- [Activity(Label = "MonoMobile Android Example", MainLauncher = true)]
- public class Activity1 : Activity
- {
- IGeolocation location;
- bool watching = false;
- string watchid = "";
- TextView locationTextView;
- Button watchButton;
-
- protected override void OnCreate (Bundle bundle)
- {
- base.OnCreate (bundle);
-
- // Set our view from the "main" layout resource
- SetContentView (Resource.Layout.Main);
-
- LocationManager locationManager=(LocationManager) GetSystemService(LocationService);
-
- location = new Geolocation(locationManager);
- //
- // Get our button from the layout resource,
- // and attach an event to it
- Button getLocationButton = FindViewById(Resource.Id.GetLocationButton);
-
- watchButton = FindViewById(Resource.Id.WatchButton);
-
- locationTextView = FindViewById(Resource.Id.LocationTextView);
-
- getLocationButton.Click += delegate
- {
- LogDeviceInfo();
- GetCurrentPosition();
- };
-
- watchButton.Click += delegate { ToggleWatch(); };
- }
-
- private void GetCurrentPosition()
- {
- location.GetCurrentPosition(
- CurrentPositionSuccess,
- (error) => { },
- new GeolocationOptions() {EnableHighAccuracy = false }
- );
- }
-
-
- private void ToggleWatch()
- {
- if (!watching)
- {
- watchid=location.WatchPosition(WatchSuccess);
- watchButton.Text = GetString(Resource.String.watchStop);
- }
- else
- {
- location.ClearWatch(watchid);
- watchButton.Text = GetString(Resource.String.watchStart);
- }
- watching = !watching;
- }
-
- private void LogDeviceInfo()
- {
- var device = new MonoMobile.Extensions.Device(this);
- Android.Util.Log.Info("MonoMobile.Extensions", "Device Name: {0}", device.Name);
- Android.Util.Log.Info("MonoMobile.Extensions", "Device Platform: {0}", device.Platform);
- Android.Util.Log.Info("MonoMobile.Extensions", "Device UUID: {0}", device.UUID);
- Android.Util.Log.Info("MonoMobile.Extensions", "Device Version: {0}", device.Version);
- Android.Util.Log.Info("MonoMobile.Extensions", "MonoMobile Version: {0}", device.MonoMobileVersion);
- }
-
- private void CurrentPositionSuccess(Position obj)
- {
- string message = string.Format("GetCurrentPosition location: {0} {1}-{2} [{3}]",obj.Timestamp, obj.Coords.Latitude,
- obj.Coords.Longitude, obj.Coords.Accuracy);
- Android.Util.Log.Info("MonoMobile.Extensions",message);
- locationTextView.Text = message;
- }
-
- private void WatchSuccess(Position obj)
- {
- string message = string.Format("WatchPosition location: {0} {1}-{2} [{3}]",obj.Timestamp, obj.Coords.Latitude,
- obj.Coords.Longitude, obj.Coords.Accuracy);
- Android.Util.Log.Info("MonoMobile.Extension", message);
- locationTextView.Text = message;
- }
- }
-}
-
-
diff --git a/MonoDroid/MonoMobile.Example/Resources/Drawable-mdpi/Icon.png b/MonoDroid/MonoMobile.Example/Resources/Drawable-mdpi/Icon.png
deleted file mode 100644
index a07c69f..0000000
Binary files a/MonoDroid/MonoMobile.Example/Resources/Drawable-mdpi/Icon.png and /dev/null differ
diff --git a/MonoDroid/MonoMobile.Example/Resources/Layout/Main.axml b/MonoDroid/MonoMobile.Example/Resources/Layout/Main.axml
deleted file mode 100644
index 5a4be7a..0000000
--- a/MonoDroid/MonoMobile.Example/Resources/Layout/Main.axml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
diff --git a/MonoDroid/MonoMobile.Example/Resources/Resource.designer.cs b/MonoDroid/MonoMobile.Example/Resources/Resource.designer.cs
deleted file mode 100644
index ee878d8..0000000
--- a/MonoDroid/MonoMobile.Example/Resources/Resource.designer.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.431
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace MonoMobile.Example
-{
-
-
- public partial class Resource
- {
-
- public partial class Attribute
- {
-
- private Attribute()
- {
- }
- }
-
- public partial class Drawable
- {
-
- // aapt resource value: 0x7f020000
- public const int Icon = 2130837504;
-
- private Drawable()
- {
- }
- }
-
- public partial class Id
- {
-
- // aapt resource value: 0x7f050000
- public const int GetLocationButton = 2131034112;
-
- // aapt resource value: 0x7f050002
- public const int LocationTextView = 2131034114;
-
- // aapt resource value: 0x7f050001
- public const int WatchButton = 2131034113;
-
- private Id()
- {
- }
- }
-
- public partial class Layout
- {
-
- // aapt resource value: 0x7f030000
- public const int Main = 2130903040;
-
- private Layout()
- {
- }
- }
-
- public partial class String
- {
-
- // aapt resource value: 0x7f040003
- public const int app_name = 2130968579;
-
- // aapt resource value: 0x7f040000
- public const int getlocation = 2130968576;
-
- // aapt resource value: 0x7f040004
- public const int locationTextView = 2130968580;
-
- // aapt resource value: 0x7f040001
- public const int watchStart = 2130968577;
-
- // aapt resource value: 0x7f040002
- public const int watchStop = 2130968578;
-
- private String()
- {
- }
- }
- }
-}
diff --git a/MonoDroid/MonoMobile.Example/Resources/Values/Strings.xml b/MonoDroid/MonoMobile.Example/Resources/Values/Strings.xml
deleted file mode 100644
index f339d18..0000000
--- a/MonoDroid/MonoMobile.Example/Resources/Values/Strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- Get location
- Start watching
- Stop watching
- MonoMobile.Example
- Not started
-
diff --git a/MonoDroid/MonoMobile.Extensions/Device.cs b/MonoDroid/MonoMobile.Extensions/Device.cs
deleted file mode 100644
index 30f8882..0000000
--- a/MonoDroid/MonoMobile.Extensions/Device.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using Android.App;
-using Android.Content;
-using Android.Provider;
-
-namespace MonoMobile.Extensions
-{
- public class Device : IDevice
- {
- public Device(Activity context)
- {
- Context = context;
- }
-
- private Context Context { get; set; }
-
- public string Name
- {
- get { return Android.OS.Build.Product; }
- }
-
- public string MonoMobileVersion
- {
- get { return ExtensionHelper.MonoMobile; }
- }
-
- public string Platform
- {
- get { return "Android"; }
- }
-
- public string UUID
- {
- get { return Settings.Secure.GetString(Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId); }
- }
-
- public string Version
- {
- get { return Android.OS.Build.VERSION.Release; }
- }
- }
-}
diff --git a/MonoDroid/MonoMobile.Extensions/Geolocation.cs b/MonoDroid/MonoMobile.Extensions/Geolocation.cs
deleted file mode 100644
index 2d97885..0000000
--- a/MonoDroid/MonoMobile.Extensions/Geolocation.cs
+++ /dev/null
@@ -1,187 +0,0 @@
-using System;
-using System.Linq;
-using System.Timers;
-using Android.Locations;
-using Android.OS;
-using Android.Util;
-using Java.IO;
-
-namespace MonoMobile.Extensions
-{
-
- public class Geolocation : Java.Lang.Object, IGeolocation, ILocationListener
- {
- private readonly LocationManager _locationManager;
-
- private Action _success;
- private Action _error;
- private GeolocationOptions _options;
- private string _watchId;
- private Timer _timedWatch = new Timer();
- private bool _isTiming = false;
-
- public Geolocation(LocationManager locationManager)
- {
- _locationManager = locationManager;
- _success = position => { };
- _error = error => { };
- _options= new GeolocationOptions();
- _watchId = Guid.NewGuid().ToString();
- }
-
- #region IGeolocation Members
-
- public void GetCurrentPosition(Action success)
- {
- GetCurrentPosition(success, (error)=> { });
- }
-
- public void GetCurrentPosition(Action success, Action error)
- {
- GetCurrentPosition(success, error, new GeolocationOptions());
- }
-
- public void GetCurrentPosition(Action success, Action error, GeolocationOptions options)
- {
- try
- {
- _success = success;
- _error = error;
- _options = options;
- GetLastKnownLocation(_options);
- }
- catch (Exception exception)
- {
- error(new PositionError(PositionErrorCode.PositionUnavailable, exception.Message));
- }
- }
-
- private void GetLastKnownLocation(GeolocationOptions options)
- {
- Location lastKnownLocation=null;
- if (options!=null && options.EnableHighAccuracy)
- lastKnownLocation = _locationManager.GetLastKnownLocation(LocationManager.GpsProvider);
-
- if (lastKnownLocation==null)
- lastKnownLocation = _locationManager.GetLastKnownLocation(LocationManager.NetworkProvider);
-
- SendLocation(lastKnownLocation);
- }
-
- public string WatchPosition(Action success)
- {
- return WatchPosition(success, error => { });
- }
-
- public string WatchPosition(Action success, Action error)
- {
- return WatchPosition(success,error,new GeolocationOptions());
- }
-
- public string WatchPosition(Action success, Action error, GeolocationOptions options)
- {
- _success = success;
- _error = error;
- _options = options;
- string provider = options==null ? LocationManager.NetworkProvider: _options.EnableHighAccuracy ? LocationManager.GpsProvider : LocationManager.NetworkProvider;
- TimeWatch();
-
- _locationManager.RequestLocationUpdates(provider,_options.MaximumAge, 50,this);
-
- return _watchId;
- }
-
- private void TimeWatch()
- {
- if (_options.Timeout > 0)
- {
- _timedWatch=new Timer(_options.Timeout);
- _timedWatch.Elapsed += TimerElapsed;
- _isTiming = true;
- _timedWatch.Start();
- }
- }
-
- private void TimerElapsed(object o, ElapsedEventArgs e)
- {
- if (_isTiming)
- {
- var options = new GeolocationOptions
- {
- EnableHighAccuracy = false,
- MaximumAge = _options.MaximumAge,
- Timeout = _options.Timeout
- };
- GetLastKnownLocation(options);
- StopTiming();
- }
- }
-
- public void ClearWatch(string watchID)
- {
- if (watchID != _watchId)
- return;
-
- _locationManager.RemoveUpdates(this);
- }
-
- #endregion
-
- #region ILocationListener Members
-
- public void OnLocationChanged(Location location)
- {
- SendLocation(location);
- }
-
- public void OnProviderDisabled(string provider)
- {
- //Does this concern us ?
- }
-
- public void OnProviderEnabled(string provider)
- {
- //Does this concern us ?
- }
-
- public void OnStatusChanged(string provider, int status, Bundle extras)
- {
- //Does this concern us ?
- }
-
-
- #endregion
-
- private void SendLocation(Location lastKnownLocation)
- {
- Position pos=new Position();
- pos.Timestamp = DateTime.Now;
- if (lastKnownLocation != null)
- {
- pos.Coords = new Coordinates
- {
- Accuracy = lastKnownLocation.Accuracy,
- Heading = lastKnownLocation.Bearing,
- Altitude = lastKnownLocation.Altitude,
- AltitudeAccuracy = lastKnownLocation.Accuracy,
- Latitude = lastKnownLocation.Latitude,
- Longitude = lastKnownLocation.Longitude,
- Speed = lastKnownLocation.Speed
- };
-
- }
- _success(pos);
- StopTiming();
- }
-
- private void StopTiming()
- {
- if (_isTiming)
- {
- _isTiming = false;
- _timedWatch.Stop();
- ClearWatch(_watchId);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/MonoDroid/MonoMobile.Extensions/MonoMobile.Extensions.csproj b/MonoDroid/MonoMobile.Extensions/MonoMobile.Extensions.csproj
deleted file mode 100644
index 385a034..0000000
--- a/MonoDroid/MonoMobile.Extensions/MonoMobile.Extensions.csproj
+++ /dev/null
@@ -1,79 +0,0 @@
-
-
-
- DebugMonoDroid
- AnyCPU
- 8.0.30703
- 2.0
- {32DFF77E-AE38-48D6-B067-CF555798EA32}
- {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Library
- Properties
- MonoMobile.Extensions
- MonoMobile.Extensions
- 512
- v2.2
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- None
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- false
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- false
-
-
-
-
-
-
-
-
-
-
-
- ExtensionHelper.cs
-
-
- IDevice.cs
-
-
- IGeolocation.cs
-
-
- INotification.cs
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/MonoDroid/MonoMobile.Extensions/Notification.cs b/MonoDroid/MonoMobile.Extensions/Notification.cs
deleted file mode 100644
index b9007b4..0000000
--- a/MonoDroid/MonoMobile.Extensions/Notification.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-using System;
-using Android.App;
-using Android.Content;
-using Android.Media;
-using Android.OS;
-using Android.Provider;
-using Android.Widget;
-using Java.Lang;
-
-namespace MonoMobile.Extensions
-{
- public class Notification : INotification
- {
- private Activity Context { get; set; }
-
- public Notification(Activity context)
- {
- Context = context;
- }
-
- public void Alert(string message, Action alertCallback)
- {
- Alert(message, alertCallback, "Alert", "OK");
- }
-
- public void Alert(string message, Action alertCallback, string title)
- {
- Alert(message, alertCallback, title, "OK");
- }
-
- public void Alert(string message, Action alertCallback, string title, string buttonName)
- {
- Context.RunOnUiThread(() =>
- {
- var dlg = new AlertDialog.Builder(Context);
- dlg.SetMessage(message);
- dlg.SetTitle(title);
- dlg.SetCancelable(false);
- dlg.SetPositiveButton(buttonName, new DialogInterface(alertCallback));
- dlg.Create();
- dlg.Show();
- });
-
-
- // final PhonegapActivity ctx = this.ctx;
- //final Notification notification = this;
-
- //Runnable runnable = new Runnable() {
- // public void run() {
-
- // AlertDialog.Builder dlg = new AlertDialog.Builder(ctx);
- // dlg.setMessage(message);
- // dlg.setTitle(title);
- // dlg.setCancelable(false);
- // dlg.setPositiveButton(buttonLabel,
- // new AlertDialog.OnClickListener() {
- // public void onClick(DialogInterface dialog, int which) {
- // dialog.dismiss();
- // notification.success(new PluginResult(PluginResult.Status.OK, 0), callbackId);
- // }
- // });
- // dlg.create();
- // dlg.show();
- // };
- //};
- //this.ctx.runOnUiThread(runnable);
- }
-
- public class DialogInterface : IDialogInterfaceOnClickListener
- {
- private readonly Action _alertCallback;
- public DialogInterface(Action alertCallback)
- {
- _alertCallback = alertCallback;
- }
-
- public void OnClick(IDialogInterface dialog, DialogInterfaceButton which)
- {
- dialog.Dismiss();
- _alertCallback();
- }
-
- public IntPtr Handle
- {
- get { return Handle; }
- }
- }
-
- public void Confirm(string message, Action confirmCallback)
- {
- throw new NotImplementedException();
- }
-
- public void Confirm(string message, Action confirmCallback, string title)
- {
- throw new NotImplementedException();
- }
-
- public void Confirm(string message, Action confirmCallback, string title, string buttonLabels)
- {
- throw new NotImplementedException();
- }
-
- public void Beep()
- {
- Beep(1);
- }
-
- public void Beep(int count)
- {
- Android.Net.Uri ringtone = RingtoneManager.GetActualDefaultRingtoneUri(Context, RingtoneType.Notification);
- Ringtone notification = RingtoneManager.GetRingtone(Context, ringtone);
-
- // If phone is not set to silent mode
- if (notification != null)
- {
- for (int i = 0; i < count; ++i)
- {
- notification.Play();
- long timeout = 5000;
- while (notification.IsPlaying && (timeout > 0))
- {
- timeout = timeout - 100;
- try
- {
- Thread.Sleep(100);
- }
- catch (InterruptedException e)
- {
- }
- }
- }
- }
- }
-
- public void Vibrate()
- {
- Vibrate(500);
- }
-
- public void Vibrate(int milliseconds)
- {
- Vibrator vibrator = (Vibrator) Context.GetSystemService(Android.Content.Context.VibratorService);
- vibrator.Vibrate(milliseconds);
- }
- }
-}
diff --git a/MonoDroid/MonoMobile.ExtensionsMonoDroid.sln b/MonoDroid/MonoMobile.ExtensionsMonoDroid.sln
deleted file mode 100644
index ac2b827..0000000
--- a/MonoDroid/MonoMobile.ExtensionsMonoDroid.sln
+++ /dev/null
@@ -1,42 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MonoDroid", "MonoDroid", "{D66A3439-B7B0-4641-9B11-BCD00A611EE5}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoMobile.Extensions", "MonoMobile.Extensions\MonoMobile.Extensions.csproj", "{32DFF77E-AE38-48D6-B067-CF555798EA32}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoMobile.Example", "MonoMobile.Example\MonoMobile.Example.csproj", "{C4790D64-9278-4EB8-8623-86DC572CB8D1}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{21B17BB4-06C1-4E6E-BD78-C022CD8F8266}"
- ProjectSection(SolutionItems) = preProject
- ..\Shared\ExtensionHelper.cs = ..\Shared\ExtensionHelper.cs
- ..\Shared\IDevice.cs = ..\Shared\IDevice.cs
- ..\Shared\IGeolocation.cs = ..\Shared\IGeolocation.cs
- ..\Shared\INotification.cs = ..\Shared\INotification.cs
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- DebugMonoDroid|Any CPU = DebugMonoDroid|Any CPU
- ReleaseMonoDroid|Any CPU = ReleaseMonoDroid|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {32DFF77E-AE38-48D6-B067-CF555798EA32}.DebugMonoDroid|Any CPU.ActiveCfg = DebugMonoDroid|Any CPU
- {32DFF77E-AE38-48D6-B067-CF555798EA32}.DebugMonoDroid|Any CPU.Build.0 = DebugMonoDroid|Any CPU
- {32DFF77E-AE38-48D6-B067-CF555798EA32}.ReleaseMonoDroid|Any CPU.ActiveCfg = ReleaseMonoDroid|Any CPU
- {32DFF77E-AE38-48D6-B067-CF555798EA32}.ReleaseMonoDroid|Any CPU.Build.0 = ReleaseMonoDroid|Any CPU
- {C4790D64-9278-4EB8-8623-86DC572CB8D1}.DebugMonoDroid|Any CPU.ActiveCfg = DebugMonoDroid|Any CPU
- {C4790D64-9278-4EB8-8623-86DC572CB8D1}.DebugMonoDroid|Any CPU.Build.0 = DebugMonoDroid|Any CPU
- {C4790D64-9278-4EB8-8623-86DC572CB8D1}.ReleaseMonoDroid|Any CPU.ActiveCfg = ReleaseMonoDroid|Any CPU
- {C4790D64-9278-4EB8-8623-86DC572CB8D1}.ReleaseMonoDroid|Any CPU.Build.0 = ReleaseMonoDroid|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {32DFF77E-AE38-48D6-B067-CF555798EA32} = {D66A3439-B7B0-4641-9B11-BCD00A611EE5}
- {C4790D64-9278-4EB8-8623-86DC572CB8D1} = {D66A3439-B7B0-4641-9B11-BCD00A611EE5}
- EndGlobalSection
- GlobalSection(MonoDevelopProperties) = preSolution
- StartupItem = MonoMobile.Example\MonoMobile.Example.csproj
- EndGlobalSection
-EndGlobal
diff --git a/MonoDroid/Samples/ContactsSample/Assets/AboutAssets.txt b/MonoDroid/Samples/ContactsSample/Assets/AboutAssets.txt
new file mode 100644
index 0000000..ee39886
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/Assets/AboutAssets.txt
@@ -0,0 +1,19 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories) and given a Build Action of "AndroidAsset".
+
+These files will be deployed with you package and will be accessible using Android's
+AssetManager, like this:
+
+public class ReadAsset : Activity
+{
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ InputStream input = Assets.Open ("my_asset.txt");
+ }
+}
+
+Additionally, some Android functions will automatically load asset files:
+
+Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
\ No newline at end of file
diff --git a/MonoDroid/Samples/ContactsSample/ContactActivity.cs b/MonoDroid/Samples/ContactsSample/ContactActivity.cs
new file mode 100644
index 0000000..998dac0
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/ContactActivity.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Android.App;
+using Android.Content;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using Android.Widget;
+using Xamarin.Contacts;
+
+namespace ContactsSample
+{
+ [Activity (Label = "ContactActivity")]
+ public class ContactActivity : Activity
+ {
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ //
+ // Get the contact ID that is passed in
+ // from the main activity
+ //
+ String contactID = String.Empty;
+ if(bundle != null)
+ {
+ contactID = bundle.GetString("contactID");
+ }
+ else
+ {
+ contactID = Intent.GetStringExtra("contactID");
+ }
+
+ Contact contact = MainActivity.AddressBook.Load (contactID);
+
+ //
+ // If the contact is empty, we'll
+ // display a 'not found' error
+ //
+ String displayName = "Contact Not Found";
+ String mobilePhone = String.Empty;
+
+ //
+ // Set the displayName variable to the contact's
+ // DisplayName property
+ //
+ if(contact != null)
+ {
+ displayName = contact.DisplayName;
+ var phone = contact.Phones.FirstOrDefault (p => p.Type == PhoneType.Mobile);
+ if(phone != null)
+ {
+ mobilePhone = phone.Number;
+ }
+ }
+
+ //
+ // Show the contacts display name and mobile phone
+ //
+ SetContentView (Resource.Layout.contact_view);
+ var fullNameTextView = FindViewById (Resource.Id.full_name);
+ fullNameTextView.Text = displayName;
+ var mobilePhoneTextView = FindViewById (Resource.Id.mobile_phone);
+ mobilePhoneTextView.Text = mobilePhone;
+
+ }
+ }
+}
+
diff --git a/MonoDroid/Samples/ContactsSample/Contacts Sample.csproj b/MonoDroid/Samples/ContactsSample/Contacts Sample.csproj
new file mode 100644
index 0000000..63039d3
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/Contacts Sample.csproj
@@ -0,0 +1,86 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Properties
+ ContactsSample
+ ContactsSample
+ 512
+ true
+ Resources\Resource.Designer.cs
+ Off
+ Properties\AndroidManifest.xml
+ v2.3
+
+
+ True
+ full
+ False
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ None
+ armeabi;armeabi-v7a;x86
+
+
+ pdbonly
+ True
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ False
+ armeabi;armeabi-v7a;x86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {32DFF77E-AE38-48D6-B067-CF555798EA32}
+ Xamarin.Mobile.Android
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Samples/ContactsSample/ContactsSample.sln b/MonoDroid/Samples/ContactsSample/ContactsSample.sln
new file mode 100644
index 0000000..c942ba8
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/ContactsSample.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContactsSample", "ContactsSample.csproj", "{32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = ContactsSample.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/MonoDroid/Samples/ContactsSample/MainActivity.cs b/MonoDroid/Samples/ContactsSample/MainActivity.cs
new file mode 100644
index 0000000..f194121
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/MainActivity.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Text;
+using System.Threading.Tasks;
+using Android.App;
+using Android.Content;
+using Android.Database;
+using Android.Net;
+using Android.OS;
+using Android.Provider;
+using Android.Widget;
+using Xamarin.Contacts;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace ContactsSample
+{
+ [Activity(Label = "ContactsSample", MainLauncher = true, Icon = "@drawable/icon")]
+ public class MainActivity : ListActivity
+ {
+ List contacts = new List();
+ List contactIDs = new List();
+
+ public static readonly AddressBook AddressBook = new AddressBook (Application.Context) { PreferContactAggregation = true };
+
+ protected override void OnCreate(Bundle bundle)
+ {
+ base.OnCreate(bundle);
+
+ // We must request permission to access the user's address book
+ // This will prompt the user on platforms that ask, or it will validate
+ // manifest permissions on platforms that declare their required permissions.
+ AddressBook.RequestPermission().ContinueWith (t =>
+ {
+ if (!t.Result) {
+ Toast.MakeText (this, "Permission denied, check your manifest", ToastLength.Long).Show();
+ return;
+ }
+
+ // Contacts can be selected and sorted using LINQ!
+ //
+ // In this sample, we'll just use LINQ to sort contacts by
+ // their last name in reverse order.
+ foreach (Contact contact in AddressBook.Where (c => c.FirstName != null).OrderBy (c => c.FirstName)) {
+ contacts.Add (contact.DisplayName);
+ contactIDs.Add (contact.Id); // Save the ID in a parallel list
+ }
+
+ ListAdapter = new ArrayAdapter (this, Resource.Layout.list_item, contacts.ToArray());
+ ListView.TextFilterEnabled = true;
+
+ // When clicked, start a new activity to display more contact details
+ ListView.ItemClick += delegate (object sender, AdapterView.ItemClickEventArgs args) {
+
+ // To show the contact on the details activity, we
+ // need to send that activity the contacts ID
+ string contactId = contactIDs[args.Position];
+ Intent showContactDetails = new Intent (this, typeof(ContactActivity));
+ showContactDetails.PutExtra ("contactID", contactId);
+ StartActivity (showContactDetails);
+
+ // Alternatively, show a toast with the name of the contact selected
+ //
+ //Toast.MakeText (Application, ((TextView)args.View).Text, ToastLength.Short).Show ();
+ };
+ }, TaskScheduler.FromCurrentSynchronizationContext());
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Samples/ContactsSample/Properties/AndroidManifest.xml b/MonoDroid/Samples/ContactsSample/Properties/AndroidManifest.xml
new file mode 100644
index 0000000..33f6f94
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/Properties/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Samples/ContactsSample/Properties/AssemblyInfo.cs b/MonoDroid/Samples/ContactsSample/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8739c90
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Android.App;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ContactsSample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Xamarin Inc.")]
+[assembly: AssemblyProduct("ContactsSample")]
+[assembly: AssemblyCopyright("Copyright © 2011-2012 Xamarin Inc.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a557ce8c-9dbe-4b93-8fc4-95ffc126cf14")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+
+// This app uses the internet, this can be removed if not needed
+[assembly: UsesPermission("android.permission.INTERNET")]
\ No newline at end of file
diff --git a/MonoDroid/Samples/ContactsSample/Resources/Drawable/Icon.png b/MonoDroid/Samples/ContactsSample/Resources/Drawable/Icon.png
new file mode 100644
index 0000000..8074c4c
Binary files /dev/null and b/MonoDroid/Samples/ContactsSample/Resources/Drawable/Icon.png differ
diff --git a/MonoDroid/Samples/ContactsSample/Resources/Layout/contact_view.xml b/MonoDroid/Samples/ContactsSample/Resources/Layout/contact_view.xml
new file mode 100644
index 0000000..9cc411e
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/Resources/Layout/contact_view.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Samples/ContactsSample/Resources/Layout/list_item.xml b/MonoDroid/Samples/ContactsSample/Resources/Layout/list_item.xml
new file mode 100644
index 0000000..64c8f13
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/Resources/Layout/list_item.xml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/MonoDroid/Samples/ContactsSample/Resources/Resource.Designer.cs b/MonoDroid/Samples/ContactsSample/Resources/Resource.Designer.cs
new file mode 100644
index 0000000..256b860
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/Resources/Resource.Designer.cs
@@ -0,0 +1,118 @@
+#pragma warning disable 1591
+// ------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Mono Runtime Version: 4.0.30319.17020
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+// ------------------------------------------------------------------------------
+
+[assembly: Android.Runtime.ResourceDesignerAttribute("ContactsSample.Resource", IsApplication=true)]
+
+namespace ContactsSample
+{
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+ public partial class Resource
+ {
+
+ static Resource()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ public static void UpdateIdValues()
+ {
+ }
+
+ public partial class Attribute
+ {
+
+ static Attribute()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Attribute()
+ {
+ }
+ }
+
+ public partial class Drawable
+ {
+
+ // aapt resource value: 0x7f020000
+ public const int Icon = 2130837504;
+
+ static Drawable()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Drawable()
+ {
+ }
+ }
+
+ public partial class Id
+ {
+
+ // aapt resource value: 0x7f050000
+ public const int full_name = 2131034112;
+
+ // aapt resource value: 0x7f050001
+ public const int mobile_phone = 2131034113;
+
+ static Id()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Id()
+ {
+ }
+ }
+
+ public partial class Layout
+ {
+
+ // aapt resource value: 0x7f030000
+ public const int contact_view = 2130903040;
+
+ // aapt resource value: 0x7f030001
+ public const int list_item = 2130903041;
+
+ static Layout()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Layout()
+ {
+ }
+ }
+
+ public partial class String
+ {
+
+ // aapt resource value: 0x7f040001
+ public const int ApplicationName = 2130968577;
+
+ // aapt resource value: 0x7f040000
+ public const int Hello = 2130968576;
+
+ static String()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private String()
+ {
+ }
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/MonoDroid/Samples/ContactsSample/Resources/Values/Strings.xml b/MonoDroid/Samples/ContactsSample/Resources/Values/Strings.xml
new file mode 100644
index 0000000..b231544
--- /dev/null
+++ b/MonoDroid/Samples/ContactsSample/Resources/Values/Strings.xml
@@ -0,0 +1,5 @@
+
+
+ Hello World, Click Me!
+ ContactsSample
+
diff --git a/MonoDroid/Samples/GeolocationSample/Assets/AboutAssets.txt b/MonoDroid/Samples/GeolocationSample/Assets/AboutAssets.txt
new file mode 100644
index 0000000..ee39886
--- /dev/null
+++ b/MonoDroid/Samples/GeolocationSample/Assets/AboutAssets.txt
@@ -0,0 +1,19 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories) and given a Build Action of "AndroidAsset".
+
+These files will be deployed with you package and will be accessible using Android's
+AssetManager, like this:
+
+public class ReadAsset : Activity
+{
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ InputStream input = Assets.Open ("my_asset.txt");
+ }
+}
+
+Additionally, some Android functions will automatically load asset files:
+
+Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
\ No newline at end of file
diff --git a/MonoDroid/Samples/GeolocationSample/Geolocation Sample.csproj b/MonoDroid/Samples/GeolocationSample/Geolocation Sample.csproj
new file mode 100644
index 0000000..074f57b
--- /dev/null
+++ b/MonoDroid/Samples/GeolocationSample/Geolocation Sample.csproj
@@ -0,0 +1,76 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ GeolocationSample
+ Resources
+ Assets
+ Resource
+ True
+ Resources\Resource.designer.cs
+ GeolocationSample
+ Properties\AndroidManifest.xml
+ False
+ armeabi
+
+
+ v2.3
+
+
+ True
+ full
+ False
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ None
+ True
+ armeabi;armeabi-v7a;x86
+
+
+ none
+ False
+ bin\Release
+ prompt
+ 4
+ False
+ False
+ armeabi;armeabi-v7a;x86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {32DFF77E-AE38-48D6-B067-CF555798EA32}
+ Xamarin.Mobile.Android
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Samples/GeolocationSample/GeolocationSample.sln b/MonoDroid/Samples/GeolocationSample/GeolocationSample.sln
new file mode 100644
index 0000000..190dd39
--- /dev/null
+++ b/MonoDroid/Samples/GeolocationSample/GeolocationSample.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeolocationSample", "GeolocationSample.csproj", "{82254F3E-647E-4F4A-AA4F-008A614C4B02}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = GeolocationSample.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/MonoDroid/Samples/GeolocationSample/MainActivity.cs b/MonoDroid/Samples/GeolocationSample/MainActivity.cs
new file mode 100644
index 0000000..469e07d
--- /dev/null
+++ b/MonoDroid/Samples/GeolocationSample/MainActivity.cs
@@ -0,0 +1,140 @@
+using System;
+using Android.App;
+using Android.Widget;
+using Android.OS;
+using System.Threading;
+using Xamarin.Geolocation;
+
+namespace GeolocationSample
+{
+ [Activity (Label = "GeolocationSample", MainLauncher = true)]
+ public class MainActivity : Activity
+ {
+ private Button toggleListenButton, cancelPositionButton;
+
+ private TextView positionStatus, positionLatitude, positionLongitude, positionAccuracy,
+ listenStatus, listenLatitude, listenLongitude, listenAccuracy;
+
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+
+ // Set our view from the "main" layout resource
+ SetContentView (Resource.Layout.Main);
+
+ FindViewById (Resource.Id.getPositionButton)
+ .Click += OnGetPosition;
+
+ this.cancelPositionButton = FindViewById (Resource.Id.cancelPositionButton);
+ this.cancelPositionButton.Click += OnCancelPosition;
+
+ this.toggleListenButton = FindViewById (Resource.Id.toggleListeningButton);
+ this.toggleListenButton.Click += OnToggleListening;
+
+ this.positionStatus = FindViewById (Resource.Id.status);
+ this.positionAccuracy = FindViewById (Resource.Id.pAccuracy);
+ this.positionLatitude = FindViewById (Resource.Id.pLatitude);
+ this.positionLongitude = FindViewById (Resource.Id.pLongitude);
+
+ this.listenStatus = FindViewById (Resource.Id.listenStatus);
+ this.listenAccuracy = FindViewById (Resource.Id.lAccuracy);
+ this.listenLatitude = FindViewById (Resource.Id.lLatitude);
+ this.listenLongitude = FindViewById (Resource.Id.lLongitude);
+ }
+
+ private Geolocator geolocator;
+ private CancellationTokenSource cancelSource;
+
+ private void Setup()
+ {
+ if (this.geolocator != null)
+ return;
+
+ this.geolocator = new Geolocator (this) { DesiredAccuracy = 50 };
+ this.geolocator.PositionError += OnListeningError;
+ this.geolocator.PositionChanged += OnPositionChanged;
+ }
+
+ private void OnGetPosition (object sender, EventArgs e)
+ {
+ Setup();
+
+ if (!this.geolocator.IsGeolocationAvailable || !this.geolocator.IsGeolocationEnabled)
+ {
+ Toast.MakeText (this, "Geolocation is unavailable", ToastLength.Long).Show();
+ return;
+ }
+
+ this.cancelSource = new CancellationTokenSource();
+
+ this.positionStatus.Text = String.Empty;
+ this.positionAccuracy.Text = String.Empty;
+ this.positionLatitude.Text = String.Empty;
+ this.positionLongitude.Text = String.Empty;
+
+ this.geolocator.GetPositionAsync (timeout: 10000, cancelToken: this.cancelSource.Token)
+ .ContinueWith (t => RunOnUiThread (() =>
+ {
+ if (t.IsFaulted)
+ this.positionStatus.Text = ((GeolocationException)t.Exception.InnerException).Error.ToString();
+ else if (t.IsCanceled)
+ this.positionStatus.Text = "Canceled";
+ else
+ {
+ this.positionStatus.Text = t.Result.Timestamp.ToString("G");
+ this.positionAccuracy.Text = t.Result.Accuracy + "m";
+ this.positionLatitude.Text = "La: " + t.Result.Latitude.ToString("N4");
+ this.positionLongitude.Text = "Lo: " + t.Result.Longitude.ToString("N4");
+ }
+ }));
+ }
+
+ private void OnCancelPosition (object sender, EventArgs e)
+ {
+ CancellationTokenSource cancel = this.cancelSource;
+ if (cancel != null)
+ cancel.Cancel();
+ }
+
+ private void OnToggleListening (object sender, EventArgs e)
+ {
+ Setup();
+
+ if (!this.geolocator.IsListening)
+ {
+ if (!this.geolocator.IsGeolocationAvailable || !this.geolocator.IsGeolocationEnabled)
+ {
+ Toast.MakeText (this, "Geolocation is unavailable", ToastLength.Long).Show();
+ return;
+ }
+
+ this.toggleListenButton.SetText (Resource.String.stopListening);
+ this.geolocator.StartListening (minTime: 30000, minDistance: 0);
+ }
+ else
+ {
+ this.toggleListenButton.SetText (Resource.String.startListening);
+ this.geolocator.StopListening();
+ }
+ }
+
+ private void OnListeningError (object sender, PositionErrorEventArgs e)
+ {
+ RunOnUiThread (() => {
+ this.listenStatus.Text = e.Error.ToString();
+ });
+ }
+
+ private void OnPositionChanged (object sender, PositionEventArgs e)
+ {
+ RunOnUiThread (() => {
+ this.listenStatus.Text = e.Position.Timestamp.ToString("G");
+ this.listenAccuracy.Text = e.Position.Accuracy + "m";
+ this.listenLatitude.Text = "La: " + e.Position.Latitude.ToString("N4");
+ this.listenLongitude.Text = "Lo: " + e.Position.Longitude.ToString("N4");
+ });
+ }
+ }
+}
+
+
diff --git a/MonoDroid/MonoMobile.Example/Properties/AndroidManifest.xml b/MonoDroid/Samples/GeolocationSample/Properties/AndroidManifest.xml
similarity index 51%
rename from MonoDroid/MonoMobile.Example/Properties/AndroidManifest.xml
rename to MonoDroid/Samples/GeolocationSample/Properties/AndroidManifest.xml
index da4a1ee..72451d5 100644
--- a/MonoDroid/MonoMobile.Example/Properties/AndroidManifest.xml
+++ b/MonoDroid/Samples/GeolocationSample/Properties/AndroidManifest.xml
@@ -1,9 +1,8 @@

-
-
+
+
-
-
+
-
+
\ No newline at end of file
diff --git a/MonoDroid/MonoMobile.Example/Properties/AssemblyInfo.cs b/MonoDroid/Samples/GeolocationSample/Properties/AssemblyInfo.cs
similarity index 83%
rename from MonoDroid/MonoMobile.Example/Properties/AssemblyInfo.cs
rename to MonoDroid/Samples/GeolocationSample/Properties/AssemblyInfo.cs
index f5b6893..07ef0ed 100644
--- a/MonoDroid/MonoMobile.Example/Properties/AssemblyInfo.cs
+++ b/MonoDroid/Samples/GeolocationSample/Properties/AssemblyInfo.cs
@@ -1,15 +1,16 @@
using System.Reflection;
using System.Runtime.CompilerServices;
+using Android.App;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
-[assembly: AssemblyTitle("MonoMobile.Example")]
+[assembly: AssemblyTitle("GeolocationSample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
+[assembly: AssemblyCompany("Xamarin Inc.")]
[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("")]
+[assembly: AssemblyCopyright("Copyright © 2011-2012 Xamarin Inc.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/MonoDroid/Samples/GeolocationSample/Resources/AboutResources.txt b/MonoDroid/Samples/GeolocationSample/Resources/AboutResources.txt
new file mode 100644
index 0000000..10f52d4
--- /dev/null
+++ b/MonoDroid/Samples/GeolocationSample/Resources/AboutResources.txt
@@ -0,0 +1,44 @@
+Images, layout descriptions, binary blobs and string dictionaries can be included
+in your application as resource files. Various Android APIs are designed to
+operate on the resource IDs instead of dealing with images, strings or binary blobs
+directly.
+
+For example, a sample Android app that contains a user interface layout (main.axml),
+an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
+would keep its resources in the "Resources" directory of the application:
+
+Resources/
+ drawable/
+ icon.png
+
+ layout/
+ main.axml
+
+ values/
+ strings.xml
+
+In order to get the build system to recognize Android resources, set the build action to
+"AndroidResource". The native Android APIs do not operate directly with filenames, but
+instead operate on resource IDs. When you compile an Android application that uses resources,
+the build system will package the resources for distribution and generate a class called "R"
+(this is an Android convention) that contains the tokens for each one of the resources
+included. For example, for the above Resources layout, this is what the R class would expose:
+
+public class R {
+ public class drawable {
+ public const int icon = 0x123;
+ }
+
+ public class layout {
+ public const int main = 0x456;
+ }
+
+ public class strings {
+ public const int first_string = 0xabc;
+ public const int second_string = 0xbcd;
+ }
+}
+
+You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
+to reference the layout/main.axml file, or R.strings.first_string to reference the first
+string in the dictionary file values/strings.xml.
diff --git a/MonoDroid/Samples/GeolocationSample/Resources/Resource.designer.cs b/MonoDroid/Samples/GeolocationSample/Resources/Resource.designer.cs
new file mode 100644
index 0000000..74d9603
--- /dev/null
+++ b/MonoDroid/Samples/GeolocationSample/Resources/Resource.designer.cs
@@ -0,0 +1,151 @@
+#pragma warning disable 1591
+// ------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Mono Runtime Version: 4.0.30319.17020
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+// ------------------------------------------------------------------------------
+
+[assembly: Android.Runtime.ResourceDesignerAttribute("GeolocationSample.Resource", IsApplication=true)]
+
+namespace GeolocationSample
+{
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+ public partial class Resource
+ {
+
+ static Resource()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ public static void UpdateIdValues()
+ {
+ }
+
+ public partial class Attribute
+ {
+
+ static Attribute()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Attribute()
+ {
+ }
+ }
+
+ public partial class Drawable
+ {
+
+ // aapt resource value: 0x7f020000
+ public const int Icon = 2130837504;
+
+ static Drawable()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Drawable()
+ {
+ }
+ }
+
+ public partial class Id
+ {
+
+ // aapt resource value: 0x7f050001
+ public const int cancelPositionButton = 2131034113;
+
+ // aapt resource value: 0x7f050000
+ public const int getPositionButton = 2131034112;
+
+ // aapt resource value: 0x7f050008
+ public const int lAccuracy = 2131034120;
+
+ // aapt resource value: 0x7f05000a
+ public const int lLatitude = 2131034122;
+
+ // aapt resource value: 0x7f050009
+ public const int lLongitude = 2131034121;
+
+ // aapt resource value: 0x7f050007
+ public const int listenStatus = 2131034119;
+
+ // aapt resource value: 0x7f050003
+ public const int pAccuracy = 2131034115;
+
+ // aapt resource value: 0x7f050005
+ public const int pLatitude = 2131034117;
+
+ // aapt resource value: 0x7f050004
+ public const int pLongitude = 2131034116;
+
+ // aapt resource value: 0x7f050002
+ public const int status = 2131034114;
+
+ // aapt resource value: 0x7f050006
+ public const int toggleListeningButton = 2131034118;
+
+ static Id()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Id()
+ {
+ }
+ }
+
+ public partial class Layout
+ {
+
+ // aapt resource value: 0x7f030000
+ public const int Main = 2130903040;
+
+ static Layout()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Layout()
+ {
+ }
+ }
+
+ public partial class String
+ {
+
+ // aapt resource value: 0x7f040004
+ public const int app_name = 2130968580;
+
+ // aapt resource value: 0x7f040001
+ public const int cancelPosition = 2130968577;
+
+ // aapt resource value: 0x7f040000
+ public const int getPosition = 2130968576;
+
+ // aapt resource value: 0x7f040002
+ public const int startListening = 2130968578;
+
+ // aapt resource value: 0x7f040003
+ public const int stopListening = 2130968579;
+
+ static String()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private String()
+ {
+ }
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/MonoDroid/MonoMobile.Example/Resources/Drawable-hdpi/Icon.png b/MonoDroid/Samples/GeolocationSample/Resources/drawable/Icon.png
similarity index 100%
rename from MonoDroid/MonoMobile.Example/Resources/Drawable-hdpi/Icon.png
rename to MonoDroid/Samples/GeolocationSample/Resources/drawable/Icon.png
diff --git a/MonoDroid/Samples/GeolocationSample/Resources/layout/Main.axml b/MonoDroid/Samples/GeolocationSample/Resources/layout/Main.axml
new file mode 100644
index 0000000..7b5658e
--- /dev/null
+++ b/MonoDroid/Samples/GeolocationSample/Resources/layout/Main.axml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Samples/GeolocationSample/Resources/values/Strings.xml b/MonoDroid/Samples/GeolocationSample/Resources/values/Strings.xml
new file mode 100644
index 0000000..59895d2
--- /dev/null
+++ b/MonoDroid/Samples/GeolocationSample/Resources/values/Strings.xml
@@ -0,0 +1,8 @@
+
+
+ Get position
+ Cancel position
+ Start listening
+ Stop listening
+ GeolocationSample
+
diff --git a/MonoDroid/Samples/MediaPickerSample/ImageActivity.cs b/MonoDroid/Samples/MediaPickerSample/ImageActivity.cs
new file mode 100644
index 0000000..fcc6415
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/ImageActivity.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Threading.Tasks;
+using Android.App;
+using Android.Graphics;
+using Android.OS;
+using Android.Views;
+using Android.Widget;
+
+namespace MediaPickerSample
+{
+ [Activity]
+ public class ImageActivity
+ : Activity
+ {
+ private string path;
+ private ImageView image;
+ protected override void OnCreate (Bundle savedInstanceState)
+ {
+ base.OnCreate (savedInstanceState);
+ this.image = new ImageView (this);
+ this.image.SetScaleType (ImageView.ScaleType.CenterInside);
+ SetContentView (this.image, new ViewGroup.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent));
+
+ this.path = (savedInstanceState ?? Intent.Extras).GetString ("path");
+ Title = System.IO.Path.GetFileName (this.path);
+
+ Cleanup();
+ DecodeBitmapAsync (path, 400, 400).ContinueWith (t => {
+ this.image.SetImageBitmap (this.bitmap = t.Result);
+ }, TaskScheduler.FromCurrentSynchronizationContext());
+ }
+
+ protected override void OnSaveInstanceState (Bundle outState)
+ {
+ outState.PutString ("path", this.path);
+ base.OnSaveInstanceState (outState);
+ }
+
+ private static Task DecodeBitmapAsync (string path, int desiredWidth, int desiredHeight)
+ {
+ return Task.Factory.StartNew (() => {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.InJustDecodeBounds = true;
+ BitmapFactory.DecodeFile (path, options);
+
+ int height = options.OutHeight;
+ int width = options.OutWidth;
+
+ int sampleSize = 1;
+ if (height > desiredHeight || width > desiredWidth) {
+ int heightRatio = (int)Math.Round ((float)height / (float)desiredHeight);
+ int widthRatio = (int)Math.Round ((float)width / (float)desiredWidth);
+ sampleSize = Math.Min (heightRatio, widthRatio);
+ }
+
+ options = new BitmapFactory.Options();
+ options.InSampleSize = sampleSize;
+
+ return BitmapFactory.DecodeFile (path, options);
+ });
+ }
+
+ private Bitmap bitmap;
+ private void Cleanup()
+ {
+ if (this.bitmap == null)
+ return;
+
+ this.image.SetImageBitmap (null);
+ this.bitmap.Dispose();
+ this.bitmap = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Samples/MediaPickerSample/MainActivity.cs b/MonoDroid/Samples/MediaPickerSample/MainActivity.cs
new file mode 100644
index 0000000..b4f2a8f
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/MainActivity.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Threading.Tasks;
+using Android.App;
+using Android.Content;
+using Android.Content.PM;
+using Android.Widget;
+using Android.OS;
+using Xamarin.Media;
+
+namespace MediaPickerSample
+{
+ [Activity (Label = "MediaPickerSample", MainLauncher = true, Icon = "@drawable/icon", ConfigurationChanges = ConfigChanges.Orientation)]
+ public class MainActivity : Activity
+ {
+ protected override void OnCreate (Bundle bundle)
+ {
+ base.OnCreate (bundle);
+ SetContentView (Resource.Layout.Main);
+
+ Button videoButton = FindViewById (Resource.Id.takeVideoButton);
+ videoButton.Click += delegate {
+ // MediaPicker is the class used to invoke the
+ // camera and gallery picker for selecting and
+ // taking photos and videos
+ var picker = new MediaPicker (this);
+
+ // We can check to make sure the device has a camera
+ // and supports dealing with video.
+ if (!picker.IsCameraAvailable || !picker.VideosSupported) {
+ ShowUnsupported();
+ return;
+ }
+
+ // The GetTakeVideoUI method returns an Intent to start
+ // the native camera app to record a video.
+ Intent intent = picker.GetTakeVideoUI (new StoreVideoOptions {
+ Name = "MyVideo",
+ Directory = "MyVideos",
+ DesiredLength = TimeSpan.FromSeconds (10)
+ });
+
+ StartActivityForResult (intent, 1);
+ };
+
+ Button photoButton = FindViewById (Resource.Id.takePhotoButton);
+ photoButton.Click += delegate {
+ var picker = new MediaPicker (this);
+
+ if (!picker.IsCameraAvailable || !picker.PhotosSupported) {
+ ShowUnsupported();
+ return;
+ }
+
+ Intent intent = picker.GetTakePhotoUI (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+ });
+
+ StartActivityForResult (intent, 2);
+ };
+
+ Button pickVideoButton = FindViewById (Resource.Id.pickVideoButton);
+ pickVideoButton.Click += delegate {
+ var picker = new MediaPicker (this);
+
+ if (!picker.VideosSupported) {
+ ShowUnsupported();
+ return;
+ }
+
+ // The GetPickVideoUI() method returns an Intent to start
+ // the native gallery app to select a video.
+ Intent intent = picker.GetPickVideoUI();
+ StartActivityForResult (intent, 1);
+ };
+
+ Button pickPhotoButton = FindViewById (Resource.Id.pickPhotoButton);
+ pickPhotoButton.Click += delegate {
+ var picker = new MediaPicker (this);
+
+ if (!picker.PhotosSupported) {
+ ShowUnsupported();
+ return;
+ }
+
+ Intent intent = picker.GetPickPhotoUI();
+ StartActivityForResult (intent, 2);
+ };
+ }
+
+ protected override void OnActivityResult (int requestCode, Result resultCode, Intent data)
+ {
+ // User canceled
+ if (resultCode == Result.Canceled)
+ return;
+
+ data.GetMediaFileExtraAsync (this).ContinueWith (t => {
+ if (requestCode == 1) { // Video request
+ ShowVideo (t.Result.Path);
+ } else if (requestCode == 2) { // Image request
+ ShowImage (t.Result.Path);
+ }
+ }, TaskScheduler.FromCurrentSynchronizationContext());
+ }
+
+ private void ShowVideo (string path)
+ {
+ Intent videoIntent = new Intent (this, typeof (VideoActivity));
+ videoIntent.PutExtra ("path", path);
+ StartActivity (videoIntent);
+ }
+
+ private void ShowImage (string path)
+ {
+ Intent imageIntent = new Intent (this, typeof (ImageActivity));
+ imageIntent.PutExtra ("path", path);
+ StartActivity (imageIntent);
+ }
+
+ private Toast unsupportedToast;
+ private void ShowUnsupported()
+ {
+ if (this.unsupportedToast != null) {
+ this.unsupportedToast.Cancel();
+ this.unsupportedToast.Dispose();
+ }
+
+ this.unsupportedToast = Toast.MakeText (this, "Your device does not support this feature", ToastLength.Long);
+ this.unsupportedToast.Show();
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Samples/MediaPickerSample/MediaPicker Sample.csproj b/MonoDroid/Samples/MediaPickerSample/MediaPicker Sample.csproj
new file mode 100644
index 0000000..54bcbd2
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/MediaPicker Sample.csproj
@@ -0,0 +1,96 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Properties
+ MediaPickerSample
+ MediaPickerSample
+ 512
+ true
+ Resources\Resource.Designer.cs
+ Off
+ Properties\AndroidManifest.xml
+ False
+ armeabi
+
+
+ v2.3
+
+
+ True
+ full
+ False
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ None
+ True
+ armeabi;armeabi-v7a;x86
+
+
+ pdbonly
+ True
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ False
+ armeabi;armeabi-v7a;x86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {32DFF77E-AE38-48D6-B067-CF555798EA32}
+ Xamarin.Mobile.Android
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Samples/MediaPickerSample/MediaPickerSample.sln b/MonoDroid/Samples/MediaPickerSample/MediaPickerSample.sln
new file mode 100644
index 0000000..8086950
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/MediaPickerSample.sln
@@ -0,0 +1,23 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaPickerSample", "MediaPickerSample.csproj", "{35CF5239-F77C-40B0-B3A7-14AF989A19C8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = GeolocationSample.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/MonoDroid/Samples/MediaPickerSample/Properties/AndroidManifest.xml b/MonoDroid/Samples/MediaPickerSample/Properties/AndroidManifest.xml
new file mode 100644
index 0000000..dd0203b
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/Properties/AndroidManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Samples/MediaPickerSample/Properties/AssemblyInfo.cs b/MonoDroid/Samples/MediaPickerSample/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..3bf7f2a
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/Properties/AssemblyInfo.cs
@@ -0,0 +1,41 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Android.App;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("MediaPickerSample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Xamarin Inc.")]
+[assembly: AssemblyProduct("MediaPickerSample")]
+[assembly: AssemblyCopyright("Copyright © 2011-2012 Xamarin Inc.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a557ce8c-9dbe-4b93-8fc4-95ffc126cf14")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+
+// Add some common permissions, these can be removed if not needed
+[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
+[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
diff --git a/MonoDroid/MonoMobile.Example/Resources/AboutResources.txt b/MonoDroid/Samples/MediaPickerSample/Resources/AboutResources.txt
similarity index 63%
rename from MonoDroid/MonoMobile.Example/Resources/AboutResources.txt
rename to MonoDroid/Samples/MediaPickerSample/Resources/AboutResources.txt
index 1e08c0a..b0fc999 100644
--- a/MonoDroid/MonoMobile.Example/Resources/AboutResources.txt
+++ b/MonoDroid/Samples/MediaPickerSample/Resources/AboutResources.txt
@@ -3,32 +3,26 @@ in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
-For example, a sample Android app that contains a user interface layout (Main.axml),
-an internationalization string table (Strings.xml) and some icons (Drawable-XXX/Icon.png)
+For example, a sample Android app that contains a user interface layout (Main.xml),
+an internationalization string table (Strings.xml) and some icons (drawable/Icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
- Drawable-hdpi/
+ Drawable/
Icon.png
- Drawable-ldpi/
- Icon.png
-
- Drawable-mdpi/
- icon.png
-
Layout/
Main.axml
Values/
Strings.xml
-In order to get the build system to recognize Android resources, set the build action to
-"AndroidResource". The native Android APIs do not operate directly with filenames, but
+In order to get the build system to recognize Android resources, the build action should be set
+to "AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
-the build system will package the resources for distribution and generate a class called "Resource"
-(this is an Android convention) that contains the tokens for each one of the resources
-included. For example, for the above Resources layout, this is what the Resource class would expose:
+the build system will package the resources for distribution and generate a class called
+"Resource" that contains the tokens for each one of the resources included. For example,
+for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class Drawable {
@@ -45,6 +39,6 @@ public class Resource {
}
}
-You would then use Resource.Drawable.Icon to reference the Drawable/Icon.png file, or Resource.Layout.Main
-to reference the Layout/Main.axml file, or Resource.String.FirstString to reference the first
-string in the dictionary file Values/String.xml.
+You would then use Resource.Drawable.Icon to reference the Drawable/Icon.png file, or
+Resource.Layout.Main to reference the Layout/Main.axml file, or Resource.String.FirstString
+to reference the first string in the dictionary file Values/Strings.xml.
\ No newline at end of file
diff --git a/MonoDroid/Samples/MediaPickerSample/Resources/Drawable/Icon.png b/MonoDroid/Samples/MediaPickerSample/Resources/Drawable/Icon.png
new file mode 100644
index 0000000..8074c4c
Binary files /dev/null and b/MonoDroid/Samples/MediaPickerSample/Resources/Drawable/Icon.png differ
diff --git a/MonoDroid/Samples/MediaPickerSample/Resources/Layout/Main.axml b/MonoDroid/Samples/MediaPickerSample/Resources/Layout/Main.axml
new file mode 100644
index 0000000..b9da731
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/Resources/Layout/Main.axml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Samples/MediaPickerSample/Resources/Resource.Designer.cs b/MonoDroid/Samples/MediaPickerSample/Resources/Resource.Designer.cs
new file mode 100644
index 0000000..76b03ac
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/Resources/Resource.Designer.cs
@@ -0,0 +1,121 @@
+#pragma warning disable 1591
+// ------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Mono Runtime Version: 4.0.30319.17020
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+// ------------------------------------------------------------------------------
+
+[assembly: Android.Runtime.ResourceDesignerAttribute("MediaPickerSample.Resource", IsApplication=true)]
+
+namespace MediaPickerSample
+{
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+ public partial class Resource
+ {
+
+ static Resource()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ public static void UpdateIdValues()
+ {
+ }
+
+ public partial class Attribute
+ {
+
+ static Attribute()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Attribute()
+ {
+ }
+ }
+
+ public partial class Drawable
+ {
+
+ // aapt resource value: 0x7f020000
+ public const int Icon = 2130837504;
+
+ static Drawable()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Drawable()
+ {
+ }
+ }
+
+ public partial class Id
+ {
+
+ // aapt resource value: 0x7f050002
+ public const int pickPhotoButton = 2131034114;
+
+ // aapt resource value: 0x7f050003
+ public const int pickVideoButton = 2131034115;
+
+ // aapt resource value: 0x7f050000
+ public const int takePhotoButton = 2131034112;
+
+ // aapt resource value: 0x7f050001
+ public const int takeVideoButton = 2131034113;
+
+ static Id()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Id()
+ {
+ }
+ }
+
+ public partial class Layout
+ {
+
+ // aapt resource value: 0x7f030000
+ public const int Main = 2130903040;
+
+ static Layout()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Layout()
+ {
+ }
+ }
+
+ public partial class String
+ {
+
+ // aapt resource value: 0x7f040001
+ public const int ApplicationName = 2130968577;
+
+ // aapt resource value: 0x7f040000
+ public const int Hello = 2130968576;
+
+ static String()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private String()
+ {
+ }
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/MonoDroid/Samples/MediaPickerSample/Resources/Values/Strings.xml b/MonoDroid/Samples/MediaPickerSample/Resources/Values/Strings.xml
new file mode 100644
index 0000000..f58099a
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/Resources/Values/Strings.xml
@@ -0,0 +1,5 @@
+
+
+ Hello World, Click Me!
+ MediaPickerSample
+
diff --git a/MonoDroid/Samples/MediaPickerSample/VideoActivity.cs b/MonoDroid/Samples/MediaPickerSample/VideoActivity.cs
new file mode 100644
index 0000000..e5b22ad
--- /dev/null
+++ b/MonoDroid/Samples/MediaPickerSample/VideoActivity.cs
@@ -0,0 +1,34 @@
+using Android.App;
+using Android.OS;
+using Android.Views;
+using Android.Widget;
+
+namespace MediaPickerSample
+{
+ [Activity]
+ public class VideoActivity
+ : Activity
+ {
+ private VideoView video;
+ private string path;
+
+ protected override void OnCreate (Bundle savedInstanceState)
+ {
+ base.OnCreate (savedInstanceState);
+ this.video = new VideoView (this);
+ SetContentView (this.video, new ViewGroup.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent));
+
+ this.path = (savedInstanceState ?? Intent.Extras).GetString ("path");
+ Title = System.IO.Path.GetFileName (this.path);
+
+ this.video.SetVideoPath (this.path);
+ this.video.Start();
+ }
+
+ protected override void OnSaveInstanceState (Bundle outState)
+ {
+ outState.PutString ("path", this.path);
+ base.OnSaveInstanceState (outState);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Samples/Xamarin.Mobile.Android.Samples.sln b/MonoDroid/Samples/Xamarin.Mobile.Android.Samples.sln
new file mode 100644
index 0000000..39fc95d
--- /dev/null
+++ b/MonoDroid/Samples/Xamarin.Mobile.Android.Samples.sln
@@ -0,0 +1,41 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contacts Sample", "ContactsSample\Contacts Sample.csproj", "{32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geolocation Sample", "GeolocationSample\Geolocation Sample.csproj", "{82254F3E-647E-4F4A-AA4F-008A614C4B02}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaPicker Sample", "MediaPickerSample\MediaPicker Sample.csproj", "{35CF5239-F77C-40B0-B3A7-14AF989A19C8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Release|Any CPU.Build.0 = Release|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = ContactsSample\Contacts Sample.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/MonoDroid/Xamarin.Mobile Android.sln b/MonoDroid/Xamarin.Mobile Android.sln
new file mode 100644
index 0000000..55ebe5b
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile Android.sln
@@ -0,0 +1,54 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{D66A3439-B7B0-4641-9B11-BCD00A611EE5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contacts Sample", "Samples\ContactsSample\Contacts Sample.csproj", "{32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geolocation Sample", "Samples\GeolocationSample\Geolocation Sample.csproj", "{82254F3E-647E-4F4A-AA4F-008A614C4B02}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaPicker Sample", "Samples\MediaPickerSample\MediaPicker Sample.csproj", "{35CF5239-F77C-40B0-B3A7-14AF989A19C8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Mobile.Android", "Xamarin.Mobile\Xamarin.Mobile.Android.csproj", "{32DFF77E-AE38-48D6-B067-CF555798EA32}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {32DFF77E-AE38-48D6-B067-CF555798EA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32DFF77E-AE38-48D6-B067-CF555798EA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32DFF77E-AE38-48D6-B067-CF555798EA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32DFF77E-AE38-48D6-B067-CF555798EA32}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {32E5FA7A-4754-49C6-BA09-2E262BEDC4CE} = {D66A3439-B7B0-4641-9B11-BCD00A611EE5}
+ {82254F3E-647E-4F4A-AA4F-008A614C4B02} = {D66A3439-B7B0-4641-9B11-BCD00A611EE5}
+ {35CF5239-F77C-40B0-B3A7-14AF989A19C8} = {D66A3439-B7B0-4641-9B11-BCD00A611EE5}
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = Xamarin.Mobile\Xamarin.Mobile.csproj
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/MonoDroid/Xamarin.Mobile.Android.Tests/MainActivity.cs b/MonoDroid/Xamarin.Mobile.Android.Tests/MainActivity.cs
new file mode 100644
index 0000000..0561d6e
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile.Android.Tests/MainActivity.cs
@@ -0,0 +1,39 @@
+//
+// Copyright 2014, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System.Reflection;
+using Android.App;
+using Android.OS;
+using Xamarin.Android.NUnitLite;
+
+namespace Xamarin.Mobile.Tests
+{
+ [Activity (Label = "Xamarin.Mobile.Tests", MainLauncher = true)]
+ public class MainActivity : TestSuiteActivity
+ {
+ protected override void OnCreate (Bundle bundle)
+ {
+ // tests can be inside the main assembly
+ AddTest (Assembly.GetExecutingAssembly ());
+ // or in any reference assemblies
+ // AddTest (typeof (Your.Library.TestClass).Assembly);
+
+ // Once you called base.OnCreate(), you cannot add more assemblies.
+ base.OnCreate (bundle);
+ }
+ }
+}
+
diff --git a/MonoDroid/Xamarin.Mobile.Android.Tests/MockQueryProvider.cs b/MonoDroid/Xamarin.Mobile.Android.Tests/MockQueryProvider.cs
new file mode 100644
index 0000000..516c8b9
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile.Android.Tests/MockQueryProvider.cs
@@ -0,0 +1,92 @@
+//
+// Copyright 2014, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Xamarin.Mobile.Tests
+{
+ class MockQueryProvider
+ : IQueryProvider
+ {
+ public Expression LastExpression
+ {
+ get;
+ private set;
+ }
+
+ public IQueryable CreateQuery (Expression expression)
+ {
+ throw new NotImplementedException();
+ }
+
+ public object Execute (Expression expression)
+ {
+ LastExpression = expression;
+ return null;
+ }
+
+ public IQueryable CreateQuery (Expression expression)
+ {
+ return new Query (this, expression);
+ }
+
+ public TResult Execute (Expression expression)
+ {
+ ((IQueryProvider) this).Execute (expression);
+ return default (TResult);
+ }
+ }
+
+ class MockQueryable
+ : IQueryable
+ {
+ public Type ElementType
+ {
+ get { return typeof (T); }
+ }
+
+ public Expression Expression
+ {
+ get { return Expression.Constant (this); }
+ }
+
+ public IQueryProvider Provider
+ {
+ get { return this.provider; }
+ }
+
+ public Expression LastExpression
+ {
+ get { return this.provider.LastExpression; }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return Enumerable.Empty().GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ private readonly MockQueryProvider provider = new MockQueryProvider();
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile.Android.Tests/Properties/AndroidManifest.xml b/MonoDroid/Xamarin.Mobile.Android.Tests/Properties/AndroidManifest.xml
new file mode 100644
index 0000000..d64de73
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile.Android.Tests/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile.Android.Tests/Properties/AssemblyInfo.cs b/MonoDroid/Xamarin.Mobile.Android.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..93fa44d
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile.Android.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,23 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using Android.App;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle ("Xamarin.Mobile.Android.Tests")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("Xamarin Inc.")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("Copyright © 2011-2014 Xamarin Inc.")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion ("1.0.0")]
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/MonoDroid/Xamarin.Mobile.Android.Tests/Resources/Resource.designer.cs b/MonoDroid/Xamarin.Mobile.Android.Tests/Resources/Resource.designer.cs
new file mode 100644
index 0000000..b761996
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile.Android.Tests/Resources/Resource.designer.cs
@@ -0,0 +1,171 @@
+#pragma warning disable 1591
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.34003
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+[assembly: global::Android.Runtime.ResourceDesignerAttribute("Xamarin.Mobile.Tests.Resource", IsApplication=true)]
+
+namespace Xamarin.Mobile.Tests
+{
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+ public partial class Resource
+ {
+
+ static Resource()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ public static void UpdateIdValues()
+ {
+ global::Xamarin.Android.NUnitLite.Resource.Id.OptionHostName = global::Xamarin.Mobile.Tests.Resource.Id.OptionHostName;
+ global::Xamarin.Android.NUnitLite.Resource.Id.OptionPort = global::Xamarin.Mobile.Tests.Resource.Id.OptionPort;
+ global::Xamarin.Android.NUnitLite.Resource.Id.OptionRemoteServer = global::Xamarin.Mobile.Tests.Resource.Id.OptionRemoteServer;
+ global::Xamarin.Android.NUnitLite.Resource.Id.OptionsButton = global::Xamarin.Mobile.Tests.Resource.Id.OptionsButton;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultFullName = global::Xamarin.Mobile.Tests.Resource.Id.ResultFullName;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultMessage = global::Xamarin.Mobile.Tests.Resource.Id.ResultMessage;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultResultState = global::Xamarin.Mobile.Tests.Resource.Id.ResultResultState;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultStackTrace = global::Xamarin.Mobile.Tests.Resource.Id.ResultStackTrace;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultsFailed = global::Xamarin.Mobile.Tests.Resource.Id.ResultsFailed;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultsId = global::Xamarin.Mobile.Tests.Resource.Id.ResultsId;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultsIgnored = global::Xamarin.Mobile.Tests.Resource.Id.ResultsIgnored;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultsInconclusive = global::Xamarin.Mobile.Tests.Resource.Id.ResultsInconclusive;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultsMessage = global::Xamarin.Mobile.Tests.Resource.Id.ResultsMessage;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultsPassed = global::Xamarin.Mobile.Tests.Resource.Id.ResultsPassed;
+ global::Xamarin.Android.NUnitLite.Resource.Id.ResultsResult = global::Xamarin.Mobile.Tests.Resource.Id.ResultsResult;
+ global::Xamarin.Android.NUnitLite.Resource.Id.RunTestsButton = global::Xamarin.Mobile.Tests.Resource.Id.RunTestsButton;
+ global::Xamarin.Android.NUnitLite.Resource.Id.TestSuiteListView = global::Xamarin.Mobile.Tests.Resource.Id.TestSuiteListView;
+ global::Xamarin.Android.NUnitLite.Resource.Layout.options = global::Xamarin.Mobile.Tests.Resource.Layout.options;
+ global::Xamarin.Android.NUnitLite.Resource.Layout.results = global::Xamarin.Mobile.Tests.Resource.Layout.results;
+ global::Xamarin.Android.NUnitLite.Resource.Layout.test_result = global::Xamarin.Mobile.Tests.Resource.Layout.test_result;
+ global::Xamarin.Android.NUnitLite.Resource.Layout.test_suite = global::Xamarin.Mobile.Tests.Resource.Layout.test_suite;
+ }
+
+ public partial class Attribute
+ {
+
+ static Attribute()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Attribute()
+ {
+ }
+ }
+
+ public partial class Drawable
+ {
+
+ // aapt resource value: 0x7f020000
+ public const int Icon = 2130837504;
+
+ static Drawable()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Drawable()
+ {
+ }
+ }
+
+ public partial class Id
+ {
+
+ // aapt resource value: 0x7f040001
+ public const int OptionHostName = 2130968577;
+
+ // aapt resource value: 0x7f040002
+ public const int OptionPort = 2130968578;
+
+ // aapt resource value: 0x7f040000
+ public const int OptionRemoteServer = 2130968576;
+
+ // aapt resource value: 0x7f04000f
+ public const int OptionsButton = 2130968591;
+
+ // aapt resource value: 0x7f04000a
+ public const int ResultFullName = 2130968586;
+
+ // aapt resource value: 0x7f04000c
+ public const int ResultMessage = 2130968588;
+
+ // aapt resource value: 0x7f04000b
+ public const int ResultResultState = 2130968587;
+
+ // aapt resource value: 0x7f04000d
+ public const int ResultStackTrace = 2130968589;
+
+ // aapt resource value: 0x7f040006
+ public const int ResultsFailed = 2130968582;
+
+ // aapt resource value: 0x7f040003
+ public const int ResultsId = 2130968579;
+
+ // aapt resource value: 0x7f040007
+ public const int ResultsIgnored = 2130968583;
+
+ // aapt resource value: 0x7f040008
+ public const int ResultsInconclusive = 2130968584;
+
+ // aapt resource value: 0x7f040009
+ public const int ResultsMessage = 2130968585;
+
+ // aapt resource value: 0x7f040005
+ public const int ResultsPassed = 2130968581;
+
+ // aapt resource value: 0x7f040004
+ public const int ResultsResult = 2130968580;
+
+ // aapt resource value: 0x7f04000e
+ public const int RunTestsButton = 2130968590;
+
+ // aapt resource value: 0x7f040010
+ public const int TestSuiteListView = 2130968592;
+
+ static Id()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Id()
+ {
+ }
+ }
+
+ public partial class Layout
+ {
+
+ // aapt resource value: 0x7f030000
+ public const int options = 2130903040;
+
+ // aapt resource value: 0x7f030001
+ public const int results = 2130903041;
+
+ // aapt resource value: 0x7f030002
+ public const int test_result = 2130903042;
+
+ // aapt resource value: 0x7f030003
+ public const int test_suite = 2130903043;
+
+ static Layout()
+ {
+ global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+ }
+
+ private Layout()
+ {
+ }
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/MonoDroid/MonoMobile.Example/Resources/Drawable-ldpi/Icon.png b/MonoDroid/Xamarin.Mobile.Android.Tests/Resources/drawable/Icon.png
similarity index 100%
rename from MonoDroid/MonoMobile.Example/Resources/Drawable-ldpi/Icon.png
rename to MonoDroid/Xamarin.Mobile.Android.Tests/Resources/drawable/Icon.png
diff --git a/MonoDroid/Xamarin.Mobile.Android.Tests/Tests/ContactTableFinderTests.cs b/MonoDroid/Xamarin.Mobile.Android.Tests/Tests/ContactTableFinderTests.cs
new file mode 100644
index 0000000..4e4a1d4
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile.Android.Tests/Tests/ContactTableFinderTests.cs
@@ -0,0 +1,73 @@
+//
+// Copyright 2014, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Linq.Expressions;
+using Android.Provider;
+using NUnit.Framework;
+using Xamarin.Contacts;
+
+namespace Xamarin.Mobile.Tests.Tests
+{
+ [TestFixture]
+ class ContactTableFinderTests
+ {
+ [Test]
+ public void FindContactSelect()
+ {
+ var finder = new ContactTableFinder { UseRawContacts = false };
+ var result = finder.Find (GetExpression (c => c.DisplayName));
+ Assert.That (result, Is.Not.Null);
+ Assert.That (result.MimeType, Is.Null);
+ Assert.That (result.Table, Is.EqualTo (ContactsContract.Contacts.ContentUri));
+ }
+
+ [Test]
+ public void FindContactWhere()
+ {
+ var finder = new ContactTableFinder { UseRawContacts = false };
+ var result = finder.Find (GetExpression (c => c.DisplayName == "Display Name"));
+ Assert.That (result, Is.Not.Null);
+ Assert.That (result.MimeType, Is.Null);
+ Assert.That (result.Table, Is.EqualTo (ContactsContract.Contacts.ContentUri));
+ }
+
+ [Test]
+ public void FindContactSelectData()
+ {
+ var finder = new ContactTableFinder { UseRawContacts = false };
+ var result = finder.Find (GetExpression (c => c.FirstName));
+ Assert.That (result, Is.Not.Null);
+ Assert.That (result.MimeType, Is.EqualTo (ContactsContract.CommonDataKinds.StructuredName.ContentItemType));
+ Assert.That (result.Table, Is.EqualTo (ContactsContract.Data.ContentUri));
+ }
+
+ [Test]
+ public void FindContactWhereData()
+ {
+ var finder = new ContactTableFinder { UseRawContacts = false };
+ var result = finder.Find (GetExpression (c => c.FirstName == "First"));
+ Assert.That (result, Is.Not.Null);
+ Assert.That (result.MimeType, Is.EqualTo (ContactsContract.CommonDataKinds.StructuredName.ContentItemType));
+ Assert.That (result.Table, Is.EqualTo (ContactsContract.Data.ContentUri));
+ }
+
+ Expression GetExpression (Expression> expr)
+ {
+ return expr;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile.Android.Tests/Tests/ContentQueryTranslatorTests.cs b/MonoDroid/Xamarin.Mobile.Android.Tests/Tests/ContentQueryTranslatorTests.cs
new file mode 100644
index 0000000..e4fd113
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile.Android.Tests/Tests/ContentQueryTranslatorTests.cs
@@ -0,0 +1,455 @@
+//
+// Copyright 2014, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Linq;
+using Android.Provider;
+using NUnit.Framework;
+using Xamarin.Contacts;
+
+namespace Xamarin.Mobile.Tests.Tests
+{
+ [TestFixture]
+ class ContentQueryTranslatorTests
+ {
+ [Test]
+ public void FirstSingleClause()
+ {
+ Queryable.First (c => c.DisplayName == "Display Name");
+
+ AssertSingularWithSingleClause();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (1));
+ }
+
+ [Test]
+ public void FirstOrDefaultSingleClause()
+ {
+ Queryable.FirstOrDefault (c => c.DisplayName == "Display Name");
+
+ AssertSingularWithSingleClause();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (1));
+ }
+
+ [Test]
+ public void SingleOrDefaultSingleClause()
+ {
+ Queryable.SingleOrDefault (c => c.DisplayName == "Display Name");
+
+ AssertSingularWithSingleClause();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (2));
+ }
+
+ [Test]
+ public void SingleSingleClause()
+ {
+ Queryable.Single (c => c.DisplayName == "Display Name");
+
+ AssertSingularWithSingleClause();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (2));
+ }
+
+ [Test]
+ public void WhereSingleClause()
+ {
+ Queryable.Where (c => c.DisplayName == "Display Name").ToArray();
+
+ AssertSingularWithSingleClause();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ }
+
+ [Test]
+ public void CountSingleClause()
+ {
+ Queryable.Count (c => c.DisplayName == "Display Name");
+
+ AssertSingularWithSingleClause();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.True);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ }
+
+ [Test]
+ public void AnySingleClause()
+ {
+ Queryable.Any (c => c.DisplayName == "Display Name");
+
+ AssertSingularWithSingleClause();
+ Assert.That (Translator.IsAny, Is.True);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ }
+
+ public void AssertSingularWithSingleClause()
+ {
+ Translator.Translate (Queryable.LastExpression);
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ Assert.That (Translator.QueryString, Is.EqualTo ("(display_name = ?)"));
+ Assert.That (Translator.Projections, Is.Null.Or.Empty, "Projections were present");
+ Assert.That (Translator.ClauseParameters, Contains.Item ("Display Name"));
+ Assert.That (Translator.ReturnType, Is.Null.Or.EqualTo (typeof (Contact)));
+ Assert.That (Translator.Table, Is.EqualTo (ContactsContract.Contacts.ContentUri));
+ }
+
+ [Test]
+ public void FirstTwoClausesSameTableSameMimetype()
+ {
+ Queryable.First (c => c.FirstName == "Foo" && c.LastName == "Bar");
+
+ AssertSingularWithTwoClausesFromSameTableAndMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (1));
+ }
+
+ [Test]
+ public void FirstOrDefaultTwoClausesSameTableSameMimetype()
+ {
+ Queryable.FirstOrDefault (c => c.FirstName == "Foo" && c.LastName == "Bar");
+
+ AssertSingularWithTwoClausesFromSameTableAndMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (1));
+ }
+
+ [Test]
+ public void SingleTwoClausesSameTableSameMimetype()
+ {
+ Queryable.Single (c => c.FirstName == "Foo" && c.LastName == "Bar");
+
+ AssertSingularWithTwoClausesFromSameTableAndMimeType ();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (2));
+ }
+
+ [Test]
+ public void SingleOrDefaultTwoClausesSameTableSameMimetype()
+ {
+ Queryable.SingleOrDefault (c => c.FirstName == "Foo" && c.LastName == "Bar");
+
+ AssertSingularWithTwoClausesFromSameTableAndMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (2));
+ }
+
+ [Test]
+ public void WhereSingleTwoClausesSameTableSameMimeType()
+ {
+ Queryable.Where (c => c.FirstName == "Foo" && c.LastName == "Bar").ToArray();
+
+ AssertSingularWithTwoClausesFromSameTableAndMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ }
+
+ [Test]
+ public void CountSingleTwoClausesSameTableSameMimeType()
+ {
+ Queryable.Count (c => c.FirstName == "Foo" && c.LastName == "Bar");
+
+ AssertSingularWithTwoClausesFromSameTableAndMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.True);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ }
+
+ [Test]
+ public void AnySingleTwoClausesSameTableSameMimeType()
+ {
+ Queryable.Any (c => c.FirstName == "Foo" && c.LastName == "Bar");
+
+ AssertSingularWithTwoClausesFromSameTableAndMimeType();
+ Assert.That (Translator.IsAny, Is.True);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ }
+
+ public void AssertSingularWithTwoClausesFromSameTableAndMimeType()
+ {
+ Translator.Translate (Queryable.LastExpression);
+
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ Assert.That (Translator.QueryString, Is.EqualTo (
+ String.Format ("(({0} = ?) AND (({1} = ?) AND ({2} = ?)))",
+ ContactsContract.DataColumns.Mimetype,
+ ContactsContract.CommonDataKinds.StructuredName.GivenName,
+ ContactsContract.CommonDataKinds.StructuredName.FamilyName)));
+ Assert.That (Translator.Projections, Is.Null.Or.Empty, "Projections were present");
+ Assert.That (Translator.ClauseParameters[0], Is.EqualTo (ContactsContract.CommonDataKinds.StructuredName.ContentItemType));
+ Assert.That (Translator.ClauseParameters[1], Is.EqualTo ("Foo"));
+ Assert.That (Translator.ClauseParameters[2], Is.EqualTo ("Bar"));
+ Assert.That (Translator.ReturnType, Is.Null.Or.EqualTo (typeof (Contact)));
+ Assert.That (Translator.Table, Is.EqualTo (ContactsContract.Data.ContentUri));
+ Assert.That (Translator.SortString, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void WhereTwoClausesSameTableDifferentMimeType()
+ {
+ Queryable.Where (c => c.FirstName == "Foo" && c.DisplayName == "Foo Bar").ToArray();
+ AssertWhereWithTwoClausesFromSameTableDifferentMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (-1), "Take was not -1");
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ }
+
+ [Test]
+ [Category ("Any"), Category ("TwoClausesSameTableDifferentMimeType")]
+ public void AnyTwoClausesSameTableDifferentMimeType()
+ {
+ Queryable.Any (c => c.FirstName == "Foo" && c.DisplayName == "Foo Bar");
+ AssertWhereWithTwoClausesFromSameTableDifferentMimeType();
+ Assert.That (Translator.IsAny, Is.True);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (-1), "Take was not -1");
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ }
+
+ [Test]
+ [Category ("Count"), Category ("TwoClausesSameTableDifferentMimeType")]
+ public void CountTwoClausesSameTableDifferentMimeType()
+ {
+ Queryable.Count (c => c.FirstName == "Foo" && c.DisplayName == "Foo Bar");
+ AssertWhereWithTwoClausesFromSameTableDifferentMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.True);
+ Assert.That (Translator.Take, Is.EqualTo (-1), "Take was not -1");
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ }
+
+ [Test]
+ public void FirstTwoClausesSameTableDifferentMimeType()
+ {
+ Queryable.First (c => c.FirstName == "Foo" && c.DisplayName == "Foo Bar");
+ AssertWhereWithTwoClausesFromSameTableDifferentMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (1), "Take was not 1");
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ }
+
+ [Test]
+ public void FirstOrDefaultTwoClausesSameTableDifferentMimeType()
+ {
+ Queryable.FirstOrDefault (c => c.FirstName == "Foo" && c.DisplayName == "Foo Bar");
+ AssertWhereWithTwoClausesFromSameTableDifferentMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (1), "Take was not 1");
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ }
+
+ [Test]
+ public void SingleTwoClausesSameTableDifferentMimetype()
+ {
+ Queryable.Single (c => c.FirstName == "Foo" && c.DisplayName == "Foo Bar");
+ AssertWhereWithTwoClausesFromSameTableDifferentMimeType();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (2), "Take was not 2");
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ }
+
+ [Test]
+ public void SingleOrDefaultTwoClausesSameTableDifferentMimetype()
+ {
+ Queryable.SingleOrDefault (c => c.FirstName == "Foo" && c.DisplayName == "Foo Bar");
+ AssertWhereWithTwoClausesFromSameTableDifferentMimeType ();
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (2), "Take was not 2");
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ }
+
+ public void AssertWhereWithTwoClausesFromSameTableDifferentMimeType()
+ {
+ Translator.Translate (Queryable.LastExpression);
+
+ Assert.That (Translator.Skip, Is.EqualTo (-1), "Skip was not -1");
+ Assert.That (Translator.QueryString, Is.EqualTo (
+ String.Format ("(({0} = ?) AND (({1} = ?)))",
+ ContactsContract.DataColumns.Mimetype,
+ ContactsContract.CommonDataKinds.StructuredName.GivenName)));
+ Assert.That (Translator.Projections, Is.Null.Or.Empty, "Projections were present");
+ Assert.That (Translator.ClauseParameters[0], Is.EqualTo (ContactsContract.CommonDataKinds.StructuredName.ContentItemType));
+ Assert.That (Translator.ClauseParameters[1], Is.EqualTo ("Foo"));
+ Assert.That (Translator.ClauseParameters.Length, Is.EqualTo (2));
+ Assert.That (Translator.ReturnType, Is.Null.Or.EqualTo (typeof (Contact)));
+ Assert.That (Translator.Table, Is.EqualTo (ContactsContract.Data.ContentUri));
+ Assert.That (Translator.SortString, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void WhereWithOrClauseFromSameTableDifferentMimeType()
+ {
+ Queryable.Where (c => c.FirstName == "Foo" || c.DisplayName == "Foo Bar").ToArray();
+ AssertFallback();
+ }
+
+ [Test]
+ public void WhereFallback()
+ {
+ Queryable.Where (c => c.Organizations.Any()).ToArray();
+ AssertFallback();
+ }
+
+ [Test]
+ public void FirstFallback()
+ {
+ Queryable.First (c => c.Organizations.Any());
+ AssertFallback();
+ }
+
+ [Test]
+ public void FirstOrDefaultFallback()
+ {
+ Queryable.FirstOrDefault (c => c.Organizations.Any());
+ AssertFallback();
+ }
+
+ [Test]
+ public void SingleFallback()
+ {
+ Queryable.Single (c => c.Organizations.Any());
+ AssertFallback();
+ }
+
+ [Test]
+ public void SingleOrDefaultFallback()
+ {
+ Queryable.SingleOrDefault (c => c.Organizations.Any());
+ AssertFallback();
+ }
+
+ [Test]
+ public void AnyFallback()
+ {
+ Queryable.Any (c => c.Organizations.Any());
+ AssertFallback();
+ }
+
+ [Test]
+ public void CountFallback()
+ {
+ Queryable.Count (c => c.Organizations.Any());
+ AssertFallback();
+ }
+
+ public void AssertFallback()
+ {
+ Translator.Translate (Queryable.LastExpression);
+
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Skip, Is.EqualTo (-1));
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ Assert.That (Translator.Projections, Is.Null.Or.Empty);
+ Assert.That (Translator.QueryString, Is.Null.Or.Empty);
+ Assert.That (Translator.SortString, Is.Null.Or.Empty);
+ Assert.That (Translator.ReturnType, Is.Null);
+ Assert.That (Translator.Table, Is.EqualTo (ContactsContract.Contacts.ContentUri));
+ Assert.That (Translator.ClauseParameters, Is.Null.Or.Empty);
+ }
+
+ [Test]
+ public void Count()
+ {
+ Queryable.Count();
+ Translator.Translate (Queryable.LastExpression);
+
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.True);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ Assert.That (Translator.Skip, Is.EqualTo (-1));
+ Assert.That (Translator.QueryString, Is.Null.Or.Empty);
+ Assert.That (Translator.ClauseParameters, Is.Null.Or.Empty);
+ Assert.That (Translator.Projections, Is.Null.Or.Empty);
+ Assert.That (Translator.SortString, Is.Null.Or.Empty);
+ Assert.That (Translator.Table, Is.EqualTo (ContactsContract.Contacts.ContentUri));
+ Assert.That (Translator.ReturnType, Is.Null);
+ }
+
+ [Test]
+ public void Any()
+ {
+ Queryable.Any();
+ Translator.Translate (Queryable.LastExpression);
+
+ Assert.That (Translator.IsAny, Is.True);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ Assert.That (Translator.Skip, Is.EqualTo (-1));
+ Assert.That (Translator.QueryString, Is.Null);
+ Assert.That (Translator.ClauseParameters, Is.Null.Or.Empty);
+ Assert.That (Translator.Projections, Is.Null.Or.Empty);
+ Assert.That (Translator.SortString, Is.Null.Or.Empty);
+ Assert.That (Translator.Table, Is.EqualTo (ContactsContract.Contacts.ContentUri));
+ Assert.That (Translator.ReturnType, Is.Null);
+ }
+
+ [Test]
+ public void Skip()
+ {
+ Queryable.Skip (5).ToArray();
+ Translator.Translate (Queryable.LastExpression);
+
+ Assert.That (Translator.IsAny, Is.False);
+ Assert.That (Translator.IsCount, Is.False);
+ Assert.That (Translator.Take, Is.EqualTo (-1));
+ Assert.That (Translator.Skip, Is.EqualTo (5));
+ Assert.That (Translator.QueryString, Is.Null);
+ Assert.That (Translator.ClauseParameters, Is.Null.Or.Empty);
+ Assert.That (Translator.Projections, Is.Null.Or.Empty);
+ Assert.That (Translator.SortString, Is.Null.Or.Empty);
+ Assert.That (Translator.Table, Is.EqualTo (ContactsContract.Contacts.ContentUri));
+ Assert.That (Translator.ReturnType, Is.Null);
+ }
+
+ private MockQueryable Queryable
+ {
+ get { return this.queryable; }
+ }
+
+ private ContentQueryTranslator Translator
+ {
+ get { return this.translator; }
+ }
+
+ private MockQueryable queryable;
+ private ContentQueryTranslator translator;
+
+ [SetUp]
+ public void Setup()
+ {
+ this.queryable = new MockQueryable();
+ this.translator = new ContentQueryTranslator (this.queryable.Provider, new ContactTableFinder { UseRawContacts = false });
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/MonoMobile.Example/MonoMobile.Example.csproj b/MonoDroid/Xamarin.Mobile.Android.Tests/Xamarin.Mobile.Android.Tests.csproj
similarity index 53%
rename from MonoDroid/MonoMobile.Example/MonoMobile.Example.csproj
rename to MonoDroid/Xamarin.Mobile.Android.Tests/Xamarin.Mobile.Android.Tests.csproj
index 8c0d86d..8fc8a7d 100644
--- a/MonoDroid/MonoMobile.Example/MonoMobile.Example.csproj
+++ b/MonoDroid/Xamarin.Mobile.Android.Tests/Xamarin.Mobile.Android.Tests.csproj
@@ -1,82 +1,80 @@

- DebugMonoDroid
+ Debug
AnyCPU
- 10.0.0
+ 12.0.0
2.0
- {C4790D64-9278-4EB8-8623-86DC572CB8D1}
+ {F568E695-0534-4A32-A289-3B5AE59664D8}
{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
Library
- MonoMobile.Example
- Resource
- Resources
+ Xamarin.Mobile.Tests
+ Resources
+ Assets
+ true
True
Resources\Resource.designer.cs
- MonoMobile.Example
- v2.2
+ Resource
+ Xamarin.Mobile.Android.Tests
+
+
Properties\AndroidManifest.xml
+ armeabi,armeabi-v7a,x86
+
+
+
+
-
+
true
full
false
bin\Debug
- DEBUG
+ DEBUG;__MOBILE__;__ANDROID__;
prompt
4
+ None
false
- None
-
- none
- false
+
+ full
+ true
bin\Release
+ __MOBILE__;__ANDROID__;
prompt
4
- false
false
-
-
- none
- false
- bin\Release
- prompt
- 4
false
- false
+
-
+
+
+
+
-
+
-
- Designer
-
-
-
-
-
+
-
-
- {32DFF77E-AE38-48D6-B067-CF555798EA32}
- MonoMobile.Extensions
+
+ {32dff77e-ae38-48d6-b067-cf555798ea32}
+ Xamarin.Mobile.Android
-
+
+
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/AsyncQuery.cs b/MonoDroid/Xamarin.Mobile/AsyncQuery.cs
new file mode 100644
index 0000000..05c7adf
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/AsyncQuery.cs
@@ -0,0 +1,71 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Threading.Tasks;
+using Android.Content;
+using Android.Database;
+
+namespace Xamarin
+{
+ internal class AsyncQuery
+ : AsyncQueryHandler
+ {
+ internal AsyncQuery (ContentResolver cr, Func selector)
+ : base (cr)
+ {
+ if (selector == null)
+ throw new ArgumentNullException ("selector");
+
+ this.selector = selector;
+ }
+
+ internal AsyncQuery (ContentResolver cr, Func selector, Func predicate)
+ : this (cr, selector)
+ {
+ this.selector = selector;
+ this.predicate = predicate;
+ }
+
+ public Task Task
+ {
+ get { return this.tcs.Task; }
+ }
+
+ protected override void OnQueryComplete (int token, Java.Lang.Object cookie, ICursor cursor)
+ {
+ bool set = false;
+ while (cursor.MoveToNext())
+ {
+ if (this.predicate == null || this.predicate (cursor))
+ {
+ set = true;
+ this.tcs.SetResult (this.selector (cursor));
+ break;
+ }
+ }
+
+ if (!set)
+ this.tcs.SetResult (default(T));
+
+ base.OnQueryComplete (token, cookie, cursor);
+ }
+
+ private readonly TaskCompletionSource tcs = new TaskCompletionSource();
+ private readonly Func selector;
+ private readonly Func predicate;
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Contacts/AddressBook.cs b/MonoDroid/Xamarin.Mobile/Contacts/AddressBook.cs
new file mode 100644
index 0000000..fea4710
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Contacts/AddressBook.cs
@@ -0,0 +1,196 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using Android.Content;
+using Android.Content.Res;
+using Android.Database;
+using Android.Provider;
+
+namespace Xamarin.Contacts
+{
+ public sealed class AddressBook
+ : IQueryable
+ {
+ public AddressBook (Context context)
+ {
+ if (context == null)
+ throw new ArgumentNullException ("context");
+
+ this.content = context.ContentResolver;
+ this.resources = context.Resources;
+ this.contactsProvider = new ContactQueryProvider (context.ContentResolver, context.Resources);
+ }
+
+ public bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public bool SingleContactsSupported
+ {
+ get { return true; }
+ }
+
+ public bool AggregateContactsSupported
+ {
+ get { return true; }
+ }
+
+ public bool PreferContactAggregation
+ {
+ get { return !this.contactsProvider.UseRawContacts; }
+ set { this.contactsProvider.UseRawContacts = !value; }
+ }
+
+ public bool LoadSupported
+ {
+ get { return true; }
+ }
+
+ public Task RequestPermission()
+ {
+ return Task.Factory.StartNew (() =>
+ {
+ try
+ {
+ ICursor cursor = this.content.Query (ContactsContract.Data.ContentUri, null, null, null, null);
+ cursor.Dispose();
+
+ return true;
+ }
+ catch (Java.Lang.SecurityException)
+ {
+ return false;
+ }
+ });
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return ContactHelper.GetContacts (!PreferContactAggregation, this.content, this.resources).GetEnumerator();
+ }
+
+ ///
+ /// Attempts to load a contact for the specified .
+ ///
+ ///
+ /// The if found, null otherwise.
+ /// is null .
+ /// is empty.
+ public Contact Load (string id)
+ {
+ if (id == null)
+ throw new ArgumentNullException ("id");
+ if (id.Trim() == String.Empty)
+ throw new ArgumentException ("Invalid ID", "id");
+
+ Android.Net.Uri curi; string column;
+ if (PreferContactAggregation)
+ {
+ curi = ContactsContract.Contacts.ContentUri;
+ column = ContactsContract.ContactsColumns.LookupKey;
+ }
+ else
+ {
+ curi = ContactsContract.RawContacts.ContentUri;
+ column = ContactsContract.RawContactsColumns.ContactId;
+ }
+
+ ICursor c = null;
+ try
+ {
+ c = this.content.Query (curi, null, column + " = ?", new[] { id }, null);
+ return (c.MoveToNext() ? ContactHelper.GetContact (!PreferContactAggregation, this.content, this.resources, c) : null);
+ }
+ finally
+ {
+ if (c != null)
+ c.Deactivate();
+ }
+ }
+
+ //public Contact SaveNew (Contact contact)
+ //{
+ // if (contact == null)
+ // throw new ArgumentNullException ("contact");
+ // if (contact.Id != null)
+ // throw new ArgumentException ("Contact is not new", "contact");
+
+ // throw new NotImplementedException();
+ //}
+
+ //public Contact SaveExisting (Contact contact)
+ //{
+ // if (contact == null)
+ // throw new ArgumentNullException ("contact");
+ // if (String.IsNullOrWhiteSpace (contact.Id))
+ // throw new ArgumentException ("Contact is not existing");
+
+ // throw new NotImplementedException();
+
+ // return Load (contact.Id);
+ //}
+
+ //public Contact Save (Contact contact)
+ //{
+ // if (contact == null)
+ // throw new ArgumentNullException ("contact");
+
+ // return (String.IsNullOrWhiteSpace (contact.Id) ? SaveNew (contact) : SaveExisting (contact));
+ //}
+
+ //public void Delete (Contact contact)
+ //{
+ // if (contact == null)
+ // throw new ArgumentNullException ("contact");
+ // if (!String.IsNullOrWhiteSpace (contact.Id))
+ // throw new ArgumentException ("Contact is not a persisted instance", "contact");
+
+ // // TODO: Does this cascade?
+ // this.content.Delete (ContactsContract.RawContacts.ContentUri, ContactsContract.RawContactsColumns.ContactId + " = ?", new[] { contact.Id });
+ //}
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ Type IQueryable.ElementType
+ {
+ get { return typeof (Contact); }
+ }
+
+ Expression IQueryable.Expression
+ {
+ get { return Expression.Constant (this); }
+ }
+
+ IQueryProvider IQueryable.Provider
+ {
+ get { return this.contactsProvider; }
+ }
+
+ private readonly ContactQueryProvider contactsProvider;
+ private readonly ContentResolver content;
+ private readonly Resources resources;
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Contacts/Contact.cs b/MonoDroid/Xamarin.Mobile/Contacts/Contact.cs
new file mode 100644
index 0000000..4e2985a
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Contacts/Contact.cs
@@ -0,0 +1,201 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Android.Content;
+using Android.Database;
+using Android.Graphics;
+using Android.OS;
+using Android.Provider;
+using Xamarin.Media;
+
+namespace Xamarin.Contacts
+{
+ public class Contact
+ {
+ public Contact()
+ {
+ }
+
+ internal Contact (string id, bool isAggregate, ContentResolver content)
+ {
+ this.content = content;
+ IsAggregate = isAggregate;
+ Id = id;
+ }
+
+ public string Id
+ {
+ get;
+ private set;
+ }
+
+ public bool IsAggregate
+ {
+ get;
+ private set;
+ }
+
+ public string DisplayName
+ {
+ get;
+ set;
+ }
+
+ public string Prefix
+ {
+ get;
+ set;
+ }
+
+ public string FirstName
+ {
+ get;
+ set;
+ }
+
+ public string MiddleName
+ {
+ get;
+ set;
+ }
+
+ public string LastName
+ {
+ get;
+ set;
+ }
+
+ public string Nickname
+ {
+ get;
+ set;
+ }
+
+ public string Suffix
+ {
+ get;
+ set;
+ }
+
+ internal List relationships = new List();
+ public IEnumerable Relationships
+ {
+ get { return this.relationships; }
+ set { this.relationships = new List (value); }
+ }
+
+ internal List addresses = new List();
+ public IEnumerable Addresses
+ {
+ get { return this.addresses; }
+ set { this.addresses = new List (value); }
+ }
+
+ internal List instantMessagingAccounts = new List();
+ public IEnumerable InstantMessagingAccounts
+ {
+ get { return this.instantMessagingAccounts; }
+ set { this.instantMessagingAccounts = new List (value); }
+ }
+
+ internal List websites = new List();
+ public IEnumerable Websites
+ {
+ get { return this.websites; }
+ set { this.websites = new List (value); }
+ }
+
+ internal List organizations = new List();
+ public IEnumerable Organizations
+ {
+ get { return this.organizations; }
+ set { this.organizations = new List (value); }
+ }
+
+ internal List notes = new List();
+ public IEnumerable Notes
+ {
+ get { return this.notes; }
+ set { this.notes = new List (value); }
+ }
+
+ internal List emails = new List();
+ public IEnumerable Emails
+ {
+ get { return this.emails; }
+ set { this.emails = new List (value); }
+ }
+
+ internal List phones = new List();
+ public IEnumerable Phones
+ {
+ get { return this.phones; }
+ set { this.phones = new List (value); }
+ }
+
+ public Bitmap GetThumbnail()
+ {
+ byte[] data = GetThumbnailBytes();
+ return (data == null) ? null : BitmapFactory.DecodeByteArray (data, 0, data.Length);
+ }
+
+ public Task SaveThumbnailAsync (string path)
+ {
+ if (path == null)
+ throw new ArgumentNullException ("path");
+
+ return Task.Factory.StartNew (() => {
+ byte[] bytes = GetThumbnailBytes();
+ if (bytes == null)
+ return null;
+
+ File.WriteAllBytes (path, bytes);
+ return new MediaFile (path, deletePathOnDispose: false);
+ });
+ }
+
+ byte[] GetThumbnailBytes()
+ {
+ string lookupColumn = (IsAggregate)
+ ? ContactsContract.ContactsColumns.LookupKey
+ : ContactsContract.RawContactsColumns.ContactId;
+
+ ICursor c = null;
+ try {
+ c = this.content.Query (ContactsContract.Data.ContentUri, new[] { ContactsContract.CommonDataKinds.Photo.PhotoColumnId, ContactsContract.DataColumns.Mimetype },
+ lookupColumn + "=? AND " + ContactsContract.DataColumns.Mimetype + "=?", new[] { Id, ContactsContract.CommonDataKinds.Photo.ContentItemType }, null);
+
+ while (c.MoveToNext()) {
+ byte[] tdata = c.GetBlob (c.GetColumnIndex (ContactsContract.CommonDataKinds.Photo.PhotoColumnId));
+ if (tdata != null)
+ return tdata;
+ }
+ } finally {
+ if (c != null)
+ c.Close();
+ }
+
+ return null;
+ }
+
+ private readonly ContentResolver content;
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Contacts/ContactHelper.cs b/MonoDroid/Xamarin.Mobile/Contacts/ContactHelper.cs
new file mode 100644
index 0000000..a0005e2
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Contacts/ContactHelper.cs
@@ -0,0 +1,509 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Android.Content;
+using Android.Content.Res;
+using Android.Database;
+using Android.Provider;
+
+using StructuredName = Android.Provider.ContactsContract.CommonDataKinds.StructuredName;
+using StructuredPostal = Android.Provider.ContactsContract.CommonDataKinds.StructuredPostal;
+using CommonColumns = Android.Provider.ContactsContract.CommonDataKinds.CommonColumns;
+using Uri = Android.Net.Uri;
+using InstantMessaging = Android.Provider.ContactsContract.CommonDataKinds.Im;
+using OrganizationData = Android.Provider.ContactsContract.CommonDataKinds.Organization;
+using WebsiteData = Android.Provider.ContactsContract.CommonDataKinds.Website;
+using Relation = Android.Provider.ContactsContract.CommonDataKinds.Relation;
+
+namespace Xamarin.Contacts
+{
+ internal static class ContactHelper
+ {
+ internal static IEnumerable GetContacts (bool rawContacts, ContentResolver content, Resources resources)
+ {
+ Uri curi = (rawContacts)
+ ? ContactsContract.RawContacts.ContentUri
+ : ContactsContract.Contacts.ContentUri;
+
+ ICursor cursor = null;
+ try
+ {
+ cursor = content.Query (curi, null, null, null, null);
+ if (cursor == null)
+ yield break;
+
+ foreach (Contact contact in GetContacts (cursor, rawContacts, content, resources, 20))
+ yield return contact;
+ }
+ finally
+ {
+ if (cursor != null)
+ cursor.Close();
+ }
+ }
+
+ internal static IEnumerable GetContacts (ICursor cursor, bool rawContacts, ContentResolver content, Resources resources, int batchSize)
+ {
+ if (cursor == null)
+ yield break;
+
+ string column = (rawContacts)
+ ? ContactsContract.RawContactsColumns.ContactId
+ : ContactsContract.ContactsColumns.LookupKey;
+
+ string[] ids = new string[batchSize];
+ int columnIndex = cursor.GetColumnIndex (column);
+
+ HashSet uniques = new HashSet();
+
+ int i = 0;
+ while (cursor.MoveToNext())
+ {
+ if (i == batchSize)
+ {
+ i = 0;
+ foreach (Contact c in GetContacts (rawContacts, content, resources, ids))
+ yield return c;
+ }
+
+ string id = cursor.GetString (columnIndex);
+ if (uniques.Contains (id))
+ continue;
+
+ uniques.Add (id);
+ ids[i++] = id;
+ }
+
+ if (i > 0)
+ {
+ foreach (Contact c in GetContacts (rawContacts, content, resources, ids.Take(i).ToArray()))
+ yield return c;
+ }
+ }
+
+ internal static IEnumerable GetContacts (bool rawContacts, ContentResolver content, Resources resources, string[] ids)
+ {
+ ICursor c = null;
+
+ string column = (rawContacts)
+ ? ContactsContract.RawContactsColumns.ContactId
+ : ContactsContract.ContactsColumns.LookupKey;
+
+ StringBuilder whereb = new StringBuilder();
+ for (int i = 0; i < ids.Length; i++)
+ {
+ if (i > 0)
+ whereb.Append (" OR ");
+
+ whereb.Append (column);
+ whereb.Append ("=?");
+ }
+
+ int x = 0;
+ var map = new Dictionary (ids.Length);
+
+ try
+ {
+ Contact currentContact = null;
+
+ c = content.Query (ContactsContract.Data.ContentUri, null, whereb.ToString(), ids, ContactsContract.ContactsColumns.LookupKey);
+ if (c == null)
+ yield break;
+
+ int idIndex = c.GetColumnIndex (column);
+ int dnIndex = c.GetColumnIndex (ContactsContract.ContactsColumns.DisplayName);
+ while (c.MoveToNext())
+ {
+ string id = c.GetString (idIndex);
+ if (currentContact == null || currentContact.Id != id)
+ {
+ // We need to yield these in the original ID order
+ if (currentContact != null) {
+ if (currentContact.Id == ids[x]) {
+ yield return currentContact;
+ x++;
+ }
+ else
+ map.Add (currentContact.Id, currentContact);
+ }
+
+ currentContact = new Contact (id, !rawContacts, content);
+ currentContact.DisplayName = c.GetString (dnIndex);
+ }
+
+ FillContactWithRow (resources, currentContact, c);
+ }
+
+ if (currentContact != null)
+ map.Add (currentContact.Id, currentContact);
+
+ for (; x < ids.Length; x++) {
+ Contact tContact = null;
+ if (map.TryGetValue (ids[x], out tContact))
+ yield return tContact;
+ }
+ }
+ finally
+ {
+ if (c != null)
+ c.Close();
+ }
+ }
+
+ internal static Contact GetContact (bool rawContact, ContentResolver content, Resources resources, ICursor cursor)
+ {
+ string id = (rawContact)
+ ? cursor.GetString (cursor.GetColumnIndex (ContactsContract.RawContactsColumns.ContactId))
+ : cursor.GetString (cursor.GetColumnIndex (ContactsContract.ContactsColumns.LookupKey));
+
+ Contact contact = new Contact (id, !rawContact, content);
+ contact.DisplayName = GetString (cursor, ContactsContract.ContactsColumns.DisplayName);
+
+ FillContactExtras (rawContact, content, resources, id, contact);
+
+ return contact;
+ }
+
+ internal static void FillContactExtras (bool rawContact, ContentResolver content, Resources resources, string recordId, Contact contact)
+ {
+ ICursor c = null;
+
+ string column = (rawContact)
+ ? ContactsContract.RawContactsColumns.ContactId
+ : ContactsContract.ContactsColumns.LookupKey;
+
+ try
+ {
+ c = content.Query (ContactsContract.Data.ContentUri, null, column + " = ?", new[] { recordId }, null);
+ if (c == null)
+ return;
+
+ while (c.MoveToNext())
+ FillContactWithRow (resources, contact, c);
+ }
+ finally
+ {
+ if (c != null)
+ c.Close();
+ }
+ }
+
+ private static void FillContactWithRow (Resources resources, Contact contact, ICursor c)
+ {
+ string dataType = c.GetString (c.GetColumnIndex (ContactsContract.DataColumns.Mimetype));
+ switch (dataType)
+ {
+ case ContactsContract.CommonDataKinds.Nickname.ContentItemType:
+ contact.Nickname = c.GetString (c.GetColumnIndex (ContactsContract.CommonDataKinds.Nickname.Name));
+ break;
+
+ case StructuredName.ContentItemType:
+ contact.Prefix = c.GetString (StructuredName.Prefix);
+ contact.FirstName = c.GetString (StructuredName.GivenName);
+ contact.MiddleName = c.GetString (StructuredName.MiddleName);
+ contact.LastName = c.GetString (StructuredName.FamilyName);
+ contact.Suffix = c.GetString (StructuredName.Suffix);
+ break;
+
+ case ContactsContract.CommonDataKinds.Phone.ContentItemType:
+ contact.phones.Add (GetPhone (c, resources));
+ break;
+
+ case ContactsContract.CommonDataKinds.Email.ContentItemType:
+ contact.emails.Add (GetEmail (c, resources));
+ break;
+
+ case ContactsContract.CommonDataKinds.Note.ContentItemType:
+ contact.notes.Add (GetNote (c, resources));
+ break;
+
+ case ContactsContract.CommonDataKinds.Organization.ContentItemType:
+ contact.organizations.Add (GetOrganization (c, resources));
+ break;
+
+ case StructuredPostal.ContentItemType:
+ contact.addresses.Add (GetAddress (c, resources));
+ break;
+
+ case InstantMessaging.ContentItemType:
+ contact.instantMessagingAccounts.Add (GetImAccount (c, resources));
+ break;
+
+ case WebsiteData.ContentItemType:
+ contact.websites.Add (GetWebsite (c, resources));
+ break;
+
+ case Relation.ContentItemType:
+ contact.relationships.Add (GetRelationship (c, resources));
+ break;
+ }
+ }
+
+ internal static Note GetNote (ICursor c, Resources resources)
+ {
+ return new Note { Contents = GetString (c, ContactsContract.DataColumns.Data1) };
+ }
+
+ internal static Relationship GetRelationship (ICursor c, Resources resources)
+ {
+ Relationship r = new Relationship { Name = c.GetString (Relation.Name) };
+
+ RelationDataKind rtype = (RelationDataKind)c.GetInt (c.GetColumnIndex (CommonColumns.Type));
+ switch (rtype)
+ {
+ case RelationDataKind.DomesticPartner:
+ case RelationDataKind.Spouse:
+ case RelationDataKind.Friend:
+ r.Type = RelationshipType.SignificantOther;
+ break;
+
+ case RelationDataKind.Child:
+ r.Type = RelationshipType.Child;
+ break;
+
+ default:
+ r.Type = RelationshipType.Other;
+ break;
+ }
+
+ return r;
+ }
+
+ internal static InstantMessagingAccount GetImAccount (ICursor c, Resources resources)
+ {
+ InstantMessagingAccount ima = new InstantMessagingAccount();
+ ima.Account = c.GetString (CommonColumns.Data);
+
+ //IMTypeDataKind imKind = (IMTypeDataKind) c.GetInt (c.GetColumnIndex (CommonColumns.Type));
+ //ima.Type = imKind.ToInstantMessagingType();
+ //ima.Label = InstantMessaging.GetTypeLabel (resources, imKind, c.GetString (CommonColumns.Label));
+
+ IMProtocolDataKind serviceKind = (IMProtocolDataKind) c.GetInt (c.GetColumnIndex (InstantMessaging.Protocol));
+ ima.Service = serviceKind.ToInstantMessagingService();
+ ima.ServiceLabel = (serviceKind != IMProtocolDataKind.Custom)
+ ? InstantMessaging.GetProtocolLabel (resources, serviceKind, String.Empty)
+ : c.GetString (InstantMessaging.CustomProtocol);
+
+ return ima;
+ }
+
+ internal static Address GetAddress (ICursor c, Resources resources)
+ {
+ Address a = new Address();
+ a.Country = c.GetString (StructuredPostal.Country);
+ a.Region = c.GetString (StructuredPostal.Region);
+ a.City = c.GetString (StructuredPostal.City);
+ a.PostalCode = c.GetString (StructuredPostal.Postcode);
+
+ AddressDataKind kind = (AddressDataKind) c.GetInt (c.GetColumnIndex (CommonColumns.Type));
+ a.Type = kind.ToAddressType();
+ a.Label = (kind != AddressDataKind.Custom)
+ ? StructuredPostal.GetTypeLabel (resources, kind, String.Empty)
+ : c.GetString (CommonColumns.Label);
+
+ string street = c.GetString (StructuredPostal.Street);
+ string pobox = c.GetString (StructuredPostal.Pobox);
+ if (street != null)
+ a.StreetAddress = street;
+ if (pobox != null)
+ {
+ if (street != null)
+ a.StreetAddress += Environment.NewLine;
+
+ a.StreetAddress += pobox;
+ }
+ return a;
+ }
+
+ internal static Phone GetPhone (ICursor c, Resources resources)
+ {
+ Phone p = new Phone();
+ p.Number = GetString (c, ContactsContract.CommonDataKinds.Phone.Number);
+
+ PhoneDataKind pkind = (PhoneDataKind) c.GetInt (c.GetColumnIndex (CommonColumns.Type));
+ p.Type = pkind.ToPhoneType();
+ p.Label = (pkind != PhoneDataKind.Custom)
+ ? ContactsContract.CommonDataKinds.Phone.GetTypeLabel (resources, pkind, String.Empty)
+ : c.GetString (CommonColumns.Label);
+
+ return p;
+ }
+
+ internal static Email GetEmail (ICursor c, Resources resources)
+ {
+ Email e = new Email();
+ e.Address = c.GetString (ContactsContract.DataColumns.Data1);
+
+ EmailDataKind ekind = (EmailDataKind) c.GetInt (c.GetColumnIndex (CommonColumns.Type));
+ e.Type = ekind.ToEmailType();
+ e.Label = (ekind != EmailDataKind.Custom)
+ ? ContactsContract.CommonDataKinds.Email.GetTypeLabel (resources, ekind, String.Empty)
+ : c.GetString (CommonColumns.Label);
+
+ return e;
+ }
+
+ internal static Organization GetOrganization (ICursor c, Resources resources)
+ {
+ Organization o = new Organization();
+ o.Name = c.GetString (OrganizationData.Company);
+ o.ContactTitle = c.GetString (OrganizationData.Title);
+
+ OrganizationDataKind d = (OrganizationDataKind) c.GetInt (c.GetColumnIndex (CommonColumns.Type));
+ o.Type = d.ToOrganizationType();
+ o.Label = (d != OrganizationDataKind.Custom)
+ ? OrganizationData.GetTypeLabel (resources, d, String.Empty)
+ : c.GetString (CommonColumns.Label);
+
+ return o;
+ }
+
+ internal static Website GetWebsite (ICursor c, Resources resources)
+ {
+ Website w = new Website();
+ w.Address = c.GetString (WebsiteData.Url);
+
+ //WebsiteDataKind kind = (WebsiteDataKind)c.GetInt (c.GetColumnIndex (CommonColumns.Type));
+ //w.Type = kind.ToWebsiteType();
+ //w.Label = (kind != WebsiteDataKind.Custom)
+ // ? resources.GetString ((int) kind)
+ // : c.GetString (CommonColumns.Label);
+
+ return w;
+ }
+
+ //internal static WebsiteType ToWebsiteType (this WebsiteDataKind websiteKind)
+ //{
+ // switch (websiteKind)
+ // {
+ // case WebsiteDataKind.Work:
+ // return WebsiteType.Work;
+ // case WebsiteDataKind.Home:
+ // return WebsiteType.Home;
+
+ // default:
+ // return WebsiteType.Other;
+ // }
+ //}
+
+ internal static string GetString (this ICursor c, string colName)
+ {
+ return c.GetString (c.GetColumnIndex (colName));
+ }
+
+ internal static AddressType ToAddressType (this AddressDataKind addressKind)
+ {
+ switch (addressKind)
+ {
+ case AddressDataKind.Home:
+ return AddressType.Home;
+ case AddressDataKind.Work:
+ return AddressType.Work;
+ default:
+ return AddressType.Other;
+ }
+ }
+
+ internal static EmailType ToEmailType (this EmailDataKind emailKind)
+ {
+ switch (emailKind)
+ {
+ case EmailDataKind.Home:
+ return EmailType.Home;
+ case EmailDataKind.Work:
+ return EmailType.Work;
+ default:
+ return EmailType.Other;
+ }
+ }
+
+ internal static PhoneType ToPhoneType (this PhoneDataKind phoneKind)
+ {
+ switch (phoneKind)
+ {
+ case PhoneDataKind.Home:
+ return PhoneType.Home;
+ case PhoneDataKind.Mobile:
+ return PhoneType.Mobile;
+ case PhoneDataKind.FaxHome:
+ return PhoneType.HomeFax;
+ case PhoneDataKind.Work:
+ return PhoneType.Work;
+ case PhoneDataKind.FaxWork:
+ return PhoneType.WorkFax;
+ case PhoneDataKind.Pager:
+ case PhoneDataKind.WorkPager:
+ return PhoneType.Pager;
+ default:
+ return PhoneType.Other;
+ }
+ }
+
+ internal static OrganizationType ToOrganizationType (this OrganizationDataKind organizationKind)
+ {
+ switch (organizationKind)
+ {
+ case OrganizationDataKind.Work:
+ return OrganizationType.Work;
+
+ default:
+ return OrganizationType.Other;
+ }
+ }
+
+ internal static InstantMessagingService ToInstantMessagingService (this IMProtocolDataKind protocolKind)
+ {
+ switch (protocolKind)
+ {
+ case IMProtocolDataKind.Aim:
+ return InstantMessagingService.Aim;
+ case IMProtocolDataKind.Msn:
+ return InstantMessagingService.Msn;
+ case IMProtocolDataKind.Yahoo:
+ return InstantMessagingService.Yahoo;
+ case IMProtocolDataKind.Jabber:
+ return InstantMessagingService.Jabber;
+ case IMProtocolDataKind.Icq:
+ return InstantMessagingService.Icq;
+ case IMProtocolDataKind.Skype:
+ return InstantMessagingService.Skype;
+ case IMProtocolDataKind.GoogleTalk:
+ return InstantMessagingService.Google;
+ case IMProtocolDataKind.Qq:
+ return InstantMessagingService.QQ;
+ default:
+ return InstantMessagingService.Other;
+ }
+ }
+
+ //internal static InstantMessagingType ToInstantMessagingType (this IMTypeDataKind imKind)
+ //{
+ // switch (imKind)
+ // {
+ // case IMTypeDataKind.Home:
+ // return InstantMessagingType.Home;
+ // case IMTypeDataKind.Work:
+ // return InstantMessagingType.Work;
+ // default:
+ // return InstantMessagingType.Other;
+ // }
+ //}
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Contacts/ContactQueryProvider.cs b/MonoDroid/Xamarin.Mobile/Contacts/ContactQueryProvider.cs
new file mode 100644
index 0000000..c4349ea
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Contacts/ContactQueryProvider.cs
@@ -0,0 +1,66 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections;
+using Android.Content;
+using Android.Content.Res;
+
+namespace Xamarin.Contacts
+{
+ internal class ContactQueryProvider
+ : ContentQueryProvider
+ {
+ internal ContactQueryProvider (ContentResolver content, Resources resources)
+ : base (content, resources, new ContactTableFinder())
+ {
+ }
+
+ public bool UseRawContacts
+ {
+ get { return ((ContactTableFinder)TableFinder).UseRawContacts; }
+ set { ((ContactTableFinder)TableFinder).UseRawContacts = value; }
+ }
+
+ protected override IEnumerable GetObjectReader (ContentQueryTranslator translator)
+ {
+ if (translator == null || translator.ReturnType == null || translator.ReturnType == typeof(Contact))
+ return new ContactReader (UseRawContacts, translator, content, resources);
+ else if (translator.ReturnType == typeof(Phone))
+ return new GenericQueryReader (translator, content, resources, ContactHelper.GetPhone);
+ else if (translator.ReturnType == typeof(Email))
+ return new GenericQueryReader (translator, content, resources, ContactHelper.GetEmail);
+ else if (translator.ReturnType == typeof(Address))
+ return new GenericQueryReader (translator, content, resources, ContactHelper.GetAddress);
+ else if (translator.ReturnType == typeof(Relationship))
+ return new GenericQueryReader (translator, content, resources, ContactHelper.GetRelationship);
+ else if (translator.ReturnType == typeof(InstantMessagingAccount))
+ return new GenericQueryReader (translator, content, resources, ContactHelper.GetImAccount);
+ else if (translator.ReturnType == typeof(Website))
+ return new GenericQueryReader (translator, content, resources, ContactHelper.GetWebsite);
+ else if (translator.ReturnType == typeof(Organization))
+ return new GenericQueryReader (translator, content, resources, ContactHelper.GetOrganization);
+ else if (translator.ReturnType == typeof(Note))
+ return new GenericQueryReader (translator, content, resources, ContactHelper.GetNote);
+ else if (translator.ReturnType == typeof(string))
+ return new ProjectionReader (content, translator, (cur,col) => cur.GetString (col));
+ else if (translator.ReturnType == typeof(int))
+ return new ProjectionReader (content, translator, (cur, col) => cur.GetInt (col));
+
+ throw new ArgumentException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Contacts/ContactReader.cs b/MonoDroid/Xamarin.Mobile/Contacts/ContactReader.cs
new file mode 100644
index 0000000..b27d72a
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Contacts/ContactReader.cs
@@ -0,0 +1,121 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Android.Content;
+using Android.Content.Res;
+using Android.Database;
+using Android.Provider;
+
+namespace Xamarin.Contacts
+{
+ internal class ContactReader
+ : IEnumerable
+ {
+ public ContactReader (bool useRawContacts, ContentQueryTranslator translator, ContentResolver content, Resources resources)
+ {
+ this.rawContacts = useRawContacts;
+ this.translator = translator;
+ this.content = content;
+ this.resources = resources;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ Android.Net.Uri table = (this.rawContacts)
+ ? ContactsContract.RawContacts.ContentUri
+ : ContactsContract.Contacts.ContentUri;
+
+ string query = null;
+ string[] parameters = null;
+ string sortString = null;
+ string[] projections = null;
+
+ if (this.translator != null)
+ {
+ table = this.translator.Table;
+ query = this.translator.QueryString;
+ parameters = this.translator.ClauseParameters;
+ sortString = this.translator.SortString;
+
+ if (this.translator.Projections != null)
+ {
+ projections = this.translator.Projections
+ .Where (p => p.Columns != null)
+ .SelectMany (t => t.Columns)
+ .ToArray();
+
+ if (projections.Length == 0)
+ projections = null;
+ }
+
+ if (this.translator.Skip > 0 || this.translator.Take > 0)
+ {
+ StringBuilder limitb = new StringBuilder();
+
+ if (sortString == null)
+ limitb.Append (ContactsContract.ContactsColumns.LookupKey);
+
+ limitb.Append (" LIMIT ");
+
+ if (this.translator.Skip > 0)
+ {
+ limitb.Append (this.translator.Skip);
+ if (this.translator.Take > 0)
+ limitb.Append (",");
+ }
+
+ if (this.translator.Take > 0)
+ limitb.Append (this.translator.Take);
+
+ sortString = (sortString == null) ? limitb.ToString() : sortString + limitb;
+ }
+ }
+
+ ICursor cursor = null;
+ try
+ {
+ cursor = this.content.Query (table, projections, query, parameters, sortString);
+ if (cursor == null)
+ yield break;
+
+ foreach (Contact contact in ContactHelper.GetContacts (cursor, this.rawContacts, this.content, this.resources, BatchSize))
+ yield return contact;
+ }
+ finally
+ {
+ if (cursor != null)
+ cursor.Close();
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ private readonly bool rawContacts;
+ private readonly ContentQueryTranslator translator;
+ private readonly ContentResolver content;
+ private readonly Resources resources;
+
+ private const int BatchSize = 20;
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Contacts/ContactTableFinder.cs b/MonoDroid/Xamarin.Mobile/Contacts/ContactTableFinder.cs
new file mode 100644
index 0000000..f2caf74
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Contacts/ContactTableFinder.cs
@@ -0,0 +1,289 @@
+//
+// Copyright 2011-2014, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+using Android.Provider;
+using Uri = Android.Net.Uri;
+
+namespace Xamarin.Contacts
+{
+ internal class ContactTableFinder
+ : ExpressionVisitor, ITableFinder
+ {
+ public bool UseRawContacts
+ {
+ get;
+ set;
+ }
+
+ public Uri DefaultTable
+ {
+ get { return (UseRawContacts) ? ContactsContract.RawContacts.ContentUri : ContactsContract.Contacts.ContentUri; }
+ }
+
+ public TableFindResult Find (Expression expression)
+ {
+ Visit (expression);
+
+ var result = new TableFindResult (this.table, this.mimeType);
+
+ this.table = null;
+ this.mimeType = null;
+
+ return result;
+ }
+
+ public bool IsSupportedType (Type type)
+ {
+ return type == typeof(Contact)
+ || type == typeof(Phone)
+ || type == typeof(Email)
+ || type == typeof(Address)
+ || type == typeof(Relationship)
+ || type == typeof(InstantMessagingAccount)
+ || type == typeof(Website)
+ || type == typeof(Organization)
+ || type == typeof(Note);
+ }
+
+ public ContentResolverColumnMapping GetColumn (MemberInfo member)
+ {
+ if (member.DeclaringType == typeof(Contact))
+ return GetContactColumn (member);
+ if (member.DeclaringType == typeof(Email))
+ return GetEmailColumn (member);
+ if (member.DeclaringType == typeof(Phone))
+ return GetPhoneColumn (member);
+ if (member.DeclaringType == typeof(Address))
+ return GetAddressColumn (member);
+ if (member.DeclaringType == typeof(Relationship))
+ return GetRelationshipColumn (member);
+ if (member.DeclaringType == typeof(InstantMessagingAccount))
+ return GetImColumn (member);
+ if (member.DeclaringType == typeof(Website))
+ return GetWebsiteColumn (member);
+ if (member.DeclaringType == typeof(Organization))
+ return GetOrganizationColumn (member);
+ if (member.DeclaringType == typeof(Note))
+ return GetNoteColumn (member);
+
+ return null;
+ }
+
+ private Uri table;
+ private string mimeType;
+
+ private ContentResolverColumnMapping GetNoteColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "Contents":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.CommonColumns.Data, typeof (string));
+ }
+
+ return null;
+ }
+
+ private ContentResolverColumnMapping GetOrganizationColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "ContactTitle":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.Organization.Title, typeof (string));
+ case "Name":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.Organization.Company, typeof (string));
+ }
+
+ return null;
+ }
+
+ private ContentResolverColumnMapping GetWebsiteColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "Address":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.Website.Url, typeof (string));
+ }
+
+ return null;
+ }
+
+ private ContentResolverColumnMapping GetImColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "Account":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.CommonColumns.Data, typeof(string));
+ }
+
+ return null;
+ }
+
+ private ContentResolverColumnMapping GetRelationshipColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "Name":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.Relation.Name, typeof (string));
+ }
+
+ return null;
+ }
+
+ private ContentResolverColumnMapping GetAddressColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "City":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.StructuredPostal.City, typeof(string));
+ case "Region":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.StructuredPostal.Region, typeof (string));
+ case "Country":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.StructuredPostal.Country, typeof (string));
+ case "PostalCode":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.StructuredPostal.Postcode, typeof(string));
+ }
+
+ return null;
+ }
+
+ private ContentResolverColumnMapping GetPhoneColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "Number":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.Phone.Number, typeof (string));
+ }
+
+ return null;
+ }
+
+ private ContentResolverColumnMapping GetEmailColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "Address":
+ return new ContentResolverColumnMapping (ContactsContract.DataColumns.Data1, typeof (string));
+ }
+
+ return null;
+ }
+
+ private ContentResolverColumnMapping GetContactColumn (MemberInfo member)
+ {
+ switch (member.Name)
+ {
+ case "DisplayName":
+ return new ContentResolverColumnMapping (ContactsContract.ContactsColumns.DisplayName, typeof(string));
+ case "Prefix":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.StructuredName.Prefix, typeof(string));
+ case "FirstName":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.StructuredName.GivenName, typeof(string));
+ case "LastName":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.StructuredName.FamilyName, typeof(string));
+ case "Suffix":
+ return new ContentResolverColumnMapping (ContactsContract.CommonDataKinds.StructuredName.Suffix, typeof(string));
+
+ case "Phones":
+ return new ContentResolverColumnMapping ((string)null, typeof (IEnumerable));
+ case "Emails":
+ return new ContentResolverColumnMapping ((string)null, typeof (IEnumerable));
+ case "Addresses":
+ return new ContentResolverColumnMapping ((string)null, typeof (IEnumerable));
+ case "Notes":
+ return new ContentResolverColumnMapping ((string) null, typeof (IEnumerable));
+ case "Relationships":
+ return new ContentResolverColumnMapping ((string) null, typeof (IEnumerable));
+ case "InstantMessagingAccounts":
+ return new ContentResolverColumnMapping ((string) null, typeof (IEnumerable));
+ case "Websites":
+ return new ContentResolverColumnMapping ((string) null, typeof (IEnumerable));
+ case "Organizations":
+ return new ContentResolverColumnMapping ((string) null, typeof (IEnumerable));
+
+ default:
+ return null;
+ }
+ }
+
+ protected override Expression VisitMemberAccess (MemberExpression member)
+ {
+ member = (MemberExpression)base.VisitMemberAccess (member);
+
+ if (this.table == null)
+ {
+ if (member.Member.DeclaringType == typeof (Contact))
+ this.table = GetContactTable (member);
+ else if (member.Member.DeclaringType == typeof(Phone))
+ this.table = ContactsContract.CommonDataKinds.Phone.ContentUri;
+ else if (member.Member.DeclaringType == typeof(Email))
+ this.table = ContactsContract.CommonDataKinds.Email.ContentUri;
+ }
+
+ return member;
+ }
+
+ private Uri GetContactTable (MemberExpression expression)
+ {
+ switch (expression.Member.Name)
+ {
+ case "DisplayName":
+ return (UseRawContacts) ? ContactsContract.RawContacts.ContentUri : ContactsContract.Contacts.ContentUri;
+
+ case "Prefix":
+ case "FirstName":
+ case "MiddleName":
+ case "LastName":
+ case "Suffix":
+ this.mimeType = ContactsContract.CommonDataKinds.StructuredName.ContentItemType;
+ return ContactsContract.Data.ContentUri;
+
+ case "Relationships":
+ this.mimeType = ContactsContract.CommonDataKinds.Relation.ContentItemType;
+ return ContactsContract.Data.ContentUri;
+
+ case "Organizations":
+ this.mimeType = ContactsContract.CommonDataKinds.Organization.ContentItemType;
+ return ContactsContract.Data.ContentUri;
+
+ case "Notes":
+ this.mimeType = ContactsContract.CommonDataKinds.Note.ContentItemType;
+ return ContactsContract.Data.ContentUri;
+
+ case "Phones":
+ return ContactsContract.CommonDataKinds.Phone.ContentUri;
+ case "Emails":
+ return ContactsContract.CommonDataKinds.Email.ContentUri;
+ case "Addresses":
+ return ContactsContract.CommonDataKinds.StructuredPostal.ContentUri;
+
+ case "Websites":
+ this.mimeType = ContactsContract.CommonDataKinds.Website.ContentItemType;
+ return ContactsContract.Data.ContentUri;
+
+ case "InstantMessagingAccounts":
+ this.mimeType = ContactsContract.CommonDataKinds.Im.ContentItemType;
+ return ContactsContract.Data.ContentUri;
+
+ default:
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/ContentQueryProvider.cs b/MonoDroid/Xamarin.Mobile/ContentQueryProvider.cs
new file mode 100644
index 0000000..576f9bf
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/ContentQueryProvider.cs
@@ -0,0 +1,130 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using Android.Content;
+using Android.Content.Res;
+using Android.Database;
+
+namespace Xamarin
+{
+ internal abstract class ContentQueryProvider
+ : IQueryProvider
+ {
+ internal ContentQueryProvider (ContentResolver content, Resources resources, ITableFinder tableFinder)
+ {
+ this.content = content;
+ this.resources = resources;
+ this.tableFinder = tableFinder;
+ }
+
+ public ITableFinder TableFinder
+ {
+ get { return this.tableFinder; }
+ }
+
+ protected readonly ContentResolver content;
+ protected readonly Resources resources;
+ private readonly ITableFinder tableFinder;
+
+ IQueryable IQueryProvider.CreateQuery (Expression expression)
+ {
+ throw new NotImplementedException();
+ }
+
+ object IQueryProvider.Execute (Expression expression)
+ {
+ var translator = new ContentQueryTranslator (this, this.tableFinder);
+ expression = translator.Translate (expression);
+
+ if (translator.IsCount || translator.IsAny)
+ {
+ ICursor cursor = null;
+ try
+ {
+ string[] projections = (translator.Projections != null)
+ ? translator.Projections
+ .Where (p => p.Columns != null)
+ .SelectMany (t => t.Columns)
+ .ToArray()
+ : null;
+
+ cursor = this.content.Query (translator.Table, projections, translator.QueryString,
+ translator.ClauseParameters, translator.SortString);
+
+ if (translator.IsCount)
+ return cursor.Count;
+ else
+ return (cursor.Count > 0);
+ }
+ finally
+ {
+ if (cursor != null)
+ cursor.Close();
+ }
+ }
+
+ IQueryable q = GetObjectReader (translator).AsQueryable();
+ //IQueryable q = GetObjectReader (null).AsQueryable();
+
+ expression = ReplaceQueryable (expression, q);
+
+ if (expression.Type.IsGenericType && expression.Type.GetGenericTypeDefinition() == typeof(IOrderedQueryable<>))
+ return q.Provider.CreateQuery (expression);
+ else
+ return q.Provider.Execute (expression);
+ }
+
+ protected abstract IEnumerable GetObjectReader (ContentQueryTranslator translator);
+
+ IQueryable IQueryProvider.CreateQuery (Expression expression)
+ {
+ return new Query (this, expression);
+ }
+
+ TResult IQueryProvider.Execute (Expression expression)
+ {
+ return (TResult)((IQueryProvider)this).Execute (expression);
+ }
+
+ private Expression ReplaceQueryable (Expression expression, object value)
+ {
+ MethodCallExpression mc = expression as MethodCallExpression;
+ if (mc != null)
+ {
+ Expression[] args = mc.Arguments.ToArray();
+ Expression narg = ReplaceQueryable (mc.Arguments[0], value);
+ if (narg != args[0])
+ {
+ args[0] = narg;
+ return Expression.Call (mc.Method, args);
+ }
+ else
+ return mc;
+ }
+
+ ConstantExpression c = expression as ConstantExpression;
+ if (c != null && c.Type.GetInterfaces().Contains (typeof(IQueryable)))
+ return Expression.Constant (value);
+
+ return expression;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/ContentQueryTranslator.cs b/MonoDroid/Xamarin.Mobile/ContentQueryTranslator.cs
new file mode 100644
index 0000000..288e533
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/ContentQueryTranslator.cs
@@ -0,0 +1,658 @@
+//
+// Copyright 2011-2014, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Text;
+using Android.Provider;
+
+namespace Xamarin
+{
+ internal class ContentQueryTranslator
+ : ExpressionVisitor
+ {
+ public ContentQueryTranslator (IQueryProvider provider, ITableFinder tableFinder)
+ {
+ this.provider = provider;
+ this.tableFinder = tableFinder;
+ Skip = -1;
+ Take = -1;
+ }
+
+ public Android.Net.Uri Table
+ {
+ get;
+ private set;
+ }
+
+ public bool IsAny
+ {
+ get;
+ private set;
+ }
+
+ public bool IsCount
+ {
+ get;
+ private set;
+ }
+
+ public Type ReturnType
+ {
+ get;
+ private set;
+ }
+
+ public IEnumerable Projections
+ {
+ get { return this.projections; }
+ }
+
+ public string QueryString
+ {
+ get { return (this.queryBuilder.Length > 0) ? this.queryBuilder.ToString() : null; }
+ }
+
+ public string[] ClauseParameters
+ {
+ get { return (this.arguments.Count > 0) ? this.arguments.ToArray() : null; }
+ }
+
+ public string SortString
+ {
+ get { return (this.sortBuilder != null) ? this.sortBuilder.ToString() : null; }
+ }
+
+ public int Skip
+ {
+ get;
+ private set;
+ }
+
+ public int Take
+ {
+ get;
+ private set;
+ }
+
+ public Expression Translate (Expression expression)
+ {
+ Expression expr = Visit (expression);
+
+ if (Table == null)
+ Table = this.tableFinder.DefaultTable;
+
+ return expr;
+ }
+
+ private readonly IQueryProvider provider;
+ private readonly ITableFinder tableFinder;
+ private bool fallback = false;
+ private List projections;
+ private StringBuilder sortBuilder;
+ private readonly List arguments = new List();
+ private readonly StringBuilder queryBuilder = new StringBuilder();
+
+ protected override Expression VisitMethodCall (MethodCallExpression methodCall)
+ {
+ if (methodCall.Arguments.Count == 0 || !(methodCall.Arguments[0] is ConstantExpression || methodCall.Arguments[0] is MethodCallExpression))
+ {
+ this.fallback = true;
+ return methodCall;
+ }
+
+ Expression expression = base.VisitMethodCall (methodCall);
+
+ methodCall = expression as MethodCallExpression;
+ if (methodCall == null)
+ {
+ this.fallback = true;
+ return expression;
+ }
+
+ if (!this.fallback)
+ {
+ if (methodCall.Method.Name == "Where")
+ expression = VisitWhere (methodCall);
+ else if (methodCall.Method.Name == "Any")
+ expression = VisitAny (methodCall);
+ else if (methodCall.Method.Name == "Select")
+ expression = VisitSelect (methodCall);
+ else if (methodCall.Method.Name == "SelectMany")
+ expression = VisitSelectMany (methodCall);
+ else if (methodCall.Method.Name == "OrderBy" || methodCall.Method.Name == "OrderByDescending")
+ expression = VisitOrder (methodCall);
+ else if (methodCall.Method.Name == "Skip")
+ expression = VisitSkip (methodCall);
+ else if (methodCall.Method.Name == "Take")
+ expression = VisitTake (methodCall);
+ else if (methodCall.Method.Name == "Count")
+ expression = VisitCount (methodCall);
+ else if (methodCall.Method.Name == "First" || methodCall.Method.Name == "FirstOrDefault")
+ expression = VisitFirst (methodCall);
+ else if (methodCall.Method.Name == "Single" || methodCall.Method.Name == "SingleOrDefault")
+ expression = VisitSingle (methodCall);
+ }
+
+ return expression;
+ }
+
+ private Expression VisitFirst (MethodCallExpression methodCall)
+ {
+ if (methodCall.Arguments.Count > 1)
+ {
+ VisitWhere (methodCall);
+ if (this.fallback)
+ return methodCall;
+ }
+
+ Take = 1;
+ return methodCall;
+ }
+
+ private Expression VisitSingle (MethodCallExpression methodCall)
+ {
+ if (methodCall.Arguments.Count > 1)
+ {
+ VisitWhere (methodCall);
+ if (this.fallback)
+ return methodCall;
+ }
+
+ Take = 2;
+ return methodCall;
+ }
+
+ private Expression VisitCount (MethodCallExpression methodCall)
+ {
+ if (methodCall.Arguments.Count > 1)
+ {
+ VisitWhere (methodCall);
+ if (this.fallback)
+ return methodCall;
+ }
+
+ IsCount = true;
+ return methodCall.Arguments[0];
+ }
+
+ private Expression VisitTake (MethodCallExpression methodCall)
+ {
+ ConstantExpression ce = (ConstantExpression) methodCall.Arguments[1];
+ Take = (int) ce.Value;
+
+ return methodCall.Arguments[0];
+ }
+
+ private Expression VisitSkip (MethodCallExpression methodCall)
+ {
+ ConstantExpression ce = (ConstantExpression) methodCall.Arguments[1];
+ Skip = (int) ce.Value;
+
+ return methodCall.Arguments[0];
+ }
+
+ private Expression VisitAny (MethodCallExpression methodCall)
+ {
+ if (methodCall.Arguments.Count > 1)
+ {
+ VisitWhere (methodCall);
+ if (this.fallback)
+ return methodCall;
+ }
+
+ IsAny = true;
+ return methodCall.Arguments[0];
+ }
+
+ private class WhereEvaluator
+ : ExpressionVisitor
+ {
+ public WhereEvaluator (ITableFinder tableFinder, Android.Net.Uri existingTable)
+ {
+ this.tableFinder = tableFinder;
+ if (existingTable != null)
+ this.table = new TableFindResult (existingTable, null);
+ }
+
+ public Android.Net.Uri Table
+ {
+ get { return this.table.Table; }
+ }
+
+ public string QueryString
+ {
+ get { return this.builder.ToString(); }
+ }
+
+ public List Arguments
+ {
+ get { return this.arguments; }
+ }
+
+ public bool Fallback
+ {
+ get;
+ private set;
+ }
+
+ public Expression Evaluate (Expression expression)
+ {
+ expression = Visit (expression);
+
+ if (!Fallback && this.table != null && this.table.MimeType != null) {
+ this.builder.Insert (0, String.Format ("(({0} = ?) AND ", ContactsContract.DataColumns.Mimetype));
+ this.builder.Append (")");
+
+ this.arguments.Insert (0, this.table.MimeType);
+ }
+
+ return expression;
+ }
+
+ private readonly ITableFinder tableFinder;
+ private TableFindResult table;
+ private StringBuilder builder = new StringBuilder();
+ private readonly List arguments = new List();
+ private ContentResolverColumnMapping currentMap;
+
+ protected override Expression VisitMemberAccess (MemberExpression memberExpression)
+ {
+ TableFindResult result = this.tableFinder.Find (memberExpression);
+ if (this.table == null)
+ this.table = result;
+ else if (Table != result.Table || result.MimeType != this.table.MimeType) {
+ Fallback = true;
+ return memberExpression;
+ }
+
+ ContentResolverColumnMapping cmap = this.tableFinder.GetColumn (memberExpression.Member);
+ if (cmap == null || cmap.Columns == null)
+ {
+ Fallback = true;
+ return memberExpression;
+ }
+
+ this.currentMap = cmap;
+
+ if (cmap.Columns.Length == 1)
+ this.builder.Append (cmap.Columns[0]);
+ else
+ throw new NotSupportedException();
+
+ return base.VisitMemberAccess (memberExpression);
+ }
+
+ protected override Expression VisitConstant (ConstantExpression constant)
+ {
+ if (constant.Value is IQueryable)
+ return constant;
+
+ if (constant.Value == null)
+ this.builder.Append ("NULL");
+ else
+ {
+ object value = constant.Value;
+ if (this.currentMap != null && this.currentMap.ValueToQueryable != null)
+ value = this.currentMap.ValueToQueryable (value);
+
+ switch (Type.GetTypeCode (value.GetType()))
+ {
+ case TypeCode.Object:
+ Fallback = true;
+ return constant;
+
+ case TypeCode.Boolean:
+ this.arguments.Add ((bool)value ? "1" : "0");
+ this.builder.Append ("?");
+ break;
+
+ default:
+ this.arguments.Add (value.ToString());
+ this.builder.Append ("?");
+ break;
+ }
+ }
+
+ return base.VisitConstant (constant);
+ }
+
+ protected override Expression VisitBinary (BinaryExpression binary)
+ {
+ string current = this.builder.ToString();
+ this.builder = new StringBuilder();
+
+ Visit (binary.Left);
+ if (Fallback)
+ return binary;
+
+ string left = this.builder.ToString();
+ this.builder = new StringBuilder();
+
+ string joiner;
+ switch (binary.NodeType)
+ {
+ case ExpressionType.AndAlso:
+ joiner = " AND ";
+ break;
+
+ case ExpressionType.OrElse:
+ joiner = " OR ";
+ break;
+
+ case ExpressionType.Equal:
+ joiner = " = ";
+ break;
+
+ case ExpressionType.GreaterThan:
+ joiner = " > ";
+ break;
+
+ case ExpressionType.LessThan:
+ joiner = " < ";
+ break;
+
+ case ExpressionType.NotEqual:
+ joiner = " IS NOT ";
+ break;
+
+ default:
+ Fallback = true;
+ return binary;
+ }
+
+ Visit (binary.Right);
+ if (Fallback) {
+ if (binary.NodeType == ExpressionType.AndAlso) {
+ Fallback = false;
+ this.builder = new StringBuilder (current);
+ this.builder.Append ("(");
+ this.builder.Append (left);
+ this.builder.Append (")");
+ return binary.Right;
+ } else
+ return binary;
+ }
+
+ string right = this.builder.ToString();
+
+ this.builder = new StringBuilder (current);
+ this.builder.Append ("(");
+ this.builder.Append (left);
+ this.builder.Append (joiner);
+ this.builder.Append (right);
+ this.builder.Append (")");
+
+ return binary;
+ }
+ }
+
+ private Expression VisitWhere (MethodCallExpression methodCall)
+ {
+ Expression expression = ExpressionEvaluator.Evaluate (methodCall);
+
+ var eval = new WhereEvaluator (this.tableFinder, Table);
+ expression = eval.Evaluate (expression);
+
+ if (eval.Fallback || eval.Table == null || (Table != null && eval.Table != Table)) {
+ this.fallback = true;
+ return methodCall;
+ }
+
+ if (Table == null)
+ Table = eval.Table;
+
+ this.arguments.AddRange (eval.Arguments);
+ if (this.queryBuilder.Length > 0)
+ this.queryBuilder.Append (" AND ");
+
+ this.queryBuilder.Append (eval.QueryString);
+
+ return methodCall.Arguments[0];
+ }
+
+ private Type GetExpressionArgumentType (Expression expression)
+ {
+ switch (expression.NodeType)
+ {
+ case ExpressionType.Constant:
+ return ((ConstantExpression) expression).Value.GetType();
+ }
+
+ return null;
+ }
+
+ private Expression VisitSelect (MethodCallExpression methodCall)
+ {
+ MemberExpression me = FindMemberExpression (methodCall.Arguments[1]);
+ if (!TryGetTable (me))
+ return methodCall;
+
+ ContentResolverColumnMapping column = this.tableFinder.GetColumn (me.Member);
+ if (column == null || column.Columns == null)
+ return methodCall;
+
+ (this.projections ?? (this.projections = new List())).Add (column);
+ if (column.ReturnType.IsValueType || column.ReturnType == typeof(string))
+ ReturnType = column.ReturnType;
+
+ this.fallback = true;
+
+ Type argType = GetExpressionArgumentType (methodCall.Arguments[0]);
+ if (ReturnType == null || (argType != null && ReturnType.IsAssignableFrom (argType)))
+ return methodCall.Arguments[0];
+
+ return Expression.Constant (Activator.CreateInstance (typeof (Query<>).MakeGenericType (ReturnType), this.provider));
+ }
+
+// private Expression VisitSelect (MethodCallExpression methodCall)
+// {
+// List mes = MemberExpressionFinder.Find (methodCall.Arguments[1], this.tableFinder);
+// if (!TryGetTable (mes))
+// return methodCall;
+//
+// Type returnType = null;
+//
+// List> projs = new List>();
+// foreach (MemberExpression me in mes)
+// {
+// Tuple column = this.tableFinder.GetColumn (me.Member);
+// if (column == null)
+// return methodCall;
+//
+// if (returnType == null)
+// returnType = column.Item2;
+// if (returnType != column.Item2)
+// return methodCall;
+//
+// projs.Add (column);
+// }
+//
+// ReturnType = returnType;
+// this.fallback = true;
+//
+// (this.projections ?? (this.projections = new List>()))
+// .AddRange (projs);
+//
+// return methodCall.Arguments[0];
+// }
+
+ private Expression VisitSelectMany (MethodCallExpression methodCall)
+ {
+ List mes = MemberExpressionFinder.Find (methodCall, this.tableFinder);
+ if (mes.Count > 1)
+ {
+ this.fallback = true;
+ return methodCall;
+ }
+
+ if (!TryGetTable (mes))
+ return methodCall;
+
+ ContentResolverColumnMapping column = this.tableFinder.GetColumn (mes[0].Member);
+ if (column == null || column.ReturnType.GetGenericTypeDefinition() != typeof(IEnumerable<>))
+ {
+ this.fallback = true;
+ return methodCall;
+ }
+
+ ReturnType = column.ReturnType.GetGenericArguments()[0];
+
+ return Expression.Constant (Activator.CreateInstance (typeof (Query<>).MakeGenericType (ReturnType), this.provider));
+ //return methodCall.Arguments[0];
+ }
+
+ private Expression VisitOrder (MethodCallExpression methodCall)
+ {
+ MemberExpression me = FindMemberExpression (methodCall.Arguments[1]);
+ if (!TryGetTable (me))
+ return methodCall;
+
+ ContentResolverColumnMapping column = this.tableFinder.GetColumn (me.Member);
+ if (column != null && column.Columns != null)
+ {
+ StringBuilder builder = this.sortBuilder ?? (this.sortBuilder = new StringBuilder());
+ if (builder.Length > 0)
+ builder.Append (", ");
+
+ if (column.Columns.Length > 1)
+ throw new NotSupportedException();
+
+ builder.Append (column.Columns[0]);
+
+ if (methodCall.Method.Name == "OrderByDescending")
+ builder.Append (" DESC");
+
+ return methodCall.Arguments[0];
+ }
+
+ return methodCall;
+ }
+
+ private bool TryGetTable (List memberExpressions)
+ {
+ if (memberExpressions.Count == 0)
+ {
+ this.fallback = true;
+ return false;
+ }
+
+ Android.Net.Uri existingTable = Table;
+
+ TableFindResult presult = null;
+
+ foreach (MemberExpression me in memberExpressions)
+ {
+ TableFindResult result = this.tableFinder.Find (me);
+ if (result.Table == null)
+ {
+ this.fallback = true;
+ return false;
+ }
+
+ if (existingTable == null)
+ {
+ existingTable = result.Table;
+ presult = result;
+ }
+ else if (existingTable != result.Table)
+ {
+ this.fallback = true;
+ return false;
+ }
+ }
+
+ if (presult == null)
+ {
+ this.fallback = true;
+ return false;
+ }
+
+ Table = presult.Table;
+
+ if (presult.MimeType != null) {
+ if (this.queryBuilder.Length > 0)
+ this.queryBuilder.Append (" AND ");
+
+ this.queryBuilder.Append (String.Format ("({0} = ?)", ContactsContract.DataColumns.Mimetype));
+ }
+
+ this.arguments.Add (presult.MimeType);
+
+ return true;
+ }
+
+ private bool TryGetTable (MemberExpression me)
+ {
+ if (me == null)
+ {
+ this.fallback = true;
+ return false;
+ }
+
+ TableFindResult result = this.tableFinder.Find (me);
+ if (result.MimeType != null) {
+ if (this.queryBuilder.Length > 0)
+ this.queryBuilder.Append (" AND ");
+
+ this.queryBuilder.Append (String.Format ("({0} = ?)", ContactsContract.DataColumns.Mimetype));
+ }
+
+ this.arguments.Add (result.MimeType);
+
+ if (Table == null)
+ Table = result.Table;
+ else if (Table != result.Table)
+ {
+ this.fallback = true;
+ return false;
+ }
+
+ return true;
+ }
+
+ private MemberExpression FindMemberExpression (Expression expression)
+ {
+ UnaryExpression ue = expression as UnaryExpression;
+ if (ue != null)
+ expression = ue.Operand;
+
+ LambdaExpression le = expression as LambdaExpression;
+ if (le != null)
+ expression = le.Body;
+
+ MemberExpression me = expression as MemberExpression;
+ if (me != null && this.tableFinder.IsSupportedType (me.Member.DeclaringType))
+ return me;
+
+ BinaryExpression be = expression as BinaryExpression;
+ if (be != null)
+ {
+ me = be.Left as MemberExpression;
+ if (me != null && this.tableFinder.IsSupportedType (me.Member.DeclaringType))
+ return me;
+
+ me = be.Right as MemberExpression;
+ if (me != null && this.tableFinder.IsSupportedType (me.Member.DeclaringType))
+ return me;
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/ContentResolverColumnMapping.cs b/MonoDroid/Xamarin.Mobile/ContentResolverColumnMapping.cs
new file mode 100644
index 0000000..dd2f043
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/ContentResolverColumnMapping.cs
@@ -0,0 +1,91 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+
+namespace Xamarin
+{
+ internal class ContentResolverColumnMapping
+ {
+ public ContentResolverColumnMapping (string column, Type returnType)
+ {
+ if (returnType == null)
+ throw new ArgumentNullException ("returnType");
+
+ if (column != null)
+ Columns = new [] { column };
+
+ ReturnType = returnType;
+ }
+
+ public ContentResolverColumnMapping (string column, Type returnType, Func toQueryable, Func fromQueryable)
+ : this (column, returnType)
+ {
+ if (toQueryable == null)
+ throw new ArgumentNullException ("toQueryable");
+ if (fromQueryable == null)
+ throw new ArgumentNullException ("fromQueryable");
+
+ ValueToQueryable = toQueryable;
+ QueryableToValue = fromQueryable;
+ }
+
+ public ContentResolverColumnMapping (string[] columns, Type returnType)
+ {
+ if (returnType == null)
+ throw new ArgumentNullException ("returnType");
+
+ Columns = columns;
+ ReturnType = returnType;
+ }
+
+ public ContentResolverColumnMapping (string[] columns, Type returnType, Func toQueryable, Func fromQueryable)
+ : this (columns, returnType)
+ {
+ if (toQueryable == null)
+ throw new ArgumentNullException ("toQueryable");
+ if (fromQueryable == null)
+ throw new ArgumentNullException ("fromQueryable");
+
+ ValueToQueryable = toQueryable;
+ QueryableToValue = fromQueryable;
+ }
+
+ public string[] Columns
+ {
+ get;
+ private set;
+ }
+
+ public Func ValueToQueryable
+ {
+ get;
+ private set;
+ }
+
+ public Func QueryableToValue
+ {
+ get;
+ private set;
+ }
+
+ public Type ReturnType
+ {
+ get;
+ private set;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/DateTimeExtensions.cs b/MonoDroid/Xamarin.Mobile/DateTimeExtensions.cs
new file mode 100644
index 0000000..f0eab53
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/DateTimeExtensions.cs
@@ -0,0 +1,30 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+
+namespace Xamarin
+{
+ internal static class DateTimeExtensions
+ {
+ public static long ToAndroidTimestamp (this DateTime self)
+ {
+ return (long)self.ToUniversalTime().Subtract (Epoch).TotalMilliseconds;
+ }
+
+ private static readonly DateTime Epoch = new DateTime (1970, 1, 1);
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/GenericQueryReader.cs b/MonoDroid/Xamarin.Mobile/GenericQueryReader.cs
new file mode 100644
index 0000000..36a2bb5
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/GenericQueryReader.cs
@@ -0,0 +1,119 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Android.Content;
+using Android.Content.Res;
+using Android.Database;
+using Android.Provider;
+
+namespace Xamarin
+{
+ internal class GenericQueryReader
+ : IEnumerable
+ {
+ public GenericQueryReader (ContentQueryTranslator translator, ContentResolver content, Resources resources, Func selector, string defaultSort)
+ : this (translator, content, resources, selector)
+ {
+ if (defaultSort == null)
+ throw new ArgumentNullException ("defaultSort");
+
+ this.defaultSort = defaultSort;
+ }
+
+ public GenericQueryReader (ContentQueryTranslator translator, ContentResolver content, Resources resources, Func selector)
+ {
+ if (translator == null)
+ throw new ArgumentNullException ("translator");
+ if (content == null)
+ throw new ArgumentNullException ("content");
+ if (resources == null)
+ throw new ArgumentNullException ("resources");
+ if (selector == null)
+ throw new ArgumentNullException ("selector");
+
+ this.translator = translator;
+ this.content = content;
+ this.resources = resources;
+ this.selector = selector;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ ICursor cursor = null;
+ try
+ {
+ string sortString = this.translator.SortString;
+ if ((sortString != null || this.defaultSort != null)
+ && this.translator != null && (this.translator.Skip > 0 || this.translator.Take > 0))
+ {
+ StringBuilder limitb = new StringBuilder();
+
+ if (sortString == null)
+ limitb.Append (this.defaultSort);
+
+ limitb.Append (" LIMIT ");
+
+ if (this.translator.Skip > 0)
+ {
+ limitb.Append (this.translator.Skip);
+ if (this.translator.Take > 0)
+ limitb.Append (",");
+ }
+
+ if (this.translator.Take > 0)
+ limitb.Append (this.translator.Take);
+
+ sortString = (sortString == null) ? limitb.ToString() : sortString + limitb;
+ }
+
+ string[] projections = (translator.Projections != null)
+ ? translator.Projections
+ .Where (p => p.Columns != null)
+ .SelectMany (t => t.Columns)
+ .ToArray()
+ : null;
+
+ cursor = this.content.Query (this.translator.Table, projections,
+ this.translator.QueryString, this.translator.ClauseParameters,
+ sortString);
+
+ while (cursor.MoveToNext())
+ yield return this.selector (cursor, this.resources);
+ }
+ finally
+ {
+ if (cursor != null)
+ cursor.Close();
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ private readonly string defaultSort;
+ private readonly Func selector;
+ private readonly ContentQueryTranslator translator;
+ private readonly ContentResolver content;
+ private readonly Resources resources;
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Geolocation/GeolocationContinuousListener.cs b/MonoDroid/Xamarin.Mobile/Geolocation/GeolocationContinuousListener.cs
new file mode 100644
index 0000000..633917c
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Geolocation/GeolocationContinuousListener.cs
@@ -0,0 +1,142 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Threading;
+using Android.Locations;
+using Android.OS;
+using System.Collections.Generic;
+
+namespace Xamarin.Geolocation
+{
+ internal class GeolocationContinuousListener
+ : Java.Lang.Object, ILocationListener
+ {
+ public GeolocationContinuousListener (LocationManager manager, TimeSpan timePeriod, IList providers)
+ {
+ this.manager = manager;
+ this.timePeriod = timePeriod;
+ this.providers = providers;
+
+ foreach (string p in providers)
+ {
+ if (manager.IsProviderEnabled (p))
+ this.activeProviders.Add (p);
+ }
+ }
+
+ public event EventHandler PositionError;
+ public event EventHandler PositionChanged;
+
+ public void OnLocationChanged (Location location)
+ {
+ if (location.Provider != this.activeProvider)
+ {
+ if (this.activeProvider != null && this.manager.IsProviderEnabled (this.activeProvider))
+ {
+ LocationProvider pr = this.manager.GetProvider (location.Provider);
+ TimeSpan lapsed = GetTimeSpan (location.Time) - GetTimeSpan (this.lastLocation.Time);
+
+ if (pr.Accuracy > this.manager.GetProvider (this.activeProvider).Accuracy
+ && lapsed < timePeriod.Add (timePeriod))
+ {
+ location.Dispose();
+ return;
+ }
+ }
+
+ this.activeProvider = location.Provider;
+ }
+
+ var previous = Interlocked.Exchange (ref this.lastLocation, location);
+ if (previous != null)
+ previous.Dispose();
+
+ var p = new Position();
+ if (location.HasAccuracy)
+ p.Accuracy = location.Accuracy;
+ if (location.HasAltitude)
+ p.Altitude = location.Altitude;
+ if (location.HasBearing)
+ p.Heading = location.Bearing;
+ if (location.HasSpeed)
+ p.Speed = location.Speed;
+
+ p.Longitude = location.Longitude;
+ p.Latitude = location.Latitude;
+ p.Timestamp = Geolocator.GetTimestamp (location);
+
+ var changed = PositionChanged;
+ if (changed != null)
+ changed (this, new PositionEventArgs (p));
+ }
+
+ public void OnProviderDisabled (string provider)
+ {
+ if (provider == LocationManager.PassiveProvider)
+ return;
+
+ lock (this.activeProviders)
+ {
+ if (this.activeProviders.Remove (provider) && this.activeProviders.Count == 0)
+ OnPositionError (new PositionErrorEventArgs (GeolocationError.PositionUnavailable));
+ }
+ }
+
+ public void OnProviderEnabled (string provider)
+ {
+ if (provider == LocationManager.PassiveProvider)
+ return;
+
+ lock (this.activeProviders)
+ this.activeProviders.Add (provider);
+ }
+
+ public void OnStatusChanged (string provider, Availability status, Bundle extras)
+ {
+ switch (status)
+ {
+ case Availability.Available:
+ OnProviderEnabled (provider);
+ break;
+
+ case Availability.OutOfService:
+ OnProviderDisabled (provider);
+ break;
+ }
+ }
+
+ private IList providers;
+ private readonly HashSet activeProviders = new HashSet();
+ private readonly LocationManager manager;
+
+ private string activeProvider;
+ private Location lastLocation;
+ private TimeSpan timePeriod;
+
+ private TimeSpan GetTimeSpan (long time)
+ {
+ return new TimeSpan (TimeSpan.TicksPerMillisecond * time);
+ }
+
+ private void OnPositionError (PositionErrorEventArgs e)
+ {
+ var error = PositionError;
+ if (error != null)
+ error (this, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Geolocation/GeolocationSingleListener.cs b/MonoDroid/Xamarin.Mobile/Geolocation/GeolocationSingleListener.cs
new file mode 100644
index 0000000..5faff00
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Geolocation/GeolocationSingleListener.cs
@@ -0,0 +1,139 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Threading.Tasks;
+using Android.Locations;
+using Android.OS;
+using System.Threading;
+using System.Collections.Generic;
+
+namespace Xamarin.Geolocation
+{
+ internal class GeolocationSingleListener
+ : Java.Lang.Object, ILocationListener
+ {
+ public GeolocationSingleListener (float desiredAccuracy, int timeout, IEnumerable activeProviders, Action finishedCallback)
+ {
+ this.desiredAccuracy = desiredAccuracy;
+ this.finishedCallback = finishedCallback;
+
+ this.activeProviders = new HashSet (activeProviders);
+
+ if (timeout != Timeout.Infinite)
+ this.timer = new Timer (TimesUp, null, timeout, 0);
+ }
+
+ public Task Task
+ {
+ get { return this.completionSource.Task; }
+ }
+
+ public void OnLocationChanged (Location location)
+ {
+ if (location.Accuracy <= this.desiredAccuracy)
+ {
+ Finish (location);
+ return;
+ }
+
+ lock (this.locationSync)
+ {
+ if (this.bestLocation == null || location.Accuracy <= this.bestLocation.Accuracy)
+ this.bestLocation = location;
+ }
+ }
+
+ public void OnProviderDisabled (string provider)
+ {
+ lock (this.activeProviders)
+ {
+ if (this.activeProviders.Remove (provider) && this.activeProviders.Count == 0)
+ this.completionSource.TrySetException (new GeolocationException (GeolocationError.PositionUnavailable));
+ }
+ }
+
+ public void OnProviderEnabled (string provider)
+ {
+ lock (this.activeProviders)
+ this.activeProviders.Add (provider);
+ }
+
+ public void OnStatusChanged (string provider, Availability status, Bundle extras)
+ {
+ switch (status)
+ {
+ case Availability.Available:
+ OnProviderEnabled (provider);
+ break;
+
+ case Availability.OutOfService:
+ OnProviderDisabled (provider);
+ break;
+ }
+ }
+
+ public void Cancel()
+ {
+ this.completionSource.TrySetCanceled();
+ }
+
+ private readonly object locationSync = new object();
+ private Location bestLocation;
+
+ private readonly Action finishedCallback;
+ private readonly float desiredAccuracy;
+ private readonly Timer timer;
+ private readonly TaskCompletionSource completionSource = new TaskCompletionSource();
+ private HashSet activeProviders = new HashSet();
+
+ private void TimesUp (object state)
+ {
+ lock (this.locationSync)
+ {
+ if (this.bestLocation == null)
+ {
+ if (this.completionSource.TrySetCanceled() && this.finishedCallback != null)
+ this.finishedCallback();
+ }
+ else
+ Finish (this.bestLocation);
+ }
+ }
+
+ private void Finish (Location location)
+ {
+ var p = new Position();
+ if (location.HasAccuracy)
+ p.Accuracy = location.Accuracy;
+ if (location.HasAltitude)
+ p.Altitude = location.Altitude;
+ if (location.HasBearing)
+ p.Heading = location.Bearing;
+ if (location.HasSpeed)
+ p.Speed = location.Speed;
+
+ p.Longitude = location.Longitude;
+ p.Latitude = location.Latitude;
+ p.Timestamp = Geolocator.GetTimestamp (location);
+
+ if (this.finishedCallback != null)
+ this.finishedCallback();
+
+ this.completionSource.TrySetResult (p);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Geolocation/Geolocator.cs b/MonoDroid/Xamarin.Mobile/Geolocation/Geolocator.cs
new file mode 100644
index 0000000..ba3dda5
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Geolocation/Geolocator.cs
@@ -0,0 +1,280 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Threading.Tasks;
+using Android.Locations;
+using System.Threading;
+using System.Collections.Generic;
+using Android.App;
+using Android.OS;
+using System.Linq;
+using Android.Content;
+
+namespace Xamarin.Geolocation
+{
+ public class Geolocator
+ {
+ public Geolocator (Context context)
+ {
+ if (context == null)
+ throw new ArgumentNullException ("context");
+
+ this.manager = (LocationManager)context.GetSystemService (Context.LocationService);
+ this.providers = manager.GetProviders (enabledOnly: false).Where (s => s != LocationManager.PassiveProvider).ToArray();
+ }
+
+ public event EventHandler PositionError;
+ public event EventHandler PositionChanged;
+
+ public bool IsListening
+ {
+ get { return this.listener != null; }
+ }
+
+ public double DesiredAccuracy
+ {
+ get;
+ set;
+ }
+
+ public bool SupportsHeading
+ {
+ get
+ {
+ return false;
+// if (this.headingProvider == null || !this.manager.IsProviderEnabled (this.headingProvider))
+// {
+// Criteria c = new Criteria { BearingRequired = true };
+// string providerName = this.manager.GetBestProvider (c, enabledOnly: false);
+//
+// LocationProvider provider = this.manager.GetProvider (providerName);
+//
+// if (provider.SupportsBearing())
+// {
+// this.headingProvider = providerName;
+// return true;
+// }
+// else
+// {
+// this.headingProvider = null;
+// return false;
+// }
+// }
+// else
+// return true;
+ }
+ }
+
+ public bool IsGeolocationAvailable
+ {
+ get { return this.providers.Length > 0; }
+ }
+
+ public bool IsGeolocationEnabled
+ {
+ get { return this.providers.Any (this.manager.IsProviderEnabled); }
+ }
+
+ public Task GetPositionAsync (CancellationToken cancelToken)
+ {
+ return GetPositionAsync (cancelToken, false);
+ }
+
+ public Task GetPositionAsync (CancellationToken cancelToken, bool includeHeading)
+ {
+ return GetPositionAsync (Timeout.Infinite, cancelToken);
+ }
+
+ public Task GetPositionAsync (int timeout)
+ {
+ return GetPositionAsync (timeout, false);
+ }
+
+ public Task GetPositionAsync (int timeout, bool includeHeading)
+ {
+ return GetPositionAsync (timeout, CancellationToken.None);
+ }
+
+ public Task GetPositionAsync (int timeout, CancellationToken cancelToken)
+ {
+ return GetPositionAsync (timeout, cancelToken, false);
+ }
+
+ public Task GetPositionAsync (int timeout, CancellationToken cancelToken, bool includeHeading)
+ {
+ if (timeout <= 0 && timeout != Timeout.Infinite)
+ throw new ArgumentOutOfRangeException ("timeout", "timeout must be greater than or equal to 0");
+
+ var tcs = new TaskCompletionSource();
+
+ if (!IsListening)
+ {
+ GeolocationSingleListener singleListener = null;
+ singleListener = new GeolocationSingleListener ((float)DesiredAccuracy, timeout, this.providers.Where (this.manager.IsProviderEnabled),
+ finishedCallback: () =>
+ {
+ for (int i = 0; i < this.providers.Length; ++i)
+ this.manager.RemoveUpdates (singleListener);
+ });
+
+ if (cancelToken != CancellationToken.None)
+ {
+ cancelToken.Register (() =>
+ {
+ singleListener.Cancel();
+
+ for (int i = 0; i < this.providers.Length; ++i)
+ this.manager.RemoveUpdates (singleListener);
+ }, true);
+ }
+
+ try
+ {
+ Looper looper = Looper.MyLooper() ?? Looper.MainLooper;
+
+ int enabled = 0;
+ for (int i = 0; i < this.providers.Length; ++i)
+ {
+ if (this.manager.IsProviderEnabled (this.providers[i]))
+ enabled++;
+
+ this.manager.RequestLocationUpdates (this.providers[i], 0, 0, singleListener, looper);
+ }
+
+ if (enabled == 0)
+ {
+ for (int i = 0; i < this.providers.Length; ++i)
+ this.manager.RemoveUpdates (singleListener);
+
+ tcs.SetException (new GeolocationException (GeolocationError.PositionUnavailable));
+ return tcs.Task;
+ }
+ }
+ catch (Java.Lang.SecurityException ex)
+ {
+ tcs.SetException (new GeolocationException (GeolocationError.Unauthorized, ex));
+ return tcs.Task;
+ }
+
+ return singleListener.Task;
+ }
+
+ // If we're already listening, just use the current listener
+ lock (this.positionSync)
+ {
+ if (this.lastPosition == null)
+ {
+ if (cancelToken != CancellationToken.None)
+ {
+ cancelToken.Register (() => tcs.TrySetCanceled());
+ }
+
+ EventHandler gotPosition = null;
+ gotPosition = (s, e) =>
+ {
+ tcs.TrySetResult (e.Position);
+ PositionChanged -= gotPosition;
+ };
+
+ PositionChanged += gotPosition;
+ }
+ else
+ {
+ tcs.SetResult (this.lastPosition);
+ }
+ }
+
+ return tcs.Task;
+ }
+
+ public void StartListening (int minTime, double minDistance)
+ {
+ StartListening (minTime, minDistance, false);
+ }
+
+ public void StartListening (int minTime, double minDistance, bool includeHeading)
+ {
+ if (minTime < 0)
+ throw new ArgumentOutOfRangeException ("minTime");
+ if (minDistance < 0)
+ throw new ArgumentOutOfRangeException ("minDistance");
+ if (IsListening)
+ throw new InvalidOperationException ("This Geolocator is already listening");
+
+ this.listener = new GeolocationContinuousListener (this.manager, TimeSpan.FromMilliseconds (minTime), this.providers);
+ this.listener.PositionChanged += OnListenerPositionChanged;
+ this.listener.PositionError += OnListenerPositionError;
+
+ Looper looper = Looper.MyLooper() ?? Looper.MainLooper;
+ for (int i = 0; i < this.providers.Length; ++i)
+ this.manager.RequestLocationUpdates (providers[i], minTime, (float)minDistance, listener, looper);
+ }
+
+ public void StopListening()
+ {
+ if (this.listener == null)
+ return;
+
+ this.listener.PositionChanged -= OnListenerPositionChanged;
+ this.listener.PositionError -= OnListenerPositionError;
+
+ for (int i = 0; i < this.providers.Length; ++i)
+ this.manager.RemoveUpdates (this.listener);
+
+ this.listener = null;
+ }
+
+ private readonly string[] providers;
+ private readonly LocationManager manager;
+ private string headingProvider;
+
+ private GeolocationContinuousListener listener;
+
+ private readonly object positionSync = new object();
+ private Position lastPosition;
+
+ private void OnListenerPositionChanged (object sender, PositionEventArgs e)
+ {
+ if (!IsListening) // ignore anything that might come in afterwards
+ return;
+
+ lock (this.positionSync)
+ {
+ this.lastPosition = e.Position;
+
+ var changed = PositionChanged;
+ if (changed != null)
+ changed (this, e);
+ }
+ }
+
+ private void OnListenerPositionError (object sender, PositionErrorEventArgs e)
+ {
+ StopListening();
+
+ var error = PositionError;
+ if (error != null)
+ error (this, e);
+ }
+
+ private static readonly DateTime Epoch = new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ internal static DateTimeOffset GetTimestamp (Location location)
+ {
+ return new DateTimeOffset (Epoch.AddMilliseconds (location.Time));
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/ITableFinder.cs b/MonoDroid/Xamarin.Mobile/ITableFinder.cs
new file mode 100644
index 0000000..99ac873
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/ITableFinder.cs
@@ -0,0 +1,70 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Text;
+using Uri = Android.Net.Uri;
+
+namespace Xamarin
+{
+ internal interface ITableFinder
+ {
+ ///
+ /// Gets the default table (content hierarchy root).
+ ///
+ Uri DefaultTable { get; }
+
+ TableFindResult Find (Expression expression);
+
+ ///
+ /// Gets whether the is a supported type for this finder.
+ ///
+ /// The type to check.
+ /// true if the is supported, false otherwise.
+ bool IsSupportedType (Type type);
+
+ ///
+ /// Gets the Android column name for the model's member.
+ ///
+ /// The for the model's member.
+ /// Android column name for the model's member, null if unknown.
+ ContentResolverColumnMapping GetColumn (MemberInfo memberInfo);
+ }
+
+ internal class TableFindResult
+ {
+ internal TableFindResult (Uri table, string mimeType)
+ {
+ Table = table;
+ MimeType = mimeType;
+ }
+
+ public Uri Table
+ {
+ get;
+ private set;
+ }
+
+ public string MimeType
+ {
+ get;
+ private set;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Media/MediaFile.cs b/MonoDroid/Xamarin.Mobile/Media/MediaFile.cs
new file mode 100644
index 0000000..ac6fee0
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Media/MediaFile.cs
@@ -0,0 +1,110 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Android.Content;
+using File = System.IO.File;
+using IOException = System.IO.IOException;
+
+namespace Xamarin.Media
+{
+ public static class MediaFileExtensions
+ {
+ public static Task GetMediaFileExtraAsync (this Intent self, Context context)
+ {
+ if (self == null)
+ throw new ArgumentNullException ("self");
+ if (context == null)
+ throw new ArgumentNullException ("context");
+
+ string action = self.GetStringExtra ("action");
+ if (action == null)
+ throw new ArgumentException ("Intent was not results from MediaPicker", "self");
+
+ var uri = (Android.Net.Uri)self.GetParcelableExtra (MediaFile.ExtraName);
+ bool isPhoto = self.GetBooleanExtra ("isPhoto", false);
+ var path = (Android.Net.Uri)self.GetParcelableExtra ("path");
+
+ return MediaPickerActivity.GetMediaFileAsync (context, 0, action, isPhoto, ref path, uri)
+ .ContinueWith (t => t.Result.ToTask()).Unwrap();
+ }
+ }
+
+ public sealed class MediaFile
+ : IDisposable
+ {
+ internal MediaFile (string path, bool deletePathOnDispose)
+ {
+ this.deletePathOnDispose = deletePathOnDispose;
+ this.path = path;
+ }
+
+ public string Path
+ {
+ get
+ {
+ if (this.isDisposed)
+ throw new ObjectDisposedException (null);
+
+ return this.path;
+ }
+ }
+
+ public Stream GetStream()
+ {
+ if (this.isDisposed)
+ throw new ObjectDisposedException (null);
+
+ return File.OpenRead (this.path);
+ }
+
+ public void Dispose()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+
+ private bool isDisposed;
+ private readonly bool deletePathOnDispose;
+ private readonly string path;
+
+ internal const string ExtraName = "MediaFile";
+
+ private void Dispose (bool disposing)
+ {
+ if (this.isDisposed)
+ return;
+
+ this.isDisposed = true;
+ if (this.deletePathOnDispose) {
+ try {
+ File.Delete (this.path);
+ // We don't really care if this explodes for a normal IO reason.
+ } catch (UnauthorizedAccessException) {
+ } catch (DirectoryNotFoundException) {
+ } catch (IOException) {
+ }
+ }
+ }
+
+ ~MediaFile()
+ {
+ Dispose (false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Media/MediaPicker.cs b/MonoDroid/Xamarin.Mobile/Media/MediaPicker.cs
new file mode 100644
index 0000000..8837f4c
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Media/MediaPicker.cs
@@ -0,0 +1,203 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Android.Content;
+using Android.Content.PM;
+using Android.OS;
+using Android.Provider;
+
+namespace Xamarin.Media
+{
+ public class MediaPicker
+ {
+ public MediaPicker (Context context)
+ {
+ if (context == null)
+ throw new ArgumentNullException ("context");
+
+ this.context = context;
+ IsCameraAvailable = context.PackageManager.HasSystemFeature (PackageManager.FeatureCamera);
+
+ if (Build.VERSION.SdkInt >= BuildVersionCodes.Gingerbread)
+ IsCameraAvailable |= context.PackageManager.HasSystemFeature (PackageManager.FeatureCameraFront);
+ }
+
+ public bool IsCameraAvailable
+ {
+ get;
+ private set;
+ }
+
+ public bool PhotosSupported
+ {
+ get { return true; }
+ }
+
+ public bool VideosSupported
+ {
+ get { return true; }
+ }
+
+ public Intent GetPickPhotoUI()
+ {
+ int id = GetRequestId();
+ return CreateMediaIntent (id, "image/*", Intent.ActionPick, null, tasked: false);
+ }
+
+ public Intent GetTakePhotoUI (StoreCameraMediaOptions options)
+ {
+ if (!IsCameraAvailable)
+ throw new NotSupportedException();
+
+ VerifyOptions (options);
+
+ int id = GetRequestId();
+ return CreateMediaIntent (id, "image/*", MediaStore.ActionImageCapture, options, tasked: false);
+ }
+
+ public Intent GetPickVideoUI()
+ {
+ int id = GetRequestId();
+ return CreateMediaIntent (id, "video/*", Intent.ActionPick, null, tasked: false);
+ }
+
+ public Intent GetTakeVideoUI (StoreVideoOptions options)
+ {
+ if (!IsCameraAvailable)
+ throw new NotSupportedException();
+
+ VerifyOptions (options);
+
+ return CreateMediaIntent (GetRequestId(), "video/*", MediaStore.ActionVideoCapture, options, tasked: false);
+ }
+
+ [Obsolete ("Use GetPickPhotoUI instead.")]
+ public Task PickPhotoAsync()
+ {
+ return TakeMediaAsync ("image/*", Intent.ActionPick, null);
+ }
+
+ [Obsolete ("Use GetTakePhotoUI instead.")]
+ public Task TakePhotoAsync (StoreCameraMediaOptions options)
+ {
+ if (!IsCameraAvailable)
+ throw new NotSupportedException();
+
+ VerifyOptions (options);
+
+ return TakeMediaAsync ("image/*", MediaStore.ActionImageCapture, options);
+ }
+
+ [Obsolete ("Use GetPickVideoUI instead.")]
+ public Task PickVideoAsync()
+ {
+ return TakeMediaAsync ("video/*", Intent.ActionPick, null);
+ }
+
+ [Obsolete ("use GetTakeVideoUI instead.")]
+ public Task TakeVideoAsync (StoreVideoOptions options)
+ {
+ if (!IsCameraAvailable)
+ throw new NotSupportedException();
+
+ VerifyOptions (options);
+
+ return TakeMediaAsync ("video/*", MediaStore.ActionVideoCapture, options);
+ }
+
+ private readonly Context context;
+ private int requestId;
+ private TaskCompletionSource completionSource;
+
+ private void VerifyOptions (StoreMediaOptions options)
+ {
+ if (options == null)
+ throw new ArgumentNullException ("options");
+ if (Path.IsPathRooted (options.Directory))
+ throw new ArgumentException ("options.Directory must be a relative path", "options");
+ }
+
+ private Intent CreateMediaIntent (int id, string type, string action, StoreMediaOptions options, bool tasked = true)
+ {
+ Intent pickerIntent = new Intent (this.context, typeof (MediaPickerActivity));
+ pickerIntent.PutExtra (MediaPickerActivity.ExtraId, id);
+ pickerIntent.PutExtra (MediaPickerActivity.ExtraType, type);
+ pickerIntent.PutExtra (MediaPickerActivity.ExtraAction, action);
+ pickerIntent.PutExtra (MediaPickerActivity.ExtraTasked, tasked);
+
+ if (options != null) {
+ pickerIntent.PutExtra (MediaPickerActivity.ExtraPath, options.Directory);
+ pickerIntent.PutExtra (MediaStore.Images.ImageColumns.Title, options.Name);
+
+ var vidOptions = (options as StoreVideoOptions);
+ if (vidOptions != null) {
+ pickerIntent.PutExtra (MediaStore.ExtraDurationLimit, (int)vidOptions.DesiredLength.TotalSeconds);
+ pickerIntent.PutExtra (MediaStore.ExtraVideoQuality, (int)vidOptions.Quality);
+ }
+ }
+
+ return pickerIntent;
+ }
+
+ private int GetRequestId()
+ {
+ int id = this.requestId;
+ if (this.requestId == Int32.MaxValue)
+ this.requestId = 0;
+ else
+ this.requestId++;
+
+ return id;
+ }
+
+ private Task TakeMediaAsync (string type, string action, StoreMediaOptions options)
+ {
+ int id = GetRequestId();
+
+ var ntcs = new TaskCompletionSource (id);
+ if (Interlocked.CompareExchange (ref this.completionSource, ntcs, null) != null)
+ throw new InvalidOperationException ("Only one operation can be active at a time");
+
+ this.context.StartActivity (CreateMediaIntent (id, type, action, options));
+
+ EventHandler handler = null;
+ handler = (s, e) =>
+ {
+ TaskCompletionSource tcs = Interlocked.Exchange (ref this.completionSource, null);
+
+ MediaPickerActivity.MediaPicked -= handler;
+
+ if (e.RequestId != id)
+ return;
+
+ if (e.Error != null)
+ tcs.SetException (e.Error);
+ else if (e.IsCanceled)
+ tcs.SetCanceled();
+ else
+ tcs.SetResult (e.Media);
+ };
+
+ MediaPickerActivity.MediaPicked += handler;
+
+ return ntcs.Task;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Media/MediaPickerActivity.cs b/MonoDroid/Xamarin.Mobile/Media/MediaPickerActivity.cs
new file mode 100644
index 0000000..b73f19f
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Media/MediaPickerActivity.cs
@@ -0,0 +1,451 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Android.App;
+using Android.Content;
+using Android.Database;
+using Android.OS;
+using Android.Provider;
+using Environment = Android.OS.Environment;
+using Path = System.IO.Path;
+using Uri = Android.Net.Uri;
+
+namespace Xamarin.Media
+{
+ [Activity]
+ internal class MediaPickerActivity
+ : Activity
+ {
+ internal const string ExtraPath = "path";
+ internal const string ExtraLocation = "location";
+ internal const string ExtraType = "type";
+ internal const string ExtraId = "id";
+ internal const string ExtraAction = "action";
+ internal const string ExtraTasked = "tasked";
+
+ internal static event EventHandler MediaPicked;
+
+ private int id;
+ private string title;
+ private string description;
+ private string type;
+
+ ///
+ /// The user's destination path.
+ ///
+ private Uri path;
+ private bool isPhoto;
+ private string action;
+
+ private int seconds;
+ private VideoQuality quality;
+
+ private bool tasked;
+
+ protected override void OnSaveInstanceState (Bundle outState)
+ {
+ outState.PutBoolean ("ran", true);
+ outState.PutString (MediaStore.MediaColumns.Title, this.title);
+ outState.PutString (MediaStore.Images.ImageColumns.Description, this.description);
+ outState.PutInt (ExtraId, this.id);
+ outState.PutString (ExtraType, this.type);
+ outState.PutString (ExtraAction, this.action);
+ outState.PutInt (MediaStore.ExtraDurationLimit, this.seconds);
+ outState.PutInt (MediaStore.ExtraVideoQuality, (int)this.quality);
+ outState.PutBoolean (ExtraTasked, this.tasked);
+
+ if (this.path != null)
+ outState.PutString (ExtraPath, this.path.Path);
+
+ base.OnSaveInstanceState (outState);
+ }
+
+ protected override void OnCreate (Bundle savedInstanceState)
+ {
+ base.OnCreate (savedInstanceState);
+
+ Bundle b = (savedInstanceState ?? Intent.Extras);
+
+ bool ran = b.GetBoolean ("ran", defaultValue: false);
+
+ this.title = b.GetString (MediaStore.MediaColumns.Title);
+ this.description = b.GetString (MediaStore.Images.ImageColumns.Description);
+
+ this.tasked = b.GetBoolean (ExtraTasked);
+ this.id = b.GetInt (ExtraId, 0);
+ this.type = b.GetString (ExtraType);
+ if (this.type == "image/*")
+ this.isPhoto = true;
+
+ this.action = b.GetString (ExtraAction);
+ Intent pickIntent = null;
+ try
+ {
+ pickIntent = new Intent (this.action);
+ if (this.action == Intent.ActionPick)
+ pickIntent.SetType (type);
+ else
+ {
+ if (!this.isPhoto)
+ {
+ this.seconds = b.GetInt (MediaStore.ExtraDurationLimit, 0);
+ if (this.seconds != 0)
+ pickIntent.PutExtra (MediaStore.ExtraDurationLimit, seconds);
+ }
+
+ this.quality = (VideoQuality)b.GetInt (MediaStore.ExtraVideoQuality, (int)VideoQuality.High);
+ pickIntent.PutExtra (MediaStore.ExtraVideoQuality, GetVideoQuality (this.quality));
+
+ if (!ran) {
+ this.path = GetOutputMediaFile (this, b.GetString (ExtraPath), this.title, this.isPhoto);
+
+ Touch();
+ pickIntent.PutExtra (MediaStore.ExtraOutput, this.path);
+ } else
+ this.path = Uri.Parse (b.GetString (ExtraPath));
+ }
+
+ if (!ran)
+ StartActivityForResult (pickIntent, this.id);
+ }
+ catch (Exception ex)
+ {
+ OnMediaPicked (new MediaPickedEventArgs (this.id, ex));
+ }
+ finally
+ {
+ if (pickIntent != null)
+ pickIntent.Dispose();
+ }
+ }
+
+ private void Touch()
+ {
+ if (this.path.Scheme != "file")
+ return;
+
+ File.Create (GetLocalPath (this.path)).Close();
+ }
+
+ internal static Task GetMediaFileAsync (Context context, int requestCode, string action, bool isPhoto, ref Uri path, Uri data)
+ {
+ Task> pathFuture;
+
+ string originalPath = null;
+
+ if (action != Intent.ActionPick) {
+ originalPath = path.Path;
+
+ // Not all camera apps respect EXTRA_OUTPUT, some will instead
+ // return a content or file uri from data.
+ if (data != null && data.Path != originalPath) {
+ originalPath = data.ToString();
+ string currentPath = path.Path;
+ pathFuture = TryMoveFileAsync (context, data, path, isPhoto).ContinueWith (t =>
+ new Tuple (t.Result ? currentPath : null, false));
+ } else
+ pathFuture = TaskFromResult (new Tuple (path.Path, false));
+ } else if (data != null) {
+ originalPath = data.ToString();
+ path = data;
+ pathFuture = GetFileForUriAsync (context, path, isPhoto);
+ } else
+ pathFuture = TaskFromResult> (null);
+
+ return pathFuture.ContinueWith (t => {
+ string resultPath = t.Result.Item1;
+ if (resultPath != null && File.Exists (t.Result.Item1)) {
+ var mf = new MediaFile (resultPath, deletePathOnDispose: t.Result.Item2);
+ return new MediaPickedEventArgs (requestCode, false, mf);
+ } else
+ return new MediaPickedEventArgs (requestCode, new MediaFileNotFoundException (originalPath));
+ });
+ }
+
+ protected override async void OnActivityResult (int requestCode, Result resultCode, Intent data)
+ {
+ base.OnActivityResult (requestCode, resultCode, data);
+
+ if (this.tasked) {
+ Task future;
+
+ if (resultCode == Result.Canceled) {
+ future = TaskFromResult(new MediaPickedEventArgs(requestCode, isCanceled: true));
+ Finish();
+ future.ContinueWith (t => OnMediaPicked (t.Result));
+ }
+ else{
+ //Handle android 5.1.1 as you now must access file on
+ //the same activity that launched it.
+ if ((int)Build.VERSION.SdkInt >= 22) {
+ var e = await GetMediaFileAsync(this, requestCode, this.action, this.isPhoto, ref this.path, (data != null) ? data.Data : null);
+ OnMediaPicked(e);
+ Finish();
+ }
+ else {
+ future = GetMediaFileAsync(this, requestCode, this.action, this.isPhoto, ref this.path, (data != null) ? data.Data : null);
+ Finish();
+ future.ContinueWith(t => OnMediaPicked(t.Result));
+ }
+ }
+ } else {
+ if (resultCode == Result.Canceled)
+ SetResult (Result.Canceled);
+ else {
+ Intent resultData = new Intent();
+ resultData.PutExtra (MediaFile.ExtraName, (data != null) ? data.Data : null);
+ resultData.PutExtra ("path", this.path);
+ resultData.PutExtra ("isPhoto", this.isPhoto);
+ resultData.PutExtra ("action", this.action);
+
+ SetResult (Result.Ok, resultData);
+ }
+
+ Finish();
+ }
+ }
+
+ private static Task TryMoveFileAsync (Context context, Uri url, Uri path, bool isPhoto)
+ {
+ string moveTo = GetLocalPath (path);
+ return GetFileForUriAsync (context, url, isPhoto).ContinueWith (t => {
+ if (t.Result.Item1 == null)
+ return false;
+
+ File.Delete (moveTo);
+ File.Move (t.Result.Item1, moveTo);
+
+ if (url.Scheme == "content")
+ context.ContentResolver.Delete (url, null, null);
+
+ return true;
+ }, TaskScheduler.Default);
+ }
+
+ private static int GetVideoQuality (VideoQuality videoQuality)
+ {
+ switch (videoQuality)
+ {
+ case VideoQuality.Medium:
+ case VideoQuality.High:
+ return 1;
+
+ default:
+ return 0;
+ }
+ }
+
+ private static string GetUniquePath (string folder, string name, bool isPhoto)
+ {
+ string ext = Path.GetExtension (name);
+ if (ext == String.Empty)
+ ext = ((isPhoto) ? ".jpg" : ".mp4");
+
+ name = Path.GetFileNameWithoutExtension (name);
+
+ string nname = name + ext;
+ int i = 1;
+ while (File.Exists (Path.Combine (folder, nname)))
+ nname = name + "_" + (i++) + ext;
+
+ return Path.Combine (folder, nname);
+ }
+
+ private static Uri GetOutputMediaFile (Context context, string subdir, string name, bool isPhoto)
+ {
+ subdir = subdir ?? String.Empty;
+
+ if (String.IsNullOrWhiteSpace (name))
+ {
+ string timestamp = DateTime.Now.ToString ("yyyyMMdd_HHmmss");
+ if (isPhoto)
+ name = "IMG_" + timestamp + ".jpg";
+ else
+ name = "VID_" + timestamp + ".mp4";
+ }
+
+ string mediaType = (isPhoto) ? Environment.DirectoryPictures : Environment.DirectoryMovies;
+ using (Java.IO.File mediaStorageDir = new Java.IO.File (context.GetExternalFilesDir (mediaType), subdir))
+ {
+ if (!mediaStorageDir.Exists())
+ {
+ if (!mediaStorageDir.Mkdirs())
+ throw new IOException ("Couldn't create directory, have you added the WRITE_EXTERNAL_STORAGE permission?");
+
+ // Ensure this media doesn't show up in gallery apps
+ using (Java.IO.File nomedia = new Java.IO.File (mediaStorageDir, ".nomedia"))
+ nomedia.CreateNewFile();
+ }
+
+ return Uri.FromFile (new Java.IO.File (GetUniquePath (mediaStorageDir.Path, name, isPhoto)));
+ }
+ }
+
+ internal static Task> GetFileForUriAsync (Context context, Uri uri, bool isPhoto)
+ {
+ var tcs = new TaskCompletionSource>();
+
+ if (uri.Scheme == "file")
+ tcs.SetResult (new Tuple (new System.Uri (uri.ToString()).LocalPath, false));
+ else if (uri.Scheme == "content")
+ {
+ Task.Factory.StartNew (() =>
+ {
+ ICursor cursor = null;
+ try
+ {
+ string contentPath = null;
+ try {
+ string[] proj = null;
+ //Android 5.1.1 requires projection
+ if((int)Build.VERSION.SdkInt >= 22)
+ proj = new[] { MediaStore.MediaColumns.Data };
+ cursor = context.ContentResolver.Query (uri, proj, null, null, null);
+ } catch (Exception) {
+ }
+ if (cursor != null && cursor.MoveToNext()) {
+ int column = cursor.GetColumnIndex (MediaStore.MediaColumns.Data);
+ if (column != -1)
+ contentPath = cursor.GetString (column);
+ }
+
+ bool copied = false;
+
+ // If they don't follow the "rules", try to copy the file locally
+ if (contentPath == null || !contentPath.StartsWith ("file"))
+ {
+ copied = true;
+ Uri outputPath = GetOutputMediaFile (context, "temp", null, isPhoto);
+
+ try
+ {
+ using (Stream input = context.ContentResolver.OpenInputStream (uri))
+ using (Stream output = File.Create (outputPath.Path))
+ input.CopyTo (output);
+
+ contentPath = outputPath.Path;
+ }
+ catch (Exception)
+ {
+ // If there's no data associated with the uri, we don't know
+ // how to open this. contentPath will be null which will trigger
+ // MediaFileNotFoundException.
+ }
+ }
+
+ tcs.SetResult (new Tuple (contentPath, copied));
+ }
+ finally
+ {
+ if (cursor != null)
+ {
+ cursor.Close();
+ cursor.Dispose();
+ }
+ }
+ }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
+ }
+ else
+ tcs.SetResult (new Tuple (null, false));
+
+ return tcs.Task;
+ }
+
+ private static string GetLocalPath (Uri uri)
+ {
+ return new System.Uri (uri.ToString()).LocalPath;
+ }
+
+ private static Task TaskFromResult (T result)
+ {
+ var tcs = new TaskCompletionSource();
+ tcs.SetResult (result);
+ return tcs.Task;
+ }
+
+ private static void OnMediaPicked (MediaPickedEventArgs e)
+ {
+ var picked = MediaPicked;
+ if (picked != null)
+ picked (null, e);
+ }
+ }
+
+ internal class MediaPickedEventArgs
+ : EventArgs
+ {
+ public MediaPickedEventArgs (int id, Exception error)
+ {
+ if (error == null)
+ throw new ArgumentNullException ("error");
+
+ RequestId = id;
+ Error = error;
+ }
+
+ public MediaPickedEventArgs (int id, bool isCanceled, MediaFile media = null)
+ {
+ RequestId = id;
+ IsCanceled = isCanceled;
+ if (!IsCanceled && media == null)
+ throw new ArgumentNullException ("media");
+
+ Media = media;
+ }
+
+ public int RequestId
+ {
+ get;
+ private set;
+ }
+
+ public bool IsCanceled
+ {
+ get;
+ private set;
+ }
+
+ public Exception Error
+ {
+ get;
+ private set;
+ }
+
+ public MediaFile Media
+ {
+ get;
+ private set;
+ }
+
+ public Task ToTask()
+ {
+ var tcs = new TaskCompletionSource();
+
+ if (IsCanceled)
+ tcs.SetCanceled();
+ else if (Error != null)
+ tcs.SetException (Error);
+ else
+ tcs.SetResult (Media);
+
+ return tcs.Task;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/MemberExpressionFinder.cs b/MonoDroid/Xamarin.Mobile/MemberExpressionFinder.cs
new file mode 100644
index 0000000..2ce2fa1
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/MemberExpressionFinder.cs
@@ -0,0 +1,58 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace Xamarin
+{
+ internal class MemberExpressionFinder
+ : ExpressionVisitor
+ {
+ internal MemberExpressionFinder (ITableFinder tableFinder)
+ {
+ if (tableFinder == null)
+ throw new ArgumentNullException ("tableFinder");
+
+ this.tableFinder = tableFinder;
+ }
+
+ private readonly List expressions = new List();
+ private readonly ITableFinder tableFinder;
+
+ protected override Expression VisitMemberAccess (MemberExpression member)
+ {
+ if (this.tableFinder.IsSupportedType (member.Member.DeclaringType))
+ this.expressions.Add (member);
+
+ return base.VisitMemberAccess (member);
+ }
+
+ internal static List Find (Expression expression, ITableFinder tableFinder)
+ {
+ if (expression == null)
+ throw new ArgumentNullException ("expression");
+ if (tableFinder == null)
+ throw new ArgumentNullException ("tableFinder");
+
+ var finder = new MemberExpressionFinder (tableFinder);
+ finder.Visit (expression);
+
+ return finder.expressions;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/MultiProjectionReader.cs b/MonoDroid/Xamarin.Mobile/MultiProjectionReader.cs
new file mode 100644
index 0000000..6ea02f3
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/MultiProjectionReader.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using Android.Content;
+using Android.Database;
+
+namespace Xamarin
+{
+ internal class MultiProjectionReader
+ : IEnumerable
+ {
+ internal MultiProjectionReader (ContentResolver content, ContentQueryTranslator translator)
+ {
+ this.content = content;
+ this.translator = translator;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ ContentResolverColumnMapping[] projections = translator.Projections.ToArray();
+
+ ICursor cursor = null;
+ try
+ {
+ cursor = this.content.Query (translator.Table, projections.Select (s => s.Item1).ToArray(), translator.QueryString,
+ translator.ClauseParameters, translator.SortString);
+
+ while (cursor.MoveToNext())
+ {
+ object[] values = new object[projections.Length];
+ for (int i = 0; i < projections.Length; ++i)
+ {
+ int index = cursor.GetColumnIndex (projections[i].Item1);
+
+ Type t = projections[i].Item2;
+ if (t == typeof(string))
+ values[i] = cursor.GetString (index);
+ else if (t == typeof(int))
+ values[i] = cursor.GetInt (index);
+
+ yield return values;
+ }
+ }
+ }
+ finally
+ {
+ if (cursor != null)
+ cursor.Close();
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ private readonly ContentResolver content;
+ private readonly ContentQueryTranslator translator;
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/ProjectionReader.cs b/MonoDroid/Xamarin.Mobile/ProjectionReader.cs
new file mode 100644
index 0000000..8403ae9
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/ProjectionReader.cs
@@ -0,0 +1,79 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using Android.Content;
+using Android.Database;
+
+namespace Xamarin
+{
+ internal class ProjectionReader
+ : IEnumerable
+ {
+ internal ProjectionReader (ContentResolver content, ContentQueryTranslator translator, Func selector)
+ {
+ this.content = content;
+ this.translator = translator;
+ this.selector = selector;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ string[] projections = null;
+ if (this.translator.Projections != null)
+ {
+ projections = this.translator.Projections
+ .Where (p => p.Columns != null)
+ .SelectMany (t => t.Columns)
+ .ToArray();
+
+ if (projections.Length == 0)
+ projections = null;
+ }
+
+ ICursor cursor = null;
+ try
+ {
+
+ cursor = content.Query (translator.Table, projections,
+ translator.QueryString, translator.ClauseParameters, translator.SortString);
+
+ while (cursor.MoveToNext())
+ {
+ int colIndex = cursor.GetColumnIndex (projections[0]);
+ yield return this.selector (cursor, colIndex);
+ }
+ }
+ finally
+ {
+ if (cursor != null)
+ cursor.Close();
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ private readonly ContentResolver content;
+ private readonly ContentQueryTranslator translator;
+ private readonly Func selector;
+ }
+}
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Properties/AssemblyInfo.cs b/MonoDroid/Xamarin.Mobile/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f842c7c
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Properties/AssemblyInfo.cs
@@ -0,0 +1,31 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Xamarin.Mobile")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Xamarin Inc.")]
+[assembly: AssemblyProduct("Xamarin.Mobile")]
+[assembly: AssemblyCopyright("Copyright © 2011-2014 Xamarin Inc.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.7.1.0")]
+[assembly: AssemblyFileVersion("0.7.1.0")]
+
+[assembly: InternalsVisibleTo("Xamarin.Mobile.Android.Tests")]
\ No newline at end of file
diff --git a/MonoDroid/Xamarin.Mobile/Xamarin.Mobile.Android.csproj b/MonoDroid/Xamarin.Mobile/Xamarin.Mobile.Android.csproj
new file mode 100644
index 0000000..aafd412
--- /dev/null
+++ b/MonoDroid/Xamarin.Mobile/Xamarin.Mobile.Android.csproj
@@ -0,0 +1,126 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {32DFF77E-AE38-48D6-B067-CF555798EA32}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Properties
+ Xamarin
+ Xamarin.Mobile
+ 512
+ armeabi
+
+
+ v2.3
+
+
+ true
+ bin\Release\
+ AnyCPU
+ false
+ false
+ true
+ full
+ false
+ 4
+
+
+ true
+ TRACE;DEBUG
+ bin\Debug\
+ full
+ None
+ 4
+ false
+ False
+
+
+
+
+
+
+
+
+
+
+
+ Contacts\Address.cs
+
+
+ Contacts\Email.cs
+
+
+ Contacts\InstantMessangingAccount.cs
+
+
+ Contacts\Note.cs
+
+
+ Contacts\Organization.cs
+
+
+ Contacts\Phone.cs
+
+
+ Contacts\Relationship.cs
+
+
+ Contacts\Website.cs
+
+
+ EvaluationNominator.cs
+
+
+ ExpressionEvaluator.cs
+
+
+ ExpressionVisitor.cs
+
+
+ Media\MediaFileNotFoundException.cs
+
+
+ Media\StoreMediaOptions.cs
+
+
+ Geolocation\Position.cs
+
+
+ Query.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MonoTouch/MonoMobile.Extensions/Camera.cs b/MonoTouch/MonoMobile.Extensions/Camera.cs
deleted file mode 100644
index b34cabb..0000000
--- a/MonoTouch/MonoMobile.Extensions/Camera.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using System;
-using MonoTouch.UIKit;
-using MonoTouch.Foundation;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Diagnostics;
-
-namespace MonoMobile.Extensions
-{
- public class Camera
- {
- public class CameraOptions
- {
- // Set up Camera Option defaults
- public UIImagePickerControllerSourceType SourceType = UIImagePickerControllerSourceType.Camera;
- public bool AllowEdit = false;
- public int Quality = 100;
- public DestinationType Destination = DestinationType.FileUri;
- }
-
- public enum DestinationType
- {
- // Might want to add a destination type of Object and return UIImage?
- FileUri,
- DataUri
- }
-
- public Camera (UIViewController currentViewController)
- {
- viewController = currentViewController;
- }
-
- UIViewController viewController;
- UIImagePickerController pickerController;
-
- public void GetPicture(CameraOptions options, Action successCallback, Action errorCallback)
- {
- if(options == null)
- options = new CameraOptions();
-
- if(!UIImagePickerController.IsSourceTypeAvailable(options.SourceType))
- {
- Debug.WriteLine ("Source type {0} isn't available.", options.SourceType);
- return;
- }
-
- pickerController = new UIImagePickerController();
-
- pickerController.AllowsEditing = options.AllowEdit;
- pickerController.SourceType = options.SourceType;
-
- pickerController.FinishedPickingMedia += delegate(object sender, UIImagePickerMediaPickedEventArgs e) {
-
- pickerController.DismissModalViewControllerAnimated(true);
-
- float quality = options.Quality / 100.0f;
-
- var mediaType = (NSString) e.Info[new NSString("UIImagePickerControllerMediaType")];
- if(mediaType == "public.image")
- {
- // Get the image
- UIImage image = null;
- if(pickerController.AllowsEditing && e.Info[new NSString("UIImagePickerControllerEditedImage")] != null)
- image = (UIImage) e.Info[new NSString("UIImagePickerControllerEditedImage")];
- else
- image = (UIImage) e.Info[new NSString("UIImagePickerControllerOriginalImage")];
-
- var data = image.AsJPEG(quality);
-
- if(options.Destination == DestinationType.FileUri)
- {
- var basedir = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), "..");
- var tmpDirectory = Path.Combine(basedir, "tmp");
-
- if (!Directory.Exists(tmpDirectory))
- Directory.CreateDirectory(tmpDirectory);
-
- string filePath;
- int i = 1;
- do {
- filePath = String.Format("{0}/photo_{1}.jpg", tmpDirectory, i++);
- }
- while (File.Exists(filePath));
-
- NSError error = null;
- if(!data.Save(filePath, false, out error))
- {
- Debug.WriteLine ("Error {0}", error.LocalizedDescription);
- errorCallback();
- }
- else
- successCallback(filePath);
- }
- else
- {
- var bytearray = new Byte[data.Length];
- Marshal.Copy(data.Bytes, bytearray, 0, Convert.ToInt32(data.Length));
- successCallback(Convert.ToBase64String(bytearray));
- }
- }
- };
-
- pickerController.Canceled += delegate(object sender, EventArgs e) {
- pickerController.DismissModalViewControllerAnimated(true);
- errorCallback();
- };
-
- viewController.PresentModalViewController(pickerController, true);
-
- }
- }
-}
-
diff --git a/MonoTouch/MonoMobile.Extensions/Device.cs b/MonoTouch/MonoMobile.Extensions/Device.cs
deleted file mode 100644
index 0f4fb9e..0000000
--- a/MonoTouch/MonoMobile.Extensions/Device.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using MonoTouch.UIKit;
-namespace MonoMobile.Extensions
-{
- public class Device
- {
- public Device ()
- {
- }
-
- public string Name
- {
- get { return UIDevice.CurrentDevice.Name; }
- }
-
- public string MonoMobileVersion
- {
- get { return ExtensionHelper.MonoMobile; }
- }
-
- public string Platform
- {
- get { return UIDevice.CurrentDevice.Model; }
- }
-
- public string UUID
- {
- get { return UIDevice.CurrentDevice.UniqueIdentifier; }
- }
-
- public string Version
- {
- get { return UIDevice.CurrentDevice.SystemVersion; }
- }
- }
-}
-
diff --git a/MonoTouch/MonoMobile.Extensions/Geolocation.cs b/MonoTouch/MonoMobile.Extensions/Geolocation.cs
deleted file mode 100644
index 62b8726..0000000
--- a/MonoTouch/MonoMobile.Extensions/Geolocation.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-
-namespace MonoMobile.Extensions
-{
- public class Geolocation : IGeolocation
- {
- public void GetCurrentPosition (Action success)
- {
- throw new NotImplementedException ();
- }
-
- public void GetCurrentPosition (Action success, Action error)
- {
- throw new NotImplementedException ();
- }
-
- public void GetCurrentPosition (Action success, Action error, GeolocationOptions options)
- {
- throw new NotImplementedException ();
- }
-
- public string WatchPosition (Action success)
- {
- throw new NotImplementedException ();
- }
-
- public string WatchPosition (Action success, Action error)
- {
- throw new NotImplementedException ();
- }
-
- public string WatchPosition (Action success, Action error, GeolocationOptions options)
- {
- throw new NotImplementedException ();
- }
-
- public void ClearWatch (string watchID)
- {
- throw new NotImplementedException ();
- }
- }
-}
\ No newline at end of file
diff --git a/MonoTouch/MonoMobile.Extensions/MonoMobile.Extensions.csproj b/MonoTouch/MonoMobile.Extensions/MonoMobile.Extensions.csproj
deleted file mode 100644
index b129e66..0000000
--- a/MonoTouch/MonoMobile.Extensions/MonoMobile.Extensions.csproj
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
-
- Debug
- iPhoneSimulator
- 10.0.0
- 2.0
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}
- {E613F3A2-FE9C-494F-B74E-F63BCB86FEA6};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Library
- MonoMobile.Extensions
- MonoMobileExtensions
- 3.0
- v3.5
-
-
- true
- full
- false
- bin\iPhoneSimulator\Debug
- DEBUG
- prompt
- 4
- false
- None
- True
- false
- false
- false
- false
-
-
- none
- false
- bin\iPhoneSimulator\Release
- prompt
- 4
- False
- false
- None
- false
- false
- false
- false
-
-
- true
- full
- false
- bin\iPhone\Debug
- DEBUG
- prompt
- 4
- false
- iPhone Developer
- True
- false
- false
- false
- false
-
-
- none
- false
- bin\iPhone\Release
- prompt
- 4
- False
- false
- iPhone Developer
- false
- false
- false
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ExtensionHelper.cs
-
-
- IDevice.cs
-
-
- IGeolocation.cs
-
-
- INotification.cs
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/MonoTouch/MonoMobile.Extensions/Notification.cs b/MonoTouch/MonoMobile.Extensions/Notification.cs
deleted file mode 100644
index 901c2c3..0000000
--- a/MonoTouch/MonoMobile.Extensions/Notification.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using System;
-using MonoTouch.UIKit;
-using MonoTouch.AudioToolbox;
-namespace MonoMobile.Extensions
-{
- public class Notification
- {
- public Notification ()
- {
- }
-
- public void Alert (string message, Action alertCallback)
- {
- Alert(message, alertCallback, "Alert", "OK");
- }
-
- public void Alert (string message, Action alertCallback, string title)
- {
- Alert(message, alertCallback, title, "OK");
- }
-
- public void Alert (string message, Action alertCallback, string title, string buttonName)
- {
- using(var alertView = new UIAlertView(title, message, null, buttonName, null))
- {
- alertView.Show();
- alertView.Dismissed += delegate(object sender, UIButtonEventArgs e) {
- if(alertCallback != null)
- alertCallback();
- };
- }
- }
-
- public void Confirm (string message, Action confirmCallback)
- {
-
- Confirm(message, confirmCallback, "Alert", "OK");
- }
-
- public void Confirm (string message, Action confirmCallback, string title)
- {
- Confirm(message, confirmCallback, title, "OK");
- }
-
- public void Confirm (string message, Action confirmCallback, string title, string buttonLabels)
- {
- using(var alertView = new UIAlertView(title, message, null, null, null))
- {
- var labels = buttonLabels.Split(new Char[]{','});
- foreach(var label in labels)
- {
- alertView.AddButton(label);
- }
- alertView.Show();
- alertView.Clicked += delegate(object sender, UIButtonEventArgs e) {
- if(confirmCallback != null)
- confirmCallback(e.ButtonIndex);
- };
- }
- }
-
- public void Beep ()
- {
- var beep = SystemSound.FromFile("beep.wav");
- beep.PlaySystemSound();
- }
-
- public void Beep (int times)
- {
- Beep();
- }
-
- public void Vibrate ()
- {
- SystemSound.Vibrate.PlaySystemSound();
- }
-
- public void Vibrate (int milliseconds)
- {
- Vibrate();
- }
- }
-}
-
diff --git a/MonoTouch/MonoMobile.ExtensionsMonoTouch.sln b/MonoTouch/MonoMobile.ExtensionsMonoTouch.sln
deleted file mode 100644
index 208361e..0000000
--- a/MonoTouch/MonoMobile.ExtensionsMonoTouch.sln
+++ /dev/null
@@ -1,53 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{21B17BB4-06C1-4E6E-BD78-C022CD8F8266}"
- ProjectSection(SolutionItems) = preProject
- ..\Shared\ExtensionHelper.cs = ..\Shared\ExtensionHelper.cs
- ..\Shared\IDevice.cs = ..\Shared\IDevice.cs
- ..\Shared\IGeolocation.cs = ..\Shared\IGeolocation.cs
- ..\Shared\INotification.cs = ..\Shared\INotification.cs
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MonoTouch", "MonoTouch", "{8A4D3352-DBA8-4BE4-B66C-2BF4A538C725}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoMobile.Extensions", "MonoMobile.Extensions\MonoMobile.Extensions.csproj", "{87C4E91E-8215-46E6-BC21-41650EEB8C92}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoTouch.Example", "MonoTouch.Example\MonoTouch.Example.csproj", "{EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|iPhoneSimulator = Debug|iPhoneSimulator
- Release|iPhoneSimulator = Release|iPhoneSimulator
- Debug|iPhone = Debug|iPhone
- Release|iPhone = Release|iPhone
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhone.ActiveCfg = Debug|iPhone
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhone.Build.0 = Debug|iPhone
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhone.ActiveCfg = Release|iPhone
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhone.Build.0 = Release|iPhone
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
- {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}.Debug|iPhone.ActiveCfg = Debug|iPhone
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}.Debug|iPhone.Build.0 = Debug|iPhone
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}.Release|iPhone.ActiveCfg = Release|iPhone
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}.Release|iPhone.Build.0 = Release|iPhone
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {87C4E91E-8215-46E6-BC21-41650EEB8C92} = {8A4D3352-DBA8-4BE4-B66C-2BF4A538C725}
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB} = {8A4D3352-DBA8-4BE4-B66C-2BF4A538C725}
- EndGlobalSection
- GlobalSection(MonoDevelopProperties) = preSolution
- StartupItem = MonoTouch.Example\MonoTouch.Example.csproj
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/MonoTouch/MonoTouch.Example/ExampleList.xib b/MonoTouch/MonoTouch.Example/ExampleList.xib
deleted file mode 100644
index 3982a80..0000000
--- a/MonoTouch/MonoTouch.Example/ExampleList.xib
+++ /dev/null
@@ -1,154 +0,0 @@
-
-
-
- 768
- 9L30
- 677
- 949.54
- 353.00
-
- YES
-
-
-
- YES
- com.apple.InterfaceBuilder.IBCocoaTouchPlugin
-
-
- YES
-
- YES
-
-
- YES
-
-
-
- YES
-
- IBFilesOwner
-
-
- IBFirstResponder
-
-
-
- 292
- {320, 460}
-
-
- 3
- MQA
-
- 2
-
-
-
-
-
-
-
- YES
-
-
- view
-
-
-
- 7
-
-
-
-
- YES
-
- 0
-
- YES
-
-
-
-
-
- 1
-
-
- YES
-
-
-
-
- -1
-
-
- RmlsZSdzIE93bmVyA
-
-
- -2
-
-
-
-
-
-
- YES
-
- YES
- -1.CustomClassName
- -2.CustomClassName
- 1.IBEditorWindowLastContentRect
- 1.IBPluginDependency
-
-
- YES
- ExampleList
- UIResponder
- {{357, 275}, {320, 480}}
- com.apple.InterfaceBuilder.IBCocoaTouchPlugin
-
-
-
- YES
-
- YES
-
-
- YES
-
-
-
-
- YES
-
- YES
-
-
- YES
-
-
-
- 7
-
-
-
- YES
-
- ExampleList
-
- view
- id
-
-
- IBUserSource
-
-
-
-
-
- 0
-
- 3
- 3.0
-
-
-
diff --git a/MonoTouch/MonoTouch.Example/ExampleList.xib.cs b/MonoTouch/MonoTouch.Example/ExampleList.xib.cs
deleted file mode 100644
index 315b44c..0000000
--- a/MonoTouch/MonoTouch.Example/ExampleList.xib.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using MonoTouch.Foundation;
-using MonoTouch.UIKit;
-using MonoMobile.Extensions;
-
-namespace MonoTouch.Example
-{
- public partial class ExampleList : UIViewController
- {
- #region Constructors
-
- // The IntPtr and initWithCoder constructors are required for items that need
- // to be able to be created from a xib rather than from managed code
-
- public ExampleList (IntPtr handle) : base(handle)
- {
- Initialize ();
- }
-
- [Export("initWithCoder:")]
- public ExampleList (NSCoder coder) : base(coder)
- {
- Initialize ();
- }
-
- public ExampleList () : base("ExampleList", null)
- {
- Initialize ();
- }
-
- void Initialize ()
- {
- }
-
- #endregion
-
- UIButton alertButton, confirmButton, beepButton, vibrateButton, cameraButton;
-
- public override void ViewDidLoad ()
- {
- base.ViewDidLoad ();
-
- var notification = new Notification();
- alertButton = UIButton.FromType(UIButtonType.RoundedRect);
- alertButton.Frame = new System.Drawing.RectangleF(40f, 20f, 200f, 40f);
- alertButton.SetTitle("Alert button", UIControlState.Normal);
- alertButton.TouchUpInside += (s, e) => {
- notification.Alert("My Message", () => {
- Console.WriteLine ("Dismissed");
- }, "Title", "OK");
- };
- this.View.AddSubview(alertButton);
-
- confirmButton = UIButton.FromType(UIButtonType.RoundedRect);
- confirmButton.Frame = new System.Drawing.RectangleF(40f, 60f, 200f, 40f);
- confirmButton.SetTitle("Confirm button", UIControlState.Normal);
- confirmButton.TouchUpInside += (s, e) => {
- notification.Confirm("My Message", (i) => {
- Console.WriteLine ("Button {0} pressed", i);
- }, "Alert!", "One, Two, Cancelled");
- };
- this.View.AddSubview(confirmButton);
-
- beepButton = UIButton.FromType(UIButtonType.RoundedRect);
- beepButton.Frame = new System.Drawing.RectangleF(40f, 100f, 200f, 40f);
- beepButton.SetTitle("Beep!", UIControlState.Normal);
- beepButton.TouchUpInside += (s, e) => {
- // Beep overload just calls beep anyway due to iPhone limitation.
- // Make sure there's a beep.wav set as content in the root of the app.
- notification.Beep();
- };
- this.View.AddSubview(beepButton);
-
-
- vibrateButton = UIButton.FromType(UIButtonType.RoundedRect);
- vibrateButton.Frame = new System.Drawing.RectangleF(40f, 140f, 200f, 40f);
- vibrateButton.SetTitle("Vibrate!", UIControlState.Normal);
- vibrateButton.TouchUpInside += (s, e) => {
- // Vibrate overload just calls vibrate anyway due to iPhone limitation.
- notification.Vibrate();
- };
- this.View.AddSubview(vibrateButton);
-
- var camera = new Camera(this);
- cameraButton = UIButton.FromType(UIButtonType.RoundedRect);
- cameraButton.Frame = new System.Drawing.RectangleF(40f, 180f, 200f, 40f);
- cameraButton.SetTitle("Get Picture!", UIControlState.Normal);
- cameraButton.TouchUpInside += (s, e) => {
- // Vibrate overload just calls vibrate anyway due to iPhone limitation.
- camera.GetPicture(new Camera.CameraOptions() { SourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum },
- (p) => { Console.WriteLine ("Got picture as {0}", p);},
- () => { Console.WriteLine ("Cancelled"); }
- );
- };
- this.View.AddSubview(cameraButton);
- }
- }
-}
-
diff --git a/MonoTouch/MonoTouch.Example/ExampleList.xib.designer.cs b/MonoTouch/MonoTouch.Example/ExampleList.xib.designer.cs
deleted file mode 100644
index 7ac5bdd..0000000
--- a/MonoTouch/MonoTouch.Example/ExampleList.xib.designer.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-
-// ------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Mono Runtime Version: 2.0.50727.1433
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-// ------------------------------------------------------------------------------
-
-namespace MonoTouch.Example
-{
- // Base type probably should be MonoTouch.UIKit.UIViewController or subclass
- [MonoTouch.Foundation.Register("ExampleList")]
- public partial class ExampleList
- {
-
- private MonoTouch.UIKit.UIView __mt_view;
-
- [MonoTouch.Foundation.Connect("view")]
- private MonoTouch.UIKit.UIView view {
- get {
- this.__mt_view = ((MonoTouch.UIKit.UIView)(this.GetNativeField ("view")));
- return this.__mt_view;
- }
- set {
- this.__mt_view = value;
- this.SetNativeField ("view", value);
- }
- }
- }
-}
-
diff --git a/MonoTouch/MonoTouch.Example/Info.plist b/MonoTouch/MonoTouch.Example/Info.plist
deleted file mode 100644
index 48f7943..0000000
--- a/MonoTouch/MonoTouch.Example/Info.plist
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
-
-
diff --git a/MonoTouch/MonoTouch.Example/Main.cs b/MonoTouch/MonoTouch.Example/Main.cs
deleted file mode 100644
index 5344a71..0000000
--- a/MonoTouch/MonoTouch.Example/Main.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using MonoTouch.Foundation;
-using MonoTouch.UIKit;
-using MonoMobile.Extensions;
-
-namespace MonoTouch.Example
-{
- public class Application
- {
- static void Main (string[] args)
- {
- UIApplication.Main (args);
- }
- }
-
- // The name AppDelegate is referenced in the MainWindow.xib file.
- public partial class AppDelegate : UIApplicationDelegate
- {
- UIViewController exampleList;
- // This method is invoked when the application has loaded its UI and its ready to run
- public override bool FinishedLaunching (UIApplication app, NSDictionary options)
- {
- // If you have defined a view, add it here:
- // window.AddSubview (navigationController.View);
-
- var device = new Device();
- Console.WriteLine ("Device Name: {0}", device.Name);
- Console.WriteLine ("Device Platform: {0}", device.Platform);
- Console.WriteLine ("Device UUID: {0}", device.UUID);
- Console.WriteLine ("Device Version: {0}", device.Version);
- Console.WriteLine ("MonoMobile Version: {0}", device.MonoMobileVersion);
-
- exampleList = new ExampleList();
-
- window.AddSubview(exampleList.View);
-
- window.MakeKeyAndVisible ();
-
- return true;
- }
-
- // This method is required in iPhoneOS 3.0
- public override void OnActivated (UIApplication application)
- {
- }
- }
-}
-
diff --git a/MonoTouch/MonoTouch.Example/MainWindow.xib b/MonoTouch/MonoTouch.Example/MainWindow.xib
deleted file mode 100644
index 83a288f..0000000
--- a/MonoTouch/MonoTouch.Example/MainWindow.xib
+++ /dev/null
@@ -1,184 +0,0 @@
-
-
-
- 768
- 9J61
- 677
- 949.46
- 353.00
-
- YES
-
-
-
- YES
- com.apple.InterfaceBuilder.IBCocoaTouchPlugin
-
-
- YES
-
- YES
-
-
- YES
-
-
-
- YES
-
- IBFilesOwner
-
-
- IBFirstResponder
-
-
-
-
- 1316
-
- {320, 480}
-
-
- 1
- MSAxIDEAA
-
- NO
- NO
-
-
-
-
-
- YES
-
-
- delegate
-
-
-
- 5
-
-
-
- window
-
-
-
- 7
-
-
-
-
- YES
-
- 0
-
- YES
-
-
-
-
-
- 2
-
-
- YES
-
-
-
-
- -1
-
-
- RmlsZSdzIE93bmVyA
-
-
- 4
-
-
- App Delegate
-
-
- -2
-
-
-
-
-
-
- YES
-
- YES
- -1.CustomClassName
- -2.CustomClassName
- 2.IBAttributePlaceholdersKey
- 2.IBEditorWindowLastContentRect
- 2.IBPluginDependency
- 2.UIWindow.visibleAtLaunch
- 4.CustomClassName
- 4.IBPluginDependency
-
-
- YES
- UIApplication
- UIResponder
-
- YES
-
- YES
-
-
- YES
-
-
- {{593, 276}, {320, 480}}
- com.apple.InterfaceBuilder.IBCocoaTouchPlugin
-
- AppDelegate
- com.apple.InterfaceBuilder.IBCocoaTouchPlugin
-
-
-
- YES
-
- YES
-
-
- YES
-
-
-
-
- YES
-
- YES
-
-
- YES
-
-
-
- 7
-
-
-
- YES
-
- AppDelegate
-
- window
- id
-
-
- IBUserSource
-
-
-
-
-
- 0
-
- 3
- 3.0
-
-
diff --git a/MonoTouch/MonoTouch.Example/MainWindow.xib.designer.cs b/MonoTouch/MonoTouch.Example/MainWindow.xib.designer.cs
deleted file mode 100644
index 1381ed6..0000000
--- a/MonoTouch/MonoTouch.Example/MainWindow.xib.designer.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Mono Runtime Version: 2.0.50727.1433
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-// ------------------------------------------------------------------------------
-
-namespace MonoTouch.Example {
-
-
- // Base type probably should be MonoTouch.Foundation.NSObject or subclass
- [MonoTouch.Foundation.Register("AppDelegate")]
- public partial class AppDelegate {
-
- private MonoTouch.UIKit.UIWindow __mt_window;
-
- #pragma warning disable 0169
- [MonoTouch.Foundation.Connect("window")]
- private MonoTouch.UIKit.UIWindow window {
- get {
- this.__mt_window = ((MonoTouch.UIKit.UIWindow)(this.GetNativeField("window")));
- return this.__mt_window;
- }
- set {
- this.__mt_window = value;
- this.SetNativeField("window", value);
- }
- }
- }
-}
diff --git a/MonoTouch/MonoTouch.Example/MonoTouch.Example.csproj b/MonoTouch/MonoTouch.Example/MonoTouch.Example.csproj
deleted file mode 100644
index 0181eff..0000000
--- a/MonoTouch/MonoTouch.Example/MonoTouch.Example.csproj
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
- Debug
- iPhoneSimulator
- 10.0.0
- 2.0
- {EA8AD2F7-5BF5-4442-8607-3DD30E0641EB}
- {E613F3A2-FE9C-494F-B74E-F63BCB86FEA6};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Exe
- MonoTouch.Example
- MainWindow.xib
- MonoTouchExample
- 3.0
- v3.5
-
-
- true
- full
- false
- bin\iPhoneSimulator\Debug
- DEBUG
- prompt
- 4
- None
- True
- false
- false
- false
- false
- false
- -v -v -v
-
-
-
- none
- false
- bin\iPhoneSimulator\Release
- prompt
- 4
- None
- False
- false
- false
- false
- false
- false
-
-
- true
- full
- false
- bin\iPhone\Debug
- DEBUG
- prompt
- 4
- false
- True
- iPhone Developer
- false
- false
- false
- false
-
-
-
- none
- false
- bin\iPhone\Release
- prompt
- 4
- false
- False
- false
- false
- iPhone Developer
- false
- false
- -v -v -v
-
-
-
-
-
-
-
-
- False
- ..\MonoMobile.Extensions\bin\iPhoneSimulator\Debug\MonoMobileExtensions.dll
-
-
-
-
-
-
-
- MainWindow.xib
-
-
-
- ExampleList.xib
-
-
- ExampleList.xib
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/MonoTouch/MonoTouch.Example/README b/MonoTouch/MonoTouch.Example/README
deleted file mode 100644
index 6d6c9cc..0000000
--- a/MonoTouch/MonoTouch.Example/README
+++ /dev/null
@@ -1 +0,0 @@
-Beep sound used from http://www.freesound.org/samplesViewSingle.php?id=114680 by m_O_m
diff --git a/MonoTouch/MonoTouch.Example/beep.wav b/MonoTouch/MonoTouch.Example/beep.wav
deleted file mode 100644
index fcdcf95..0000000
Binary files a/MonoTouch/MonoTouch.Example/beep.wav and /dev/null differ
diff --git a/MonoTouch/Samples/ContactsSample-Classic/AppDelegate.cs b/MonoTouch/Samples/ContactsSample-Classic/AppDelegate.cs
new file mode 100644
index 0000000..afa422e
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample-Classic/AppDelegate.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MonoTouch.Foundation;
+using MonoTouch.UIKit;
+
+namespace ContactsSample
+{
+ // The UIApplicationDelegate for the application. This class is responsible for launching the
+ // User Interface of the application, as well as listening (and optionally responding) to
+ // application events from iOS.
+ [Register ("AppDelegate")]
+ public partial class AppDelegate : UIApplicationDelegate
+ {
+ UIWindow window;
+ MainView viewController;
+
+ public UINavigationController NavigationController
+ {
+ get;
+ private set;
+ }
+
+ //
+ // This method is invoked when the application has loaded and is ready to run. In this
+ // method you should instantiate the window, load the UI into it and then make the window
+ // visible.
+ //
+ // You have 17 seconds to return from this method, or iOS will terminate your application.
+ //
+ public override bool FinishedLaunching (UIApplication app, NSDictionary options)
+ {
+ window = new UIWindow (UIScreen.MainScreen.Bounds);
+
+ NavigationController = new UINavigationController();
+
+ viewController = new MainView ();
+ NavigationController.PushViewController (viewController, false);
+ window.RootViewController = this.NavigationController;
+ window.MakeKeyAndVisible ();
+
+ return true;
+ }
+ }
+}
+
diff --git a/MonoTouch/Samples/ContactsSample-Classic/Contacts Sample-Classic.csproj b/MonoTouch/Samples/ContactsSample-Classic/Contacts Sample-Classic.csproj
new file mode 100644
index 0000000..56fc21a
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample-Classic/Contacts Sample-Classic.csproj
@@ -0,0 +1,95 @@
+
+
+
+ Debug
+ iPhoneSimulator
+ 8.0.30703
+ 2.0
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}
+ {6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Exe
+ ContactsSample
+ ContactsSample
+
+
+ True
+ full
+ False
+ bin\iPhoneSimulator\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ None
+ True
+ ARMv7
+
+
+
+
+ none
+ False
+ bin\iPhoneSimulator\Release
+ prompt
+ 4
+ False
+ None
+
+
+ True
+ full
+ False
+ bin\iPhone\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ True
+ iPhone Developer
+
+
+ ARMv7
+
+
+
+
+ none
+ False
+ bin\iPhone\Release
+ prompt
+ 4
+ False
+ iPhone Developer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}
+ Xamarin.Mobile.iOS-Classic
+
+
+
\ No newline at end of file
diff --git a/MonoTouch/Samples/ContactsSample-Classic/Info.plist b/MonoTouch/Samples/ContactsSample-Classic/Info.plist
new file mode 100644
index 0000000..2af459d
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample-Classic/Info.plist
@@ -0,0 +1,33 @@
+
+
+
+
+ MinimumOSVersion
+ 5.0
+ UIDeviceFamily
+
+ 1
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+ UIInterfaceOrientationPortraitUpsideDown
+
+ CFBundleDisplayName
+ X.M Contacts
+ CFBundleIconFiles
+
+ Resources/Default.png
+ Resources/Default@2x.png
+ Resources/Default-568h@2x.png
+
+ CFBundleIdentifier
+ com.xamarin.mobile.contactssample
+ CFBundleVersion
+
+ NSMainNibFile
+
+
+
diff --git a/MonoTouch/Samples/ContactsSample-Classic/Main.cs b/MonoTouch/Samples/ContactsSample-Classic/Main.cs
new file mode 100644
index 0000000..59419e3
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample-Classic/Main.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MonoTouch.Foundation;
+using MonoTouch.UIKit;
+
+namespace ContactsSample
+{
+ public class Application
+ {
+ // This is the main entry point of the application.
+ static void Main (string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main (args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/MonoTouch/Samples/ContactsSample-Classic/MainView.cs b/MonoTouch/Samples/ContactsSample-Classic/MainView.cs
new file mode 100644
index 0000000..efcc6fc
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample-Classic/MainView.cs
@@ -0,0 +1,190 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MonoTouch.Dialog;
+using MonoTouch.Foundation;
+using MonoTouch.UIKit;
+using Xamarin.Contacts;
+
+namespace ContactsSample
+{
+ public class MainView : UIViewController
+ {
+ public override void ViewDidLoad ()
+ {
+ base.ViewDidLoad ();
+ SetupUI();
+
+ var book = new AddressBook ();
+
+ // We must request permission to access the user's address book
+ // This will prompt the user on platforms that ask, or it will validate
+ // manifest permissions on platforms that declare their required permissions.
+ book.RequestPermission().ContinueWith (t =>
+ {
+ if (!t.Result)
+ {
+ alert = new UIAlertView ("Permission denied", "User has denied this app access to their contacts", null, "Close");
+ alert.Show();
+ }
+ else
+ {
+ // Contacts can be selected and sorted using LINQ!
+ //
+ // In this sample, we'll just use LINQ to sort contacts by
+ // their last name in reverse order.
+ list = book.OrderByDescending (c => c.LastName).ToList();
+
+ tableView.Source = new TableViewDataSource (list);
+ tableView.ReloadData();
+ }
+ }, TaskScheduler.FromCurrentSynchronizationContext());
+ }
+
+ // Simple table view data source using the List as the datasource
+ private class TableViewDataSource : UITableViewSource
+ {
+ public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
+ {
+ Contact contact = this.list[indexPath.Row];
+
+ RootElement root = new RootElement ("Info");
+
+ UIView title = new UIView (new RectangleF (0, 0, UIScreen.MainScreen.Bounds.Width, 64)) {
+ AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
+ };
+
+ title.AddSubview (new UIImageView (new RectangleF (0, 0, 64, 64)) {
+ Image = contact.GetThumbnail(),
+ BackgroundColor = UIColor.White
+ });
+
+ title.AddSubview (new UITextView (new RectangleF (64, -10, title.Bounds.Width, 36)) {
+ Text = contact.DisplayName,
+ AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
+ BackgroundColor = UIColor.Clear,
+ Font = UIFont.SystemFontOfSize (22)
+ });
+
+ var org = contact.Organizations.FirstOrDefault();
+ if (org != null) {
+ title.AddSubview (new UITextView (new RectangleF (65, 13, title.Bounds.Width, 25)) {
+ Text = org.ContactTitle,
+ AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
+ BackgroundColor = UIColor.Clear,
+ TextColor = UIColor.DarkGray,
+ });
+
+ title.AddSubview (new UITextView (new RectangleF (65, 28, title.Bounds.Width, 25)) {
+ Text = org.Name,
+ AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
+ BackgroundColor = UIColor.Clear,
+ TextColor = UIColor.DarkGray
+ });
+ }
+
+ root.Add (new Section { new UIViewElement (String.Empty, title, true) });
+
+ var phoneElements = contact.Phones.Select (p =>
+ new StringElement (p.Label.ToLower(), p.Number)).ToArray();
+
+ if (phoneElements.Length > 0) {
+ Section phones = new Section();
+ phones.AddAll (phoneElements);
+ root.Add (phones);
+ }
+
+ var emailElements = contact.Emails.Select (e =>
+ new StringElement ((e.Label == "Other") ? "Email" : e.Label, e.Address)).ToArray();
+
+ if (emailElements.Length > 0) {
+ Section emails = new Section();
+ emails.AddAll (emailElements);
+ root.Add (emails);
+ }
+
+ var addressElements = contact.Addresses.Select (a => {
+ StringBuilder address = new StringBuilder();
+ if (!String.IsNullOrEmpty (a.StreetAddress))
+ address.Append (a.StreetAddress);
+
+ if (!(String.IsNullOrEmpty (a.City) && String.IsNullOrEmpty (a.Region) && String.IsNullOrEmpty (a.PostalCode)))
+ address.AppendFormat("{3}{0} {1} {2}", a.City, a.Region, a.PostalCode, (address.Length > 0) ? Environment.NewLine : String.Empty);
+
+ if (!String.IsNullOrEmpty (a.Country))
+ address.AppendFormat ("{1}{0}", a.Country, (address.Length > 0) ? Environment.NewLine : String.Empty);
+
+ return new StyledMultilineElement (
+ (a.Label == "Other") ? "Address" : a.Label,
+ address.ToString());
+ }).ToArray();
+
+ if (addressElements.Length > 0) {
+ Section addresses = new Section();
+ addresses.AddAll (addressElements);
+ root.Add (addresses);
+ }
+
+ var dialog = new DialogViewController (root, pushing: true);
+
+ AppDelegate appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
+ appDelegate.NavigationController.PushViewController (dialog, true);
+ }
+
+ public override int RowsInSection (UITableView tableview, int section)
+ {
+ return list.Count;
+ }
+
+ static readonly NSString CellIdentifier = new NSString ("contactIdentifier");
+ private readonly List list;
+
+ public TableViewDataSource (List list)
+ {
+ this.list = list;
+ }
+
+ public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
+ {
+ UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
+ if (cell == null)
+ cell = new UITableViewCell (UITableViewCellStyle.Subtitle, CellIdentifier);
+
+ Contact contact = list[indexPath.Row];
+
+ cell.TextLabel.Text = contact.DisplayName;
+ Email firstEmail = contact.Emails.FirstOrDefault();
+ if (firstEmail != null)
+ cell.DetailTextLabel.Text = String.Format ("{0}: {1}", firstEmail.Label.ToLower(), firstEmail.Address);
+
+ return cell;
+ }
+ }
+
+ UITableView tableView;
+ List list;
+ private UIAlertView alert;
+
+ public override void ViewDidAppear (bool animated)
+ {
+ base.ViewDidAppear (animated);
+ this.tableView.DeselectRow (this.tableView.IndexPathForSelectedRow, animated: true);
+ }
+
+ private void SetupUI()
+ {
+ Title = "Contacts";
+
+ this.tableView = new UITableView {
+ AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth,
+ Frame = new RectangleF (0, 0, View.Frame.Width, View.Frame.Height)
+ };
+
+ View.AddSubview (this.tableView);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoTouch/Samples/ContactsSample-Classic/Resources/Default-568h@2x.png b/MonoTouch/Samples/ContactsSample-Classic/Resources/Default-568h@2x.png
new file mode 100644
index 0000000..b3f6678
Binary files /dev/null and b/MonoTouch/Samples/ContactsSample-Classic/Resources/Default-568h@2x.png differ
diff --git a/MonoTouch/Samples/ContactsSample-Classic/Resources/Default.png b/MonoTouch/Samples/ContactsSample-Classic/Resources/Default.png
new file mode 100644
index 0000000..7ad63b0
Binary files /dev/null and b/MonoTouch/Samples/ContactsSample-Classic/Resources/Default.png differ
diff --git a/MonoTouch/Samples/ContactsSample-Classic/Resources/Default@2x.png b/MonoTouch/Samples/ContactsSample-Classic/Resources/Default@2x.png
new file mode 100644
index 0000000..8d59426
Binary files /dev/null and b/MonoTouch/Samples/ContactsSample-Classic/Resources/Default@2x.png differ
diff --git a/MonoTouch/Samples/ContactsSample/AppDelegate.cs b/MonoTouch/Samples/ContactsSample/AppDelegate.cs
new file mode 100644
index 0000000..f9d828e
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample/AppDelegate.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Foundation;
+using UIKit;
+
+namespace ContactsSample
+{
+ // The UIApplicationDelegate for the application. This class is responsible for launching the
+ // User Interface of the application, as well as listening (and optionally responding) to
+ // application events from iOS.
+ [Register ("AppDelegate")]
+ public partial class AppDelegate : UIApplicationDelegate
+ {
+ UIWindow window;
+ MainView viewController;
+
+ public UINavigationController NavigationController
+ {
+ get;
+ private set;
+ }
+
+ //
+ // This method is invoked when the application has loaded and is ready to run. In this
+ // method you should instantiate the window, load the UI into it and then make the window
+ // visible.
+ //
+ // You have 17 seconds to return from this method, or iOS will terminate your application.
+ //
+ public override bool FinishedLaunching (UIApplication app, NSDictionary options)
+ {
+ window = new UIWindow (UIScreen.MainScreen.Bounds);
+
+ NavigationController = new UINavigationController();
+
+ viewController = new MainView ();
+ NavigationController.PushViewController (viewController, false);
+ window.RootViewController = this.NavigationController;
+ window.MakeKeyAndVisible ();
+
+ return true;
+ }
+ }
+}
+
diff --git a/MonoTouch/Samples/ContactsSample/Contacts Sample.csproj b/MonoTouch/Samples/ContactsSample/Contacts Sample.csproj
new file mode 100644
index 0000000..dbf8d83
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample/Contacts Sample.csproj
@@ -0,0 +1,96 @@
+
+
+
+ Debug
+ iPhoneSimulator
+ 8.0.30703
+ 2.0
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}
+ {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Exe
+ ContactsSample
+ ContactsSample
+
+
+ True
+ full
+ False
+ bin\iPhoneSimulator\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ None
+ True
+ ARMv7
+
+
+
+
+ none
+ False
+ bin\iPhoneSimulator\Release
+ prompt
+ 4
+ False
+ None
+
+
+ True
+ full
+ False
+ bin\iPhone\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ true
+ iPhone Developer
+
+
+ ARMv7
+
+
+ False
+
+
+ none
+ False
+ bin\iPhone\Release
+ prompt
+ 4
+ False
+ iPhone Developer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}
+ Xamarin.Mobile.iOS
+
+
+
\ No newline at end of file
diff --git a/MonoTouch/Samples/ContactsSample/Info.plist b/MonoTouch/Samples/ContactsSample/Info.plist
new file mode 100644
index 0000000..b4c73f8
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample/Info.plist
@@ -0,0 +1,33 @@
+
+
+
+
+ MinimumOSVersion
+ 5.2
+ UIDeviceFamily
+
+ 1
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+ UIInterfaceOrientationPortraitUpsideDown
+
+ CFBundleDisplayName
+ X.M Contacts
+ CFBundleIconFiles
+
+ Resources/Default.png
+ Resources/Default@2x.png
+ Resources/Default-568h@2x.png
+
+ CFBundleIdentifier
+ com.xamarin.mobile.contactssample
+ CFBundleVersion
+
+ NSMainNibFile
+
+
+
diff --git a/MonoTouch/Samples/ContactsSample/Main.cs b/MonoTouch/Samples/ContactsSample/Main.cs
new file mode 100644
index 0000000..f64141d
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample/Main.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Foundation;
+using UIKit;
+
+namespace ContactsSample
+{
+ public class Application
+ {
+ // This is the main entry point of the application.
+ static void Main (string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main (args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/MonoTouch/Samples/ContactsSample/MainView.cs b/MonoTouch/Samples/ContactsSample/MainView.cs
new file mode 100644
index 0000000..107644a
--- /dev/null
+++ b/MonoTouch/Samples/ContactsSample/MainView.cs
@@ -0,0 +1,191 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MonoTouch.Dialog;
+using Foundation;
+using UIKit;
+using Xamarin.Contacts;
+using CoreGraphics;
+
+namespace ContactsSample
+{
+ public class MainView : UIViewController
+ {
+ public override void ViewDidLoad ()
+ {
+ base.ViewDidLoad ();
+ SetupUI();
+
+ var book = new Xamarin.Contacts.AddressBook ();
+
+ // We must request permission to access the user's address book
+ // This will prompt the user on platforms that ask, or it will validate
+ // manifest permissions on platforms that declare their required permissions.
+ book.RequestPermission().ContinueWith (t =>
+ {
+ if (!t.Result)
+ {
+ alert = new UIAlertView ("Permission denied", "User has denied this app access to their contacts", null, "Close");
+ alert.Show();
+ }
+ else
+ {
+ // Contacts can be selected and sorted using LINQ!
+ //
+ // In this sample, we'll just use LINQ to sort contacts by
+ // their last name in reverse order.
+ list = book.OrderByDescending (c => c.LastName).ToList();
+
+ tableView.Source = new TableViewDataSource (list);
+ tableView.ReloadData();
+ }
+ }, TaskScheduler.FromCurrentSynchronizationContext());
+ }
+
+ // Simple table view data source using the List as the datasource
+ private class TableViewDataSource : UITableViewSource
+ {
+ public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
+ {
+ Contact contact = this.list[indexPath.Row];
+
+ RootElement root = new RootElement ("Info");
+
+ UIView title = new UIView (new CGRect (0, 0, UIScreen.MainScreen.Bounds.Width, 64)) {
+ AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
+ };
+
+ title.AddSubview (new UIImageView (new CGRect (0, 0, 64, 64)) {
+ Image = contact.GetThumbnail(),
+ BackgroundColor = UIColor.White
+ });
+
+ title.AddSubview (new UITextView (new CGRect (64, -10, title.Bounds.Width, 36)) {
+ Text = contact.DisplayName,
+ AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
+ BackgroundColor = UIColor.Clear,
+ Font = UIFont.SystemFontOfSize (22)
+ });
+
+ var org = contact.Organizations.FirstOrDefault();
+ if (org != null) {
+ title.AddSubview (new UITextView (new CGRect (65, 13, title.Bounds.Width, 25)) {
+ Text = org.ContactTitle,
+ AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
+ BackgroundColor = UIColor.Clear,
+ TextColor = UIColor.DarkGray,
+ });
+
+ title.AddSubview (new UITextView (new CGRect (65, 28, title.Bounds.Width, 25)) {
+ Text = org.Name,
+ AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
+ BackgroundColor = UIColor.Clear,
+ TextColor = UIColor.DarkGray
+ });
+ }
+
+ root.Add (new Section { new UIViewElement (String.Empty, title, true) });
+
+ var phoneElements = contact.Phones.Select (p =>
+ new StringElement (p.Label.ToLower(), p.Number)).ToArray();
+
+ if (phoneElements.Length > 0) {
+ Section phones = new Section();
+ phones.AddAll (phoneElements);
+ root.Add (phones);
+ }
+
+ var emailElements = contact.Emails.Select (e =>
+ new StringElement ((e.Label == "Other") ? "Email" : e.Label, e.Address)).ToArray();
+
+ if (emailElements.Length > 0) {
+ Section emails = new Section();
+ emails.AddAll (emailElements);
+ root.Add (emails);
+ }
+
+ var addressElements = contact.Addresses.Select (a => {
+ StringBuilder address = new StringBuilder();
+ if (!String.IsNullOrEmpty (a.StreetAddress))
+ address.Append (a.StreetAddress);
+
+ if (!(String.IsNullOrEmpty (a.City) && String.IsNullOrEmpty (a.Region) && String.IsNullOrEmpty (a.PostalCode)))
+ address.AppendFormat("{3}{0} {1} {2}", a.City, a.Region, a.PostalCode, (address.Length > 0) ? Environment.NewLine : String.Empty);
+
+ if (!String.IsNullOrEmpty (a.Country))
+ address.AppendFormat ("{1}{0}", a.Country, (address.Length > 0) ? Environment.NewLine : String.Empty);
+
+ return new StyledMultilineElement (
+ (a.Label == "Other") ? "Address" : a.Label,
+ address.ToString());
+ }).ToArray();
+
+ if (addressElements.Length > 0) {
+ Section addresses = new Section();
+ addresses.AddAll (addressElements);
+ root.Add (addresses);
+ }
+
+ var dialog = new DialogViewController (root, pushing: true);
+
+ AppDelegate appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
+ appDelegate.NavigationController.PushViewController (dialog, true);
+ }
+
+ public override nint RowsInSection (UITableView tableview, nint section)
+ {
+ return list.Count;
+ }
+
+ static readonly NSString CellIdentifier = new NSString ("contactIdentifier");
+ private readonly List list;
+
+ public TableViewDataSource (List list)
+ {
+ this.list = list;
+ }
+
+ public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
+ {
+ UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
+ if (cell == null)
+ cell = new UITableViewCell (UITableViewCellStyle.Subtitle, CellIdentifier);
+
+ Contact contact = list[indexPath.Row];
+
+ cell.TextLabel.Text = contact.DisplayName;
+ Email firstEmail = contact.Emails.FirstOrDefault();
+ if (firstEmail != null)
+ cell.DetailTextLabel.Text = String.Format ("{0}: {1}", firstEmail.Label.ToLower(), firstEmail.Address);
+
+ return cell;
+ }
+ }
+
+ UITableView tableView;
+ List list;
+ private UIAlertView alert;
+
+ public override void ViewDidAppear (bool animated)
+ {
+ base.ViewDidAppear (animated);
+ this.tableView.DeselectRow (this.tableView.IndexPathForSelectedRow, animated: true);
+ }
+
+ private void SetupUI()
+ {
+ Title = "Contacts";
+
+ this.tableView = new UITableView {
+ AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth,
+ Frame = new CGRect (0, 0, View.Frame.Width, View.Frame.Height)
+ };
+
+ View.AddSubview (this.tableView);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MonoTouch/Samples/ContactsSample/Resources/Default-568h@2x.png b/MonoTouch/Samples/ContactsSample/Resources/Default-568h@2x.png
new file mode 100644
index 0000000..b3f6678
Binary files /dev/null and b/MonoTouch/Samples/ContactsSample/Resources/Default-568h@2x.png differ
diff --git a/MonoTouch/Samples/ContactsSample/Resources/Default.png b/MonoTouch/Samples/ContactsSample/Resources/Default.png
new file mode 100644
index 0000000..7ad63b0
Binary files /dev/null and b/MonoTouch/Samples/ContactsSample/Resources/Default.png differ
diff --git a/MonoTouch/Samples/ContactsSample/Resources/Default@2x.png b/MonoTouch/Samples/ContactsSample/Resources/Default@2x.png
new file mode 100644
index 0000000..8d59426
Binary files /dev/null and b/MonoTouch/Samples/ContactsSample/Resources/Default@2x.png differ
diff --git a/MonoTouch/Samples/Geolocation-Classic/AppDelegate.cs b/MonoTouch/Samples/Geolocation-Classic/AppDelegate.cs
new file mode 100644
index 0000000..9470082
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation-Classic/AppDelegate.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MonoTouch.Foundation;
+using MonoTouch.UIKit;
+
+namespace Sample
+{
+ // The UIApplicationDelegate for the application. This class is responsible for launching the
+ // User Interface of the application, as well as listening (and optionally responding) to
+ // application events from iOS.
+ [Register ("AppDelegate")]
+ public partial class AppDelegate : UIApplicationDelegate
+ {
+ // class-level declarations
+ UIWindow window;
+ SampleViewController viewController;
+
+ //
+ // This method is invoked when the application has loaded and is ready to run. In this
+ // method you should instantiate the window, load the UI into it and then make the window
+ // visible.
+ //
+ // You have 17 seconds to return from this method, or iOS will terminate your application.
+ //
+ public override bool FinishedLaunching (UIApplication app, NSDictionary options)
+ {
+ window = new UIWindow (UIScreen.MainScreen.Bounds);
+
+ viewController = new SampleViewController ();
+ window.RootViewController = viewController;
+ window.MakeKeyAndVisible ();
+
+ return true;
+ }
+ }
+}
+
diff --git a/MonoTouch/Samples/Geolocation-Classic/Geolocation Sample-Classic.csproj b/MonoTouch/Samples/Geolocation-Classic/Geolocation Sample-Classic.csproj
new file mode 100644
index 0000000..f1f0f47
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation-Classic/Geolocation Sample-Classic.csproj
@@ -0,0 +1,98 @@
+
+
+
+ Debug
+ iPhoneSimulator
+ 8.0.30703
+ 2.0
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}
+ {6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Exe
+ Sample
+ Sample
+
+
+ True
+ full
+ False
+ bin\iPhoneSimulator\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ None
+ True
+ ARMv7
+
+
+ none
+ False
+ bin\iPhoneSimulator\Release
+ prompt
+ 4
+ False
+ None
+
+
+ True
+ full
+ False
+ bin\iPhone\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ True
+ iPhone Developer
+ ARMv7
+
+
+
+
+
+
+ none
+ False
+ bin\iPhone\Release
+ prompt
+ 4
+ False
+ iPhone Developer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SampleViewController.cs
+
+
+
+
+
+
+
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}
+ Xamarin.Mobile.iOS-Classic
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MonoTouch/Samples/Geolocation-Classic/Info.plist b/MonoTouch/Samples/Geolocation-Classic/Info.plist
new file mode 100644
index 0000000..1434e26
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation-Classic/Info.plist
@@ -0,0 +1,28 @@
+
+
+
+
+ MinimumOSVersion
+ 5.0
+ UIDeviceFamily
+
+ 1
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ CFBundleDisplayName
+ X.M Geolocation
+ CFBundleIdentifier
+ com.xamarin.mobile.geolocationsample
+ CFBundleVersion
+
+ NSMainNibFile
+
+ NSLocationWhenInUseUsageDescription
+ Please allow the sample app to access Location!
+
+
diff --git a/MonoTouch/Samples/Geolocation-Classic/Main.cs b/MonoTouch/Samples/Geolocation-Classic/Main.cs
new file mode 100644
index 0000000..f35542c
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation-Classic/Main.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MonoTouch.Foundation;
+using MonoTouch.UIKit;
+
+namespace Sample
+{
+ public class Application
+ {
+ // This is the main entry point of the application.
+ static void Main (string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main (args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/MonoTouch/Samples/Geolocation-Classic/Resources/Default-568h@2x.png b/MonoTouch/Samples/Geolocation-Classic/Resources/Default-568h@2x.png
new file mode 100644
index 0000000..b3f6678
Binary files /dev/null and b/MonoTouch/Samples/Geolocation-Classic/Resources/Default-568h@2x.png differ
diff --git a/MonoTouch/Samples/Geolocation-Classic/Resources/Default.png b/MonoTouch/Samples/Geolocation-Classic/Resources/Default.png
new file mode 100644
index 0000000..7ad63b0
Binary files /dev/null and b/MonoTouch/Samples/Geolocation-Classic/Resources/Default.png differ
diff --git a/MonoTouch/Samples/Geolocation-Classic/Resources/Default@2x.png b/MonoTouch/Samples/Geolocation-Classic/Resources/Default@2x.png
new file mode 100644
index 0000000..8d59426
Binary files /dev/null and b/MonoTouch/Samples/Geolocation-Classic/Resources/Default@2x.png differ
diff --git a/MonoTouch/Samples/Geolocation-Classic/SampleViewController.cs b/MonoTouch/Samples/Geolocation-Classic/SampleViewController.cs
new file mode 100644
index 0000000..7956dbc
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation-Classic/SampleViewController.cs
@@ -0,0 +1,128 @@
+using MonoTouch.UIKit;
+using System.Drawing;
+using System;
+using MonoTouch.Foundation;
+using System.Threading;
+using Xamarin.Geolocation;
+using System.Threading.Tasks;
+
+namespace Sample
+{
+ public partial class SampleViewController : UIViewController
+ {
+ #region Boilerplate
+ public SampleViewController () : base ("SampleViewController", null)
+ {
+ }
+
+ public override void DidReceiveMemoryWarning ()
+ {
+ // Releases the view if it doesn't have a superview.
+ base.DidReceiveMemoryWarning ();
+
+ // Release any cached data, images, etc that aren't in use.
+ }
+
+ public override void ViewDidLoad ()
+ {
+ base.ViewDidLoad ();
+ }
+
+ public override void ViewDidUnload ()
+ {
+ base.ViewDidUnload ();
+
+ // Release any retained subviews of the main view.
+ // e.g. myOutlet = null;
+ }
+
+ public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
+ {
+ // Return true for supported orientations
+ return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
+ }
+ #endregion
+
+ private Geolocator geolocator;
+
+ private TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
+ private CancellationTokenSource cancelSource;
+
+ private void Setup()
+ {
+ if (this.geolocator != null)
+ return;
+
+ this.geolocator = new Geolocator { DesiredAccuracy = 50 };
+ this.geolocator.PositionError += OnListeningError;
+ this.geolocator.PositionChanged += OnPositionChanged;
+ }
+
+ partial void GetPosition (NSObject sender)
+ {
+ Setup();
+
+ this.cancelSource = new CancellationTokenSource();
+
+ PositionStatus.Text = String.Empty;
+ PositionLatitude.Text = String.Empty;
+ PositionLongitude.Text = String.Empty;
+
+ this.geolocator.GetPositionAsync (timeout: 10000, cancelToken: this.cancelSource.Token, includeHeading: true)
+ .ContinueWith (t =>
+ {
+ if (t.IsFaulted)
+ PositionStatus.Text = ((GeolocationException)t.Exception.InnerException).Error.ToString();
+ else if (t.IsCanceled)
+ PositionStatus.Text = "Canceled";
+ else
+ {
+ PositionStatus.Text = t.Result.Timestamp.ToString("G");
+ PositionLatitude.Text = "La: " + t.Result.Latitude.ToString("N4");
+ PositionLongitude.Text = "Lo: " + t.Result.Longitude.ToString("N4");
+ }
+
+ }, scheduler);
+ }
+
+ partial void CancelPosition (NSObject sender)
+ {
+ CancellationTokenSource cancel = this.cancelSource;
+ if (cancel != null)
+ cancel.Cancel();
+ }
+
+ partial void ToggleListening (NSObject sender)
+ {
+ Setup();
+
+ if (!this.geolocator.IsListening)
+ {
+ ToggleListeningButton.SetTitle ("Stop listening", UIControlState.Normal);
+
+ this.geolocator.StartListening (minTime: 30000, minDistance: 0, includeHeading: true);
+ }
+ else
+ {
+ ToggleListeningButton.SetTitle ("Start listening", UIControlState.Normal);
+ this.geolocator.StopListening();
+ }
+ }
+
+ private void OnListeningError (object sender, PositionErrorEventArgs e)
+ {
+ BeginInvokeOnMainThread (() => {
+ ListenStatus.Text = e.Error.ToString();
+ });
+ }
+
+ private void OnPositionChanged (object sender, PositionEventArgs e)
+ {
+ BeginInvokeOnMainThread (() => {
+ ListenStatus.Text = e.Position.Timestamp.ToString("G");
+ ListenLatitude.Text = "La: " + e.Position.Latitude.ToString("N4");
+ ListenLongitude.Text = "Lo: " + e.Position.Longitude.ToString("N4");
+ });
+ }
+ }
+}
diff --git a/MonoTouch/Samples/Geolocation-Classic/SampleViewController.designer.cs b/MonoTouch/Samples/Geolocation-Classic/SampleViewController.designer.cs
new file mode 100644
index 0000000..318bda5
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation-Classic/SampleViewController.designer.cs
@@ -0,0 +1,50 @@
+// WARNING
+//
+// This file has been generated automatically by MonoDevelop to store outlets and
+// actions made in the Xcode designer. If it is removed, they will be lost.
+// Manual changes to this file may not be handled correctly.
+//
+using MonoTouch.Foundation;
+
+namespace Sample
+{
+ [Register ("SampleViewController")]
+ partial class SampleViewController
+ {
+ [Outlet]
+ MonoTouch.UIKit.UIButton PositionButton { get; set; }
+
+ [Outlet]
+ MonoTouch.UIKit.UIButton CancelButton { get; set; }
+
+ [Outlet]
+ MonoTouch.UIKit.UIButton ToggleListeningButton { get; set; }
+
+ [Outlet]
+ MonoTouch.UIKit.UILabel PositionStatus { get; set; }
+
+ [Outlet]
+ MonoTouch.UIKit.UILabel PositionLatitude { get; set; }
+
+ [Outlet]
+ MonoTouch.UIKit.UILabel PositionLongitude { get; set; }
+
+ [Outlet]
+ MonoTouch.UIKit.UILabel ListenStatus { get; set; }
+
+ [Outlet]
+ MonoTouch.UIKit.UILabel ListenLongitude { get; set; }
+
+ [Outlet]
+ MonoTouch.UIKit.UILabel ListenLatitude { get; set; }
+
+ [Action ("GetPosition:")]
+ partial void GetPosition (MonoTouch.Foundation.NSObject sender);
+
+ [Action ("CancelPosition:")]
+ partial void CancelPosition (MonoTouch.Foundation.NSObject sender);
+
+ [Action ("ToggleListening:")]
+ partial void ToggleListening (MonoTouch.Foundation.NSObject sender);
+ }
+}
diff --git a/MonoTouch/Samples/Geolocation-Classic/SampleViewController.xib b/MonoTouch/Samples/Geolocation-Classic/SampleViewController.xib
new file mode 100644
index 0000000..c5cc33e
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation-Classic/SampleViewController.xib
@@ -0,0 +1,713 @@
+
+
+
+ 2048
+ 14B25
+ 6254
+ 1343.16
+ 755.00
+
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ 6247
+
+
+ IBProxyObject
+ IBUIButton
+ IBUILabel
+ IBUIView
+
+
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+
+
+ PluginDependencyRecalculationVersion
+
+
+
+
+ IBFilesOwner
+ IBCocoaTouchFramework
+
+
+ IBFirstResponder
+ IBCocoaTouchFramework
+
+
+
+ 274
+
+
+
+ 292
+ {{163, 73}, {137, 37}}
+
+
+
+ _NS:225
+ NO
+ IBCocoaTouchFramework
+ 0
+ 0
+ 1
+
+ 1
+ MC4xOTYwNzg0MzE0IDAuMzA5ODAzOTIxNiAwLjUyMTU2ODYyNzUAA
+
+
+ 3
+ MQA
+
+ Get position
+
+ 3
+ MC41AA
+
+
+ 2
+ 15
+
+
+ HelveticaNeue-Bold
+ 15
+ 16
+
+
+
+
+ 292
+ {{163, 118}, {137, 37}}
+
+
+
+ _NS:225
+ NO
+ IBCocoaTouchFramework
+ 0
+ 0
+ 1
+
+
+ Cancel position
+
+
+
+
+
+
+ 292
+ {{20, 73}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+ 1
+ MCAwIDAAA
+ darkTextColor
+
+
+ 1
+ 10
+
+ 1
+ 17
+
+
+ HelveticaNeue
+ 17
+ 16
+
+ YES
+
+
+
+ 292
+ {{20, 102}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{20, 131}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{163, 211}, {137, 37}}
+
+
+
+ _NS:225
+ NO
+ IBCocoaTouchFramework
+ 0
+ 0
+ 1
+
+
+ Start listening
+
+
+
+
+
+
+ 292
+ {{20, 219}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{20, 248}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{20, 306}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{20, 277}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+ {{0, 20}, {320, 460}}
+
+
+
+
+ 3
+ MC43NQA
+
+ 2
+
+
+ NO
+
+
+ IBUISimulatedFreeformSizeMetricsSentinel
+ Freeform
+
+ IBCocoaTouchFramework
+
+
+
+
+
+
+ view
+
+
+
+ 7
+
+
+
+ PositionButton
+
+
+
+ 22
+
+
+
+ CancelButton
+
+
+
+ 23
+
+
+
+ ToggleListeningButton
+
+
+
+ 24
+
+
+
+ PositionStatus
+
+
+
+ 25
+
+
+
+ PositionLatitude
+
+
+
+ 26
+
+
+
+ PositionLongitude
+
+
+
+ 27
+
+
+
+ ListenStatus
+
+
+
+ 28
+
+
+
+ ListenLongitude
+
+
+
+ 29
+
+
+
+ ListenLatitude
+
+
+
+ 30
+
+
+
+ GetPosition:
+
+
+ 7
+
+ 31
+
+
+
+ CancelPosition:
+
+
+ 7
+
+ 35
+
+
+
+ ToggleListening:
+
+
+ 7
+
+ 36
+
+
+
+
+
+ 0
+
+
+
+
+
+ -1
+
+
+ File's Owner
+
+
+ -2
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+ 9
+
+
+
+
+ 10
+
+
+
+
+ 11
+
+
+
+
+ 12
+
+
+
+
+ 13
+
+
+
+
+ 14
+
+
+
+
+ 15
+
+
+
+
+ 16
+
+
+
+
+ 17
+
+
+
+
+
+
+ SampleViewController
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ UIResponder
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+
+
+
+
+
+ 36
+
+
+
+
+ SampleViewController
+ UIViewController
+
+ id
+ id
+ id
+
+
+
+ CancelPosition:
+ id
+
+
+ GetPosition:
+ id
+
+
+ ToggleListening:
+ id
+
+
+
+ UIButton
+ UILabel
+ UILabel
+ UILabel
+ UIButton
+ UILabel
+ UILabel
+ UILabel
+ UIButton
+
+
+
+ CancelButton
+ UIButton
+
+
+ ListenLatitude
+ UILabel
+
+
+ ListenLongitude
+ UILabel
+
+
+ ListenStatus
+ UILabel
+
+
+ PositionButton
+ UIButton
+
+
+ PositionLatitude
+ UILabel
+
+
+ PositionLongitude
+ UILabel
+
+
+ PositionStatus
+ UILabel
+
+
+ ToggleListeningButton
+ UIButton
+
+
+
+ IBProjectSource
+ ../SampleViewController.h
+
+
+
+ SampleViewController
+
+ id
+ id
+ id
+
+
+
+ CancelPosition:
+ id
+
+
+ GetPosition:
+ id
+
+
+ ToggleListening:
+ id
+
+
+
+ IBProjectSource
+ ../SampleViewController.m
+
+
+
+
+
+ UIButton
+ UIControl
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIButton.h
+
+
+
+ UIControl
+ UIView
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIControl.h
+
+
+
+ UIGestureRecognizer
+ NSObject
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIGestureRecognizer.h
+
+
+
+ UILabel
+ UIView
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UILabel.h
+
+
+
+ UIResponder
+ NSObject
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIResponder.h
+
+
+
+ UISearchBar
+ UIView
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UISearchBar.h
+
+
+
+ UISearchDisplayController
+ NSObject
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UISearchDisplayController.h
+
+
+
+ UIView
+ UIResponder
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIView.h
+
+
+
+ UIViewController
+ UIResponder
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIViewController.h
+
+
+
+
+ 0
+ IBCocoaTouchFramework
+ NO
+
+ com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3
+
+
+ YES
+ 3
+
+
diff --git a/MonoTouch/Samples/Geolocation/AppDelegate.cs b/MonoTouch/Samples/Geolocation/AppDelegate.cs
new file mode 100644
index 0000000..57c0454
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation/AppDelegate.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Foundation;
+using UIKit;
+
+namespace Sample
+{
+ // The UIApplicationDelegate for the application. This class is responsible for launching the
+ // User Interface of the application, as well as listening (and optionally responding) to
+ // application events from iOS.
+ [Register ("AppDelegate")]
+ public partial class AppDelegate : UIApplicationDelegate
+ {
+ // class-level declarations
+ UIWindow window;
+ SampleViewController viewController;
+
+ //
+ // This method is invoked when the application has loaded and is ready to run. In this
+ // method you should instantiate the window, load the UI into it and then make the window
+ // visible.
+ //
+ // You have 17 seconds to return from this method, or iOS will terminate your application.
+ //
+ public override bool FinishedLaunching (UIApplication app, NSDictionary options)
+ {
+ window = new UIWindow (UIScreen.MainScreen.Bounds);
+
+ viewController = new SampleViewController ();
+ window.RootViewController = viewController;
+ window.MakeKeyAndVisible ();
+
+ return true;
+ }
+ }
+}
+
diff --git a/MonoTouch/Samples/Geolocation/Geolocation Sample.csproj b/MonoTouch/Samples/Geolocation/Geolocation Sample.csproj
new file mode 100644
index 0000000..50affc2
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation/Geolocation Sample.csproj
@@ -0,0 +1,99 @@
+
+
+
+ Debug
+ iPhoneSimulator
+ 8.0.30703
+ 2.0
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}
+ {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Exe
+ Sample
+ Sample
+
+
+ True
+ full
+ False
+ bin\iPhoneSimulator\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ None
+ True
+ ARMv7
+
+
+ none
+ False
+ bin\iPhoneSimulator\Release
+ prompt
+ 4
+ False
+ None
+
+
+ True
+ full
+ False
+ bin\iPhone\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ true
+ iPhone Developer
+ ARMv7
+
+
+
+
+ False
+
+
+ none
+ False
+ bin\iPhone\Release
+ prompt
+ 4
+ False
+ iPhone Developer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SampleViewController.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}
+ Xamarin.Mobile.iOS
+
+
+
\ No newline at end of file
diff --git a/MonoTouch/Samples/Geolocation/Info.plist b/MonoTouch/Samples/Geolocation/Info.plist
new file mode 100644
index 0000000..50dc7a7
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation/Info.plist
@@ -0,0 +1,28 @@
+
+
+
+
+ MinimumOSVersion
+ 5.2
+ UIDeviceFamily
+
+ 1
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ CFBundleDisplayName
+ X.M Geolocation
+ CFBundleIdentifier
+ com.xamarin.mobile.geolocationsample
+ CFBundleVersion
+
+ NSMainNibFile
+
+ NSLocationWhenInUseUsageDescription
+ Please allow the sample app to access Location!
+
+
diff --git a/MonoTouch/Samples/Geolocation/Main.cs b/MonoTouch/Samples/Geolocation/Main.cs
new file mode 100644
index 0000000..757f383
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation/Main.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Foundation;
+using UIKit;
+
+namespace Sample
+{
+ public class Application
+ {
+ // This is the main entry point of the application.
+ static void Main (string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main (args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/MonoTouch/Samples/Geolocation/Resources/Default-568h@2x.png b/MonoTouch/Samples/Geolocation/Resources/Default-568h@2x.png
new file mode 100644
index 0000000..b3f6678
Binary files /dev/null and b/MonoTouch/Samples/Geolocation/Resources/Default-568h@2x.png differ
diff --git a/MonoTouch/Samples/Geolocation/Resources/Default.png b/MonoTouch/Samples/Geolocation/Resources/Default.png
new file mode 100644
index 0000000..7ad63b0
Binary files /dev/null and b/MonoTouch/Samples/Geolocation/Resources/Default.png differ
diff --git a/MonoTouch/Samples/Geolocation/Resources/Default@2x.png b/MonoTouch/Samples/Geolocation/Resources/Default@2x.png
new file mode 100644
index 0000000..8d59426
Binary files /dev/null and b/MonoTouch/Samples/Geolocation/Resources/Default@2x.png differ
diff --git a/MonoTouch/Samples/Geolocation/SampleViewController.cs b/MonoTouch/Samples/Geolocation/SampleViewController.cs
new file mode 100644
index 0000000..8ab07c3
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation/SampleViewController.cs
@@ -0,0 +1,127 @@
+using UIKit;
+using System;
+using Foundation;
+using System.Threading;
+using Xamarin.Geolocation;
+using System.Threading.Tasks;
+
+namespace Sample
+{
+ public partial class SampleViewController : UIViewController
+ {
+ #region Boilerplate
+ public SampleViewController () : base ("SampleViewController", null)
+ {
+ }
+
+ public override void DidReceiveMemoryWarning ()
+ {
+ // Releases the view if it doesn't have a superview.
+ base.DidReceiveMemoryWarning ();
+
+ // Release any cached data, images, etc that aren't in use.
+ }
+
+ public override void ViewDidLoad ()
+ {
+ base.ViewDidLoad ();
+ }
+
+ public override void ViewDidUnload ()
+ {
+ base.ViewDidUnload ();
+
+ // Release any retained subviews of the main view.
+ // e.g. myOutlet = null;
+ }
+
+ public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
+ {
+ // Return true for supported orientations
+ return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
+ }
+ #endregion
+
+ private Geolocator geolocator;
+
+ private TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
+ private CancellationTokenSource cancelSource;
+
+ private void Setup()
+ {
+ if (this.geolocator != null)
+ return;
+
+ this.geolocator = new Geolocator { DesiredAccuracy = 50 };
+ this.geolocator.PositionError += OnListeningError;
+ this.geolocator.PositionChanged += OnPositionChanged;
+ }
+
+ partial void GetPosition (NSObject sender)
+ {
+ Setup();
+
+ this.cancelSource = new CancellationTokenSource();
+
+ PositionStatus.Text = String.Empty;
+ PositionLatitude.Text = String.Empty;
+ PositionLongitude.Text = String.Empty;
+
+ this.geolocator.GetPositionAsync (timeout: 10000, cancelToken: this.cancelSource.Token, includeHeading: true)
+ .ContinueWith (t =>
+ {
+ if (t.IsFaulted)
+ PositionStatus.Text = ((GeolocationException)t.Exception.InnerException).Error.ToString();
+ else if (t.IsCanceled)
+ PositionStatus.Text = "Canceled";
+ else
+ {
+ PositionStatus.Text = t.Result.Timestamp.ToString("G");
+ PositionLatitude.Text = "La: " + t.Result.Latitude.ToString("N4");
+ PositionLongitude.Text = "Lo: " + t.Result.Longitude.ToString("N4");
+ }
+
+ }, scheduler);
+ }
+
+ partial void CancelPosition (NSObject sender)
+ {
+ CancellationTokenSource cancel = this.cancelSource;
+ if (cancel != null)
+ cancel.Cancel();
+ }
+
+ partial void ToggleListening (NSObject sender)
+ {
+ Setup();
+
+ if (!this.geolocator.IsListening)
+ {
+ ToggleListeningButton.SetTitle ("Stop listening", UIControlState.Normal);
+
+ this.geolocator.StartListening (minTime: 30000, minDistance: 0, includeHeading: true);
+ }
+ else
+ {
+ ToggleListeningButton.SetTitle ("Start listening", UIControlState.Normal);
+ this.geolocator.StopListening();
+ }
+ }
+
+ private void OnListeningError (object sender, PositionErrorEventArgs e)
+ {
+ BeginInvokeOnMainThread (() => {
+ ListenStatus.Text = e.Error.ToString();
+ });
+ }
+
+ private void OnPositionChanged (object sender, PositionEventArgs e)
+ {
+ BeginInvokeOnMainThread (() => {
+ ListenStatus.Text = e.Position.Timestamp.ToString("G");
+ ListenLatitude.Text = "La: " + e.Position.Latitude.ToString("N4");
+ ListenLongitude.Text = "Lo: " + e.Position.Longitude.ToString("N4");
+ });
+ }
+ }
+}
diff --git a/MonoTouch/Samples/Geolocation/SampleViewController.designer.cs b/MonoTouch/Samples/Geolocation/SampleViewController.designer.cs
new file mode 100644
index 0000000..fd03d1e
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation/SampleViewController.designer.cs
@@ -0,0 +1,50 @@
+// WARNING
+//
+// This file has been generated automatically by MonoDevelop to store outlets and
+// actions made in the Xcode designer. If it is removed, they will be lost.
+// Manual changes to this file may not be handled correctly.
+//
+using Foundation;
+
+namespace Sample
+{
+ [Register ("SampleViewController")]
+ partial class SampleViewController
+ {
+ [Outlet]
+ UIKit.UIButton PositionButton { get; set; }
+
+ [Outlet]
+ UIKit.UIButton CancelButton { get; set; }
+
+ [Outlet]
+ UIKit.UIButton ToggleListeningButton { get; set; }
+
+ [Outlet]
+ UIKit.UILabel PositionStatus { get; set; }
+
+ [Outlet]
+ UIKit.UILabel PositionLatitude { get; set; }
+
+ [Outlet]
+ UIKit.UILabel PositionLongitude { get; set; }
+
+ [Outlet]
+ UIKit.UILabel ListenStatus { get; set; }
+
+ [Outlet]
+ UIKit.UILabel ListenLongitude { get; set; }
+
+ [Outlet]
+ UIKit.UILabel ListenLatitude { get; set; }
+
+ [Action ("GetPosition:")]
+ partial void GetPosition (Foundation.NSObject sender);
+
+ [Action ("CancelPosition:")]
+ partial void CancelPosition (Foundation.NSObject sender);
+
+ [Action ("ToggleListening:")]
+ partial void ToggleListening (Foundation.NSObject sender);
+ }
+}
diff --git a/MonoTouch/Samples/Geolocation/SampleViewController.xib b/MonoTouch/Samples/Geolocation/SampleViewController.xib
new file mode 100644
index 0000000..eaacb8d
--- /dev/null
+++ b/MonoTouch/Samples/Geolocation/SampleViewController.xib
@@ -0,0 +1,713 @@
+
+
+
+ 2048
+ 14B25
+ 6254
+ 1343.16
+ 755.00
+
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ 6247
+
+
+ IBProxyObject
+ IBUIButton
+ IBUILabel
+ IBUIView
+
+
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+
+
+ PluginDependencyRecalculationVersion
+
+
+
+
+ IBFilesOwner
+ IBCocoaTouchFramework
+
+
+ IBFirstResponder
+ IBCocoaTouchFramework
+
+
+
+ 274
+
+
+
+ 292
+ {{163, 95}, {137, 37}}
+
+
+
+ _NS:225
+ NO
+ IBCocoaTouchFramework
+ 0
+ 0
+ 1
+
+ 1
+ MC4xOTYwNzg0MzE0IDAuMzA5ODAzOTIxNiAwLjUyMTU2ODYyNzUAA
+
+
+ 3
+ MQA
+
+ Get position
+
+ 3
+ MC41AA
+
+
+ 2
+ 15
+
+
+ HelveticaNeue-Bold
+ 15
+ 16
+
+
+
+
+ 292
+ {{163, 140}, {137, 37}}
+
+
+
+ _NS:225
+ NO
+ IBCocoaTouchFramework
+ 0
+ 0
+ 1
+
+
+ Cancel position
+
+
+
+
+
+
+ 292
+ {{20, 95}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+ 1
+ MCAwIDAAA
+ darkTextColor
+
+
+ 1
+ 10
+
+ 1
+ 17
+
+
+ HelveticaNeue
+ 17
+ 16
+
+ YES
+
+
+
+ 292
+ {{20, 124}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{20, 153}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{163, 234}, {137, 37}}
+
+
+
+ _NS:225
+ NO
+ IBCocoaTouchFramework
+ 0
+ 0
+ 1
+
+
+ Start listening
+
+
+
+
+
+
+ 292
+ {{20, 242}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{20, 271}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{20, 329}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+
+ 292
+ {{20, 300}, {135, 21}}
+
+
+
+ _NS:328
+ NO
+ YES
+ 7
+ NO
+ IBCocoaTouchFramework
+
+
+
+ 1
+ 10
+
+
+ YES
+
+
+ {{0, 20}, {320, 460}}
+
+
+
+
+ 3
+ MC43NQA
+
+ 2
+
+
+ NO
+
+
+ IBUISimulatedFreeformSizeMetricsSentinel
+ Freeform
+
+ IBCocoaTouchFramework
+
+
+
+
+
+
+ view
+
+
+
+ 7
+
+
+
+ PositionButton
+
+
+
+ 22
+
+
+
+ CancelButton
+
+
+
+ 23
+
+
+
+ ToggleListeningButton
+
+
+
+ 24
+
+
+
+ PositionStatus
+
+
+
+ 25
+
+
+
+ PositionLatitude
+
+
+
+ 26
+
+
+
+ PositionLongitude
+
+
+
+ 27
+
+
+
+ ListenStatus
+
+
+
+ 28
+
+
+
+ ListenLongitude
+
+
+
+ 29
+
+
+
+ ListenLatitude
+
+
+
+ 30
+
+
+
+ GetPosition:
+
+
+ 7
+
+ 31
+
+
+
+ CancelPosition:
+
+
+ 7
+
+ 35
+
+
+
+ ToggleListening:
+
+
+ 7
+
+ 36
+
+
+
+
+
+ 0
+
+
+
+
+
+ -1
+
+
+ File's Owner
+
+
+ -2
+
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
+
+
+
+
+ 9
+
+
+
+
+ 10
+
+
+
+
+ 11
+
+
+
+
+ 12
+
+
+
+
+ 13
+
+
+
+
+ 14
+
+
+
+
+ 15
+
+
+
+
+ 16
+
+
+
+
+ 17
+
+
+
+
+
+
+ SampleViewController
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ UIResponder
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+
+
+
+
+
+ 36
+
+
+
+
+ SampleViewController
+ UIViewController
+
+ id
+ id
+ id
+
+
+
+ CancelPosition:
+ id
+
+
+ GetPosition:
+ id
+
+
+ ToggleListening:
+ id
+
+
+
+ UIButton
+ UILabel
+ UILabel
+ UILabel
+ UIButton
+ UILabel
+ UILabel
+ UILabel
+ UIButton
+
+
+
+ CancelButton
+ UIButton
+
+
+ ListenLatitude
+ UILabel
+
+
+ ListenLongitude
+ UILabel
+
+
+ ListenStatus
+ UILabel
+
+
+ PositionButton
+ UIButton
+
+
+ PositionLatitude
+ UILabel
+
+
+ PositionLongitude
+ UILabel
+
+
+ PositionStatus
+ UILabel
+
+
+ ToggleListeningButton
+ UIButton
+
+
+
+ IBProjectSource
+ ../SampleViewController.h
+
+
+
+ SampleViewController
+
+ id
+ id
+ id
+
+
+
+ CancelPosition:
+ id
+
+
+ GetPosition:
+ id
+
+
+ ToggleListening:
+ id
+
+
+
+ IBProjectSource
+ ../SampleViewController.m
+
+
+
+
+
+ UIButton
+ UIControl
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIButton.h
+
+
+
+ UIControl
+ UIView
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIControl.h
+
+
+
+ UIGestureRecognizer
+ NSObject
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIGestureRecognizer.h
+
+
+
+ UILabel
+ UIView
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UILabel.h
+
+
+
+ UIResponder
+ NSObject
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIResponder.h
+
+
+
+ UISearchBar
+ UIView
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UISearchBar.h
+
+
+
+ UISearchDisplayController
+ NSObject
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UISearchDisplayController.h
+
+
+
+ UIView
+ UIResponder
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIView.h
+
+
+
+ UIViewController
+ UIResponder
+
+ IBFrameworkSource
+ UIKit.framework/Headers/UIViewController.h
+
+
+
+
+ 0
+ IBCocoaTouchFramework
+ NO
+
+ com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3
+
+
+ YES
+ 3
+
+
diff --git a/MonoTouch/Samples/MediaPickerSample-Classic/AppDelegate.cs b/MonoTouch/Samples/MediaPickerSample-Classic/AppDelegate.cs
new file mode 100644
index 0000000..85fbb3b
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample-Classic/AppDelegate.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Threading.Tasks;
+using MonoTouch.Dialog;
+using MonoTouch.Foundation;
+using MonoTouch.MediaPlayer;
+using MonoTouch.UIKit;
+using Xamarin.Media;
+
+namespace MediaPickerSample
+{
+ [Register ("AppDelegate")]
+ public partial class AppDelegate : UIApplicationDelegate
+ {
+ readonly MediaPicker mediaPicker = new MediaPicker();
+ readonly TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
+
+ private MediaPickerController mediaPickerController;
+ public override bool FinishedLaunching (UIApplication app, NSDictionary options)
+ {
+ pickPhoto = new StringElement ("Pick Photo");
+ pickPhoto.Tapped += () => {
+ mediaPickerController = mediaPicker.GetPickPhotoUI();
+ dialogController.PresentViewController (mediaPickerController, true, null);
+
+ mediaPickerController.GetResultAsync().ContinueWith (t => {
+ // We need to dismiss the controller ourselves
+ dialogController.DismissViewController (true, () => {
+ // User canceled or something went wrong
+ if (t.IsCanceled || t.IsFaulted)
+ return;
+
+ // We get back a MediaFile
+ MediaFile media = t.Result;
+ ShowPhoto (media);
+ });
+ }, uiScheduler); // Make sure we use the UI thread to show our photo.
+ };
+
+ takePhoto = new StringElement ("Take Photo");
+ takePhoto.Tapped += () => {
+ // Make sure we actually have a camera
+ if (!mediaPicker.IsCameraAvailable) {
+ ShowUnsupported();
+ return;
+ }
+
+ // When capturing new media, we can specify it's name and location
+ mediaPickerController = mediaPicker.GetTakePhotoUI (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+ });
+
+ dialogController.PresentViewController (mediaPickerController, true, null);
+
+ mediaPickerController.GetResultAsync().ContinueWith (t => {
+ // We need to dismiss the controller ourselves
+ dialogController.DismissViewController (true, () => {
+ // User canceled or something went wrong
+ if (t.IsCanceled || t.IsFaulted)
+ return;
+
+ // We get back a MediaFile
+ MediaFile media = t.Result;
+ ShowPhoto (media);
+ });
+ }, uiScheduler); // Make sure we use the UI thread to show our photo.
+ };
+
+ takeVideo = new StringElement ("Take Video");
+ takeVideo.Tapped += () => {
+ // Make sure video is supported and a camera is available
+ if (!mediaPicker.VideosSupported || !mediaPicker.IsCameraAvailable) {
+ ShowUnsupported();
+ return;
+ }
+
+ // When capturing video, we can hint at the desired quality and length.
+ // DesiredLength is only a hint, however, and the resulting video may
+ // be longer than desired.
+ mediaPickerController = mediaPicker.GetTakeVideoUI (new StoreVideoOptions {
+ Quality = VideoQuality.Medium,
+ DesiredLength = TimeSpan.FromSeconds (10),
+ Directory = "MediaPickerSample",
+ Name = "test.mp4"
+ });
+
+ dialogController.PresentViewController (mediaPickerController, true, null);
+
+ mediaPickerController.GetResultAsync().ContinueWith (t => {
+ // We need to dismiss the controller ourselves
+ dialogController.DismissViewController (true, () => {
+ // User canceled or something went wrong
+ if (t.IsCanceled || t.IsFaulted)
+ return;
+
+ // We get back a MediaFile
+ MediaFile media = t.Result;
+ ShowVideo (media);
+ });
+ }, uiScheduler); // Make sure we use the UI thread to show our video.
+ };
+
+ pickVideo = new StringElement ("Pick Video");
+ pickVideo.Tapped += () => {
+ if (!mediaPicker.VideosSupported) {
+ ShowUnsupported();
+ return;
+ }
+
+ mediaPickerController = mediaPicker.GetPickVideoUI();
+ dialogController.PresentViewController (mediaPickerController, true, null);
+
+ mediaPickerController.GetResultAsync().ContinueWith (t => {
+ // We need to dismiss the controller ourselves
+ dialogController.DismissViewController (true, () => {
+ // User canceled or something went wrong
+ if (t.IsCanceled || t.IsFaulted)
+ return;
+
+ // We get back a MediaFile
+ MediaFile media = t.Result;
+ ShowVideo (media);
+ });
+ }, uiScheduler); // Make sure we use the UI thread to show our video.
+ };
+
+ Action pickPhotoAction = async () => {
+ try {
+ var mediaFile = await mediaPicker.PickPhotoAsync ();
+ ShowPhoto (mediaFile);
+ } catch (TaskCanceledException) {
+ }
+ };
+
+ Action takePhotoAction = async () => {
+ if (!mediaPicker.VideosSupported || !mediaPicker.IsCameraAvailable) {
+ ShowUnsupported();
+ return;
+ }
+
+ try {
+ var mediaFile = await mediaPicker.TakePhotoAsync (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+ });
+ ShowPhoto (mediaFile);
+ } catch (TaskCanceledException) {
+ }
+ };
+
+ useActionSheet = new StringElement ("Use Action Sheet");
+ useActionSheet.Tapped += () => {
+
+ if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
+
+ var alertContoller = UIAlertController.Create ("Show Photo From?", string.Empty, UIAlertControllerStyle.ActionSheet);
+ alertContoller.AddAction (UIAlertAction.Create ("Pick Photo", UIAlertActionStyle.Default, (action) => pickPhotoAction ()));
+ alertContoller.AddAction (UIAlertAction.Create ("Take Photo", UIAlertActionStyle.Default, (action) => takePhotoAction ()));
+
+ if (UIDevice.CurrentDevice.UserInterfaceIdiom != UIUserInterfaceIdiom.Pad)
+ alertContoller.AddAction (UIAlertAction.Create ("Cancel", UIAlertActionStyle.Cancel, null));
+
+ if (alertContoller.PopoverPresentationController != null) {
+ alertContoller.PopoverPresentationController.PermittedArrowDirections = 0;
+
+ var rect = viewController.View.Bounds;
+ alertContoller.PopoverPresentationController.SourceRect = rect;
+ alertContoller.PopoverPresentationController.SourceView = viewController.View;
+ }
+
+ viewController.PresentViewController (alertContoller, true, null);
+ }
+ else {
+
+ var actionSheet = new UIActionSheet("Show Photo From?");
+ actionSheet.AddButton("Pick Photo");
+ actionSheet.AddButton("Take Photo");
+
+ if (UIDevice.CurrentDevice.UserInterfaceIdiom != UIUserInterfaceIdiom.Pad) {
+ actionSheet.AddButton("Cancel");
+ actionSheet.CancelButtonIndex = 2;
+ }
+
+ actionSheet.Clicked += (object sender, UIButtonEventArgs e) => {
+ if (e.ButtonIndex == 0)
+ pickPhotoAction ();
+ if (e.ButtonIndex == 1)
+ takePhotoAction ();
+ };
+
+ actionSheet.ShowInView(viewController.View);
+ }
+ };
+
+ var root = new RootElement("Xamarin.Media Sample") {
+ new Section ("Picking media") { pickPhoto, pickVideo },
+ new Section ("Capturing media") { takePhoto, takeVideo },
+ new Section ("Action Sheets") {useActionSheet}
+ };
+
+ dialogController = new DisposingMediaViewController (root);
+ viewController = new UINavigationController (dialogController);
+
+ window = new UIWindow (UIScreen.MainScreen.Bounds);
+ window.RootViewController = viewController;
+ window.MakeKeyAndVisible ();
+
+ return true;
+ }
+
+ private void ShowVideo (MediaFile media)
+ {
+ dialogController.Media = media;
+
+ moviePlayerView = new MPMoviePlayerViewController (NSUrl.FromFilename (media.Path));
+ viewController.PresentMoviePlayerViewController (moviePlayerView);
+ }
+
+ private void ShowPhoto (MediaFile media)
+ {
+ dialogController.Media = media;
+
+ image = new UIImageView (dialogController.View.Bounds);
+ image.ContentMode = UIViewContentMode.ScaleAspectFit;
+ image.Image = UIImage.FromFile (media.Path);
+
+ mediaController = new UIViewController();
+ mediaController.View.AddSubview (image);
+ mediaController.NavigationItem.LeftBarButtonItem =
+ new UIBarButtonItem (UIBarButtonSystemItem.Done, (s, e) => viewController.PopViewControllerAnimated (true));
+
+ viewController.PushViewController (mediaController, true);
+ }
+
+ private class DisposingMediaViewController : DialogViewController
+ {
+ public DisposingMediaViewController (RootElement root)
+ : base (root)
+ {
+ }
+
+ public MediaFile Media
+ {
+ get;
+ set;
+ }
+
+ public override void ViewDidAppear (bool animated)
+ {
+ // When we're done viewing the media, we should clean it up
+ if (Media != null) {
+ Media.Dispose();
+ Media = null;
+ }
+
+ base.ViewDidAppear (animated);
+ }
+ }
+
+ private UIAlertView errorAlert;
+ private void ShowUnsupported()
+ {
+ if (this.errorAlert != null)
+ this.errorAlert.Dispose();
+
+ this.errorAlert = new UIAlertView ("Device unsupported", "Your device does not support this feature",
+ new UIAlertViewDelegate(), "OK");
+ this.errorAlert.Show();
+ }
+
+ MPMoviePlayerController moviePlayer;
+ MPMoviePlayerViewController moviePlayerView;
+ UIViewController mediaController;
+ UIImageView image;
+
+ UIWindow window;
+ UINavigationController viewController;
+ DisposingMediaViewController dialogController;
+
+ StringElement pickPhoto, pickVideo, takePhoto, takeVideo, useActionSheet;
+ }
+}
+
diff --git a/MonoTouch/Samples/MediaPickerSample-Classic/Info.plist b/MonoTouch/Samples/MediaPickerSample-Classic/Info.plist
new file mode 100644
index 0000000..db1dbc1
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample-Classic/Info.plist
@@ -0,0 +1,31 @@
+
+
+
+
+ MinimumOSVersion
+ 5.0
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+
+ CFBundleDisplayName
+ X.M MediaPicker
+ CFBundleIdentifier
+ com.xamarin.mobile.mediapickersample
+ CFBundleVersion
+ 2
+ NSMainNibFile
+
+ NSMainNibFile~ipad
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/MonoTouch/Samples/MediaPickerSample-Classic/Main.cs b/MonoTouch/Samples/MediaPickerSample-Classic/Main.cs
new file mode 100644
index 0000000..109fce4
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample-Classic/Main.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MonoTouch.Foundation;
+using MonoTouch.UIKit;
+
+namespace MediaPickerSample
+{
+ public class Application
+ {
+ // This is the main entry point of the application.
+ static void Main (string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main (args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/MonoTouch/Samples/MediaPickerSample-Classic/MediaPicker Sample-Classic.csproj b/MonoTouch/Samples/MediaPickerSample-Classic/MediaPicker Sample-Classic.csproj
new file mode 100644
index 0000000..428f618
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample-Classic/MediaPicker Sample-Classic.csproj
@@ -0,0 +1,96 @@
+
+
+
+ Debug
+ iPhoneSimulator
+ 8.0.30703
+ 2.0
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}
+ {6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Exe
+ MediaPickerSample
+ MediaPickerSample
+
+
+ True
+ full
+ False
+ bin\iPhoneSimulator\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ True
+ True
+ None
+
+
+ ARMv7
+
+
+ none
+ False
+ bin\iPhoneSimulator\Release
+ prompt
+ 4
+ False
+ None
+
+
+ True
+ full
+ False
+ bin\iPhone\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ iPhone Developer
+ True
+ True
+
+
+
+
+ ARMv7
+
+
+ none
+ False
+ bin\iPhone\Release
+ prompt
+ 4
+ False
+ iPhone Developer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}
+ Xamarin.Mobile.iOS-Classic
+
+
+
+
\ No newline at end of file
diff --git a/MonoTouch/Samples/MediaPickerSample-Classic/MediaPickerSampleViewController.designer.cs b/MonoTouch/Samples/MediaPickerSample-Classic/MediaPickerSampleViewController.designer.cs
new file mode 100644
index 0000000..acbe2cd
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample-Classic/MediaPickerSampleViewController.designer.cs
@@ -0,0 +1,29 @@
+// WARNING
+//
+// This file has been generated automatically by MonoDevelop to store outlets and
+// actions made in the Xcode designer. If it is removed, they will be lost.
+// Manual changes to this file may not be handled correctly.
+//
+using MonoTouch.Foundation;
+
+namespace MediaPickerSample
+{
+ [Register ("MediaPickerSampleViewController")]
+ partial class MediaPickerSampleViewController
+ {
+ [Outlet]
+ MonoTouch.UIKit.UIImageView imageView { get; set; }
+
+ [Action ("takePhotoBtnClicked:")]
+ partial void takePhotoBtnClicked (MonoTouch.Foundation.NSObject sender);
+
+ [Action ("pickPhotoBtnClicked:")]
+ partial void pickPhotoBtnClicked (MonoTouch.Foundation.NSObject sender);
+
+ [Action ("takeVideoBtnClicked:")]
+ partial void takeVideoBtnClicked (MonoTouch.Foundation.NSObject sender);
+
+ [Action ("pickVideoBtnClicked:")]
+ partial void pickVideoBtnClicked (MonoTouch.Foundation.NSObject sender);
+ }
+}
diff --git a/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default-568h@2x.png b/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default-568h@2x.png
new file mode 100644
index 0000000..b3f6678
Binary files /dev/null and b/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default-568h@2x.png differ
diff --git a/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default.png b/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default.png
new file mode 100644
index 0000000..7ad63b0
Binary files /dev/null and b/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default.png differ
diff --git a/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default@2x.png b/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default@2x.png
new file mode 100644
index 0000000..8d59426
Binary files /dev/null and b/MonoTouch/Samples/MediaPickerSample-Classic/Resources/Default@2x.png differ
diff --git a/MonoTouch/Samples/MediaPickerSample/AppDelegate.cs b/MonoTouch/Samples/MediaPickerSample/AppDelegate.cs
new file mode 100644
index 0000000..baa05e2
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample/AppDelegate.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Threading.Tasks;
+using MonoTouch.Dialog;
+using Foundation;
+using MediaPlayer;
+using UIKit;
+using Xamarin.Media;
+
+namespace MediaPickerSample
+{
+ [Register ("AppDelegate")]
+ public partial class AppDelegate : UIApplicationDelegate
+ {
+ readonly MediaPicker mediaPicker = new MediaPicker();
+ readonly TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
+
+ private MediaPickerController mediaPickerController;
+ public override bool FinishedLaunching (UIApplication app, NSDictionary options)
+ {
+ pickPhoto = new StringElement ("Pick Photo");
+ pickPhoto.Tapped += () => {
+ mediaPickerController = mediaPicker.GetPickPhotoUI();
+ dialogController.PresentViewController (mediaPickerController, true, null);
+
+ mediaPickerController.GetResultAsync().ContinueWith (t => {
+ // We need to dismiss the controller ourselves
+ dialogController.DismissViewController (true, () => {
+ // User canceled or something went wrong
+ if (t.IsCanceled || t.IsFaulted)
+ return;
+
+ // We get back a MediaFile
+ MediaFile media = t.Result;
+ ShowPhoto (media);
+ });
+ }, uiScheduler); // Make sure we use the UI thread to show our photo.
+ };
+
+ takePhoto = new StringElement ("Take Photo");
+ takePhoto.Tapped += () => {
+ // Make sure we actually have a camera
+ if (!mediaPicker.IsCameraAvailable) {
+ ShowUnsupported();
+ return;
+ }
+
+ // When capturing new media, we can specify it's name and location
+ mediaPickerController = mediaPicker.GetTakePhotoUI (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+ });
+
+ dialogController.PresentViewController (mediaPickerController, true, null);
+
+ mediaPickerController.GetResultAsync().ContinueWith (t => {
+ // We need to dismiss the controller ourselves
+ dialogController.DismissViewController (true, () => {
+ // User canceled or something went wrong
+ if (t.IsCanceled || t.IsFaulted)
+ return;
+
+ // We get back a MediaFile
+ MediaFile media = t.Result;
+ ShowPhoto (media);
+ });
+ }, uiScheduler); // Make sure we use the UI thread to show our photo.
+ };
+
+ takeVideo = new StringElement ("Take Video");
+ takeVideo.Tapped += () => {
+ // Make sure video is supported and a camera is available
+ if (!mediaPicker.VideosSupported || !mediaPicker.IsCameraAvailable) {
+ ShowUnsupported();
+ return;
+ }
+
+ // When capturing video, we can hint at the desired quality and length.
+ // DesiredLength is only a hint, however, and the resulting video may
+ // be longer than desired.
+ mediaPickerController = mediaPicker.GetTakeVideoUI (new StoreVideoOptions {
+ Quality = VideoQuality.Medium,
+ DesiredLength = TimeSpan.FromSeconds (10),
+ Directory = "MediaPickerSample",
+ Name = "test.mp4"
+ });
+
+ dialogController.PresentViewController (mediaPickerController, true, null);
+
+ mediaPickerController.GetResultAsync().ContinueWith (t => {
+ // We need to dismiss the controller ourselves
+ dialogController.DismissViewController (true, () => {
+ // User canceled or something went wrong
+ if (t.IsCanceled || t.IsFaulted)
+ return;
+
+ // We get back a MediaFile
+ MediaFile media = t.Result;
+ ShowVideo (media);
+ });
+ }, uiScheduler); // Make sure we use the UI thread to show our video.
+ };
+
+ pickVideo = new StringElement ("Pick Video");
+ pickVideo.Tapped += () => {
+ if (!mediaPicker.VideosSupported) {
+ ShowUnsupported();
+ return;
+ }
+
+ mediaPickerController = mediaPicker.GetPickVideoUI();
+ dialogController.PresentViewController (mediaPickerController, true, null);
+
+ mediaPickerController.GetResultAsync().ContinueWith (t => {
+ // We need to dismiss the controller ourselves
+ dialogController.DismissViewController (true, () => {
+ // User canceled or something went wrong
+ if (t.IsCanceled || t.IsFaulted)
+ return;
+
+ // We get back a MediaFile
+ MediaFile media = t.Result;
+ ShowVideo (media);
+ });
+ }, uiScheduler); // Make sure we use the UI thread to show our video.
+ };
+
+ Action pickPhotoAction = async () => {
+ try {
+ var mediaFile = await mediaPicker.PickPhotoAsync ();
+ ShowPhoto (mediaFile);
+ } catch (TaskCanceledException) {
+ }
+ };
+
+ Action takePhotoAction = async () => {
+ if (!mediaPicker.VideosSupported || !mediaPicker.IsCameraAvailable) {
+ ShowUnsupported();
+ return;
+ }
+
+ try {
+ var mediaFile = await mediaPicker.TakePhotoAsync (new StoreCameraMediaOptions {
+ Name = "test.jpg",
+ Directory = "MediaPickerSample"
+ });
+ ShowPhoto (mediaFile);
+ } catch (TaskCanceledException) {
+ }
+ };
+
+ useActionSheet = new StringElement ("Use Action Sheet");
+ useActionSheet.Tapped += () => {
+
+ if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
+
+ var alertContoller = UIAlertController.Create ("Show Photo From?", string.Empty, UIAlertControllerStyle.ActionSheet);
+ alertContoller.AddAction (UIAlertAction.Create ("Pick Photo", UIAlertActionStyle.Default, (action) => pickPhotoAction ()));
+ alertContoller.AddAction (UIAlertAction.Create ("Take Photo", UIAlertActionStyle.Default, (action) => takePhotoAction ()));
+
+ if (UIDevice.CurrentDevice.UserInterfaceIdiom != UIUserInterfaceIdiom.Pad)
+ alertContoller.AddAction (UIAlertAction.Create ("Cancel", UIAlertActionStyle.Cancel, null));
+
+ if (alertContoller.PopoverPresentationController != null) {
+ alertContoller.PopoverPresentationController.PermittedArrowDirections = 0;
+
+ var rect = viewController.View.Bounds;
+ alertContoller.PopoverPresentationController.SourceRect = rect;
+ alertContoller.PopoverPresentationController.SourceView = viewController.View;
+ }
+
+ viewController.PresentViewController (alertContoller, true, null);
+ }
+ else {
+
+ var actionSheet = new UIActionSheet("Show Photo From?");
+ actionSheet.AddButton("Pick Photo");
+ actionSheet.AddButton("Take Photo");
+
+ if (UIDevice.CurrentDevice.UserInterfaceIdiom != UIUserInterfaceIdiom.Pad) {
+ actionSheet.AddButton("Cancel");
+ actionSheet.CancelButtonIndex = 2;
+ }
+
+ actionSheet.Clicked += (object sender, UIButtonEventArgs e) => {
+ if (e.ButtonIndex == 0)
+ pickPhotoAction ();
+ if (e.ButtonIndex == 1)
+ takePhotoAction ();
+ };
+
+ actionSheet.ShowInView(viewController.View);
+ }
+ };
+
+ var root = new RootElement("Xamarin.Media Sample") {
+ new Section ("Picking media") { pickPhoto, pickVideo },
+ new Section ("Capturing media") { takePhoto, takeVideo },
+ new Section ("Action Sheets") {useActionSheet}
+ };
+
+ dialogController = new DisposingMediaViewController (root);
+ viewController = new UINavigationController (dialogController);
+
+ window = new UIWindow (UIScreen.MainScreen.Bounds);
+ window.RootViewController = viewController;
+ window.MakeKeyAndVisible ();
+
+ return true;
+ }
+
+ private void ShowVideo (MediaFile media)
+ {
+ dialogController.Media = media;
+
+ moviePlayerView = new MPMoviePlayerViewController (NSUrl.FromFilename (media.Path));
+ viewController.PresentMoviePlayerViewController (moviePlayerView);
+ }
+
+ private void ShowPhoto (MediaFile media)
+ {
+ dialogController.Media = media;
+
+ image = new UIImageView (dialogController.View.Bounds);
+ image.ContentMode = UIViewContentMode.ScaleAspectFit;
+ image.Image = UIImage.FromFile (media.Path);
+
+ mediaController = new UIViewController();
+ mediaController.View.AddSubview (image);
+ mediaController.NavigationItem.LeftBarButtonItem =
+ new UIBarButtonItem (UIBarButtonSystemItem.Done, (s, e) => viewController.PopViewController (true));
+
+ viewController.PushViewController (mediaController, true);
+ }
+
+ private class DisposingMediaViewController : DialogViewController
+ {
+ public DisposingMediaViewController (RootElement root)
+ : base (root)
+ {
+ }
+
+ public MediaFile Media
+ {
+ get;
+ set;
+ }
+
+ public override void ViewDidAppear (bool animated)
+ {
+ // When we're done viewing the media, we should clean it up
+ if (Media != null) {
+ Media.Dispose();
+ Media = null;
+ }
+
+ base.ViewDidAppear (animated);
+ }
+ }
+
+ private UIAlertView errorAlert;
+ private void ShowUnsupported()
+ {
+ if (this.errorAlert != null)
+ this.errorAlert.Dispose();
+
+ this.errorAlert = new UIAlertView ("Device unsupported", "Your device does not support this feature",
+ new UIAlertViewDelegate(), "OK");
+ this.errorAlert.Show();
+ }
+
+ MPMoviePlayerController moviePlayer;
+ MPMoviePlayerViewController moviePlayerView;
+ UIViewController mediaController;
+ UIImageView image;
+
+ UIWindow window;
+ UINavigationController viewController;
+ DisposingMediaViewController dialogController;
+
+ StringElement pickPhoto, pickVideo, takePhoto, takeVideo, useActionSheet;
+ }
+}
+
diff --git a/MonoTouch/Samples/MediaPickerSample/Info.plist b/MonoTouch/Samples/MediaPickerSample/Info.plist
new file mode 100644
index 0000000..a7c87b9
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample/Info.plist
@@ -0,0 +1,31 @@
+
+
+
+
+ MinimumOSVersion
+ 5.2
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+
+ CFBundleDisplayName
+ X.M MediaPicker
+ CFBundleIdentifier
+ com.xamarin.mobile.mediapickersample
+ CFBundleVersion
+ 2
+ NSMainNibFile
+
+ NSMainNibFile~ipad
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/MonoTouch/Samples/MediaPickerSample/Main.cs b/MonoTouch/Samples/MediaPickerSample/Main.cs
new file mode 100644
index 0000000..69b4971
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample/Main.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Foundation;
+using UIKit;
+
+namespace MediaPickerSample
+{
+ public class Application
+ {
+ // This is the main entry point of the application.
+ static void Main (string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main (args, null, "AppDelegate");
+ }
+ }
+}
diff --git a/MonoTouch/Samples/MediaPickerSample/MediaPicker Sample.csproj b/MonoTouch/Samples/MediaPickerSample/MediaPicker Sample.csproj
new file mode 100644
index 0000000..0c88807
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample/MediaPicker Sample.csproj
@@ -0,0 +1,97 @@
+
+
+
+ Debug
+ iPhoneSimulator
+ 8.0.30703
+ 2.0
+ {1CC265CC-D110-4217-9748-D33DBF700436}
+ {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Exe
+ MediaPickerSample
+ MediaPickerSample
+
+
+ True
+ full
+ False
+ bin\iPhoneSimulator\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ True
+ True
+ None
+
+
+ ARMv7
+
+
+ none
+ False
+ bin\iPhoneSimulator\Release
+ prompt
+ 4
+ False
+ None
+
+
+ True
+ full
+ False
+ bin\iPhone\Debug
+ DEBUG;
+ prompt
+ 4
+ False
+ iPhone Developer
+ true
+ true
+
+
+
+
+ ARMv7
+ False
+
+
+ none
+ False
+ bin\iPhone\Release
+ prompt
+ 4
+ False
+ iPhone Developer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}
+ Xamarin.Mobile.iOS
+
+
+
\ No newline at end of file
diff --git a/MonoTouch/Samples/MediaPickerSample/MediaPickerSampleViewController.designer.cs b/MonoTouch/Samples/MediaPickerSample/MediaPickerSampleViewController.designer.cs
new file mode 100644
index 0000000..acbe2cd
--- /dev/null
+++ b/MonoTouch/Samples/MediaPickerSample/MediaPickerSampleViewController.designer.cs
@@ -0,0 +1,29 @@
+// WARNING
+//
+// This file has been generated automatically by MonoDevelop to store outlets and
+// actions made in the Xcode designer. If it is removed, they will be lost.
+// Manual changes to this file may not be handled correctly.
+//
+using MonoTouch.Foundation;
+
+namespace MediaPickerSample
+{
+ [Register ("MediaPickerSampleViewController")]
+ partial class MediaPickerSampleViewController
+ {
+ [Outlet]
+ MonoTouch.UIKit.UIImageView imageView { get; set; }
+
+ [Action ("takePhotoBtnClicked:")]
+ partial void takePhotoBtnClicked (MonoTouch.Foundation.NSObject sender);
+
+ [Action ("pickPhotoBtnClicked:")]
+ partial void pickPhotoBtnClicked (MonoTouch.Foundation.NSObject sender);
+
+ [Action ("takeVideoBtnClicked:")]
+ partial void takeVideoBtnClicked (MonoTouch.Foundation.NSObject sender);
+
+ [Action ("pickVideoBtnClicked:")]
+ partial void pickVideoBtnClicked (MonoTouch.Foundation.NSObject sender);
+ }
+}
diff --git a/MonoTouch/Samples/MediaPickerSample/Resources/Default-568h@2x.png b/MonoTouch/Samples/MediaPickerSample/Resources/Default-568h@2x.png
new file mode 100644
index 0000000..b3f6678
Binary files /dev/null and b/MonoTouch/Samples/MediaPickerSample/Resources/Default-568h@2x.png differ
diff --git a/MonoTouch/Samples/MediaPickerSample/Resources/Default.png b/MonoTouch/Samples/MediaPickerSample/Resources/Default.png
new file mode 100644
index 0000000..7ad63b0
Binary files /dev/null and b/MonoTouch/Samples/MediaPickerSample/Resources/Default.png differ
diff --git a/MonoTouch/Samples/MediaPickerSample/Resources/Default@2x.png b/MonoTouch/Samples/MediaPickerSample/Resources/Default@2x.png
new file mode 100644
index 0000000..8d59426
Binary files /dev/null and b/MonoTouch/Samples/MediaPickerSample/Resources/Default@2x.png differ
diff --git a/MonoTouch/Samples/Xamarin.Mobile.iOS-Classic.Samples.sln b/MonoTouch/Samples/Xamarin.Mobile.iOS-Classic.Samples.sln
new file mode 100644
index 0000000..ccf6f04
--- /dev/null
+++ b/MonoTouch/Samples/Xamarin.Mobile.iOS-Classic.Samples.sln
@@ -0,0 +1,56 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Mobile.iOS-Classic", "..\Xamarin.Mobile\Xamarin.Mobile.iOS-Classic.csproj", "{87C4E91E-8215-46E6-BC21-41650EEB8C92}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contacts Sample-Classic", "ContactsSample-Classic\Contacts Sample-Classic.csproj", "{0F36CBF1-1358-4FD3-8631-2775881B2635}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geolocation Sample-Classic", "Geolocation-Classic\Geolocation Sample-Classic.csproj", "{B110CA48-4524-4E13-B4E1-B4A4C54EC875}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaPicker Sample-Classic", "MediaPickerSample-Classic\MediaPicker Sample-Classic.csproj", "{64565954-31A4-46EE-ACB1-A362405CE6FE}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|iPhoneSimulator = Debug|iPhoneSimulator
+ Release|iPhoneSimulator = Release|iPhoneSimulator
+ Debug|iPhone = Debug|iPhone
+ Release|iPhone = Release|iPhone
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Debug|iPhone.Build.0 = Debug|iPhone
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Release|iPhone.ActiveCfg = Release|iPhone
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Release|iPhone.Build.0 = Release|iPhone
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Debug|iPhone.Build.0 = Debug|iPhone
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Release|iPhone.ActiveCfg = Release|iPhone
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Release|iPhone.Build.0 = Release|iPhone
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhone.Build.0 = Debug|iPhone
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhone.ActiveCfg = Release|iPhone
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhone.Build.0 = Release|iPhone
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Debug|iPhone.Build.0 = Debug|iPhone
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Release|iPhone.ActiveCfg = Release|iPhone
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Release|iPhone.Build.0 = Release|iPhone
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = ContactsSample-Classic\Contacts Sample-Classic.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/MonoTouch/Samples/Xamarin.Mobile.iOS.Samples.sln b/MonoTouch/Samples/Xamarin.Mobile.iOS.Samples.sln
new file mode 100644
index 0000000..16beebd
--- /dev/null
+++ b/MonoTouch/Samples/Xamarin.Mobile.iOS.Samples.sln
@@ -0,0 +1,56 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contacts Sample", "ContactsSample\Contacts Sample.csproj", "{B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geolocation Sample", "Geolocation\Geolocation Sample.csproj", "{BF5C6B91-152F-4C98-9C8C-C310B9BB7902}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaPicker Sample", "MediaPickerSample\MediaPicker Sample.csproj", "{1CC265CC-D110-4217-9748-D33DBF700436}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Mobile.iOS", "..\Xamarin.Mobile\Xamarin.Mobile.iOS.csproj", "{9A5D042F-607D-4E67-8FCE-176A8A7B21C0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|iPhoneSimulator = Debug|iPhoneSimulator
+ Release|iPhoneSimulator = Release|iPhoneSimulator
+ Debug|iPhone = Debug|iPhone
+ Release|iPhone = Release|iPhone
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Debug|iPhone.Build.0 = Debug|iPhone
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Release|iPhone.ActiveCfg = Release|iPhone
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Release|iPhone.Build.0 = Release|iPhone
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Debug|iPhone.Build.0 = Debug|iPhone
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Release|iPhone.ActiveCfg = Release|iPhone
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Release|iPhone.Build.0 = Release|iPhone
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Debug|iPhone.Build.0 = Debug|iPhone
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Release|iPhone.ActiveCfg = Release|iPhone
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Release|iPhone.Build.0 = Release|iPhone
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Debug|iPhone.Build.0 = Debug|iPhone
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Release|iPhone.ActiveCfg = Release|iPhone
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Release|iPhone.Build.0 = Release|iPhone
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = ContactsSample\Contacts Sample.csproj
+ EndGlobalSection
+EndGlobal
diff --git a/MonoTouch/Xamarin.Mobile iOS.sln b/MonoTouch/Xamarin.Mobile iOS.sln
new file mode 100644
index 0000000..9bd1845
--- /dev/null
+++ b/MonoTouch/Xamarin.Mobile iOS.sln
@@ -0,0 +1,109 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{F52EBD5B-7377-4856-8DBF-B85FDA42B65E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contacts Sample", "Samples\ContactsSample\Contacts Sample.csproj", "{B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geolocation Sample", "Samples\Geolocation\Geolocation Sample.csproj", "{BF5C6B91-152F-4C98-9C8C-C310B9BB7902}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaPicker Sample", "Samples\MediaPickerSample\MediaPicker Sample.csproj", "{1CC265CC-D110-4217-9748-D33DBF700436}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contacts Sample-Classic", "Samples\ContactsSample-Classic\Contacts Sample-Classic.csproj", "{0F36CBF1-1358-4FD3-8631-2775881B2635}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geolocation Sample-Classic", "Samples\Geolocation-Classic\Geolocation Sample-Classic.csproj", "{B110CA48-4524-4E13-B4E1-B4A4C54EC875}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaPicker Sample-Classic", "Samples\MediaPickerSample-Classic\MediaPicker Sample-Classic.csproj", "{64565954-31A4-46EE-ACB1-A362405CE6FE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Mobile.iOS", "Xamarin.Mobile\Xamarin.Mobile.iOS.csproj", "{9A5D042F-607D-4E67-8FCE-176A8A7B21C0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Mobile.iOS-Classic", "Xamarin.Mobile\Xamarin.Mobile.iOS-Classic.csproj", "{87C4E91E-8215-46E6-BC21-41650EEB8C92}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|iPhone = Debug|iPhone
+ Debug|iPhoneSimulator = Debug|iPhoneSimulator
+ Release|iPhone = Release|iPhone
+ Release|iPhoneSimulator = Release|iPhoneSimulator
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Debug|iPhone.Build.0 = Debug|iPhone
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Release|iPhone.ActiveCfg = Release|iPhone
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Release|iPhone.Build.0 = Release|iPhone
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {0F36CBF1-1358-4FD3-8631-2775881B2635}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Debug|iPhone.Build.0 = Debug|iPhone
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Release|iPhone.ActiveCfg = Release|iPhone
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Release|iPhone.Build.0 = Release|iPhone
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {1CC265CC-D110-4217-9748-D33DBF700436}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Debug|iPhone.Build.0 = Debug|iPhone
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Release|iPhone.ActiveCfg = Release|iPhone
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Release|iPhone.Build.0 = Release|iPhone
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {64565954-31A4-46EE-ACB1-A362405CE6FE}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhone.Build.0 = Debug|iPhone
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhone.ActiveCfg = Release|iPhone
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhone.Build.0 = Release|iPhone
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {87C4E91E-8215-46E6-BC21-41650EEB8C92}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Debug|iPhone.Build.0 = Debug|iPhone
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Release|iPhone.ActiveCfg = Release|iPhone
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Release|iPhone.Build.0 = Release|iPhone
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {9A5D042F-607D-4E67-8FCE-176A8A7B21C0}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Debug|iPhone.Build.0 = Debug|iPhone
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Release|iPhone.ActiveCfg = Release|iPhone
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Release|iPhone.Build.0 = Release|iPhone
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Debug|iPhone.Build.0 = Debug|iPhone
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Release|iPhone.ActiveCfg = Release|iPhone
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Release|iPhone.Build.0 = Release|iPhone
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Debug|iPhone.ActiveCfg = Debug|iPhone
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Debug|iPhone.Build.0 = Debug|iPhone
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Release|iPhone.ActiveCfg = Release|iPhone
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Release|iPhone.Build.0 = Release|iPhone
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {B0B85C2F-3134-40C4-9B5D-1C73A8CB0703} = {F52EBD5B-7377-4856-8DBF-B85FDA42B65E}
+ {BF5C6B91-152F-4C98-9C8C-C310B9BB7902} = {F52EBD5B-7377-4856-8DBF-B85FDA42B65E}
+ {1CC265CC-D110-4217-9748-D33DBF700436} = {F52EBD5B-7377-4856-8DBF-B85FDA42B65E}
+ {0F36CBF1-1358-4FD3-8631-2775881B2635} = {F52EBD5B-7377-4856-8DBF-B85FDA42B65E}
+ {B110CA48-4524-4E13-B4E1-B4A4C54EC875} = {F52EBD5B-7377-4856-8DBF-B85FDA42B65E}
+ {64565954-31A4-46EE-ACB1-A362405CE6FE} = {F52EBD5B-7377-4856-8DBF-B85FDA42B65E}
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = Xamarin.Mobile\Xamarin.Mobile.iOS.csproj
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/MonoTouch/Xamarin.Mobile/Contacts/AddressBook.cs b/MonoTouch/Xamarin.Mobile/Contacts/AddressBook.cs
new file mode 100644
index 0000000..5b03462
--- /dev/null
+++ b/MonoTouch/Xamarin.Mobile/Contacts/AddressBook.cs
@@ -0,0 +1,167 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+#if __UNIFIED__
+using AddressBook;
+using UIKit;
+using Foundation;
+#else
+using MonoTouch.AddressBook;
+using MonoTouch.UIKit;
+using MonoTouch.Foundation;
+#endif
+
+namespace Xamarin.Contacts
+{
+ public class AddressBook
+ : IEnumerable //IQueryable
+ {
+ public bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public bool SingleContactsSupported
+ {
+ get { return true; }
+ }
+
+ public bool AggregateContactsSupported
+ {
+ get { return false; }
+ }
+
+ public bool PreferContactAggregation
+ {
+ get;
+ set;
+ }
+
+ public bool LoadSupported
+ {
+ get { return true; }
+ }
+
+ public Task RequestPermission()
+ {
+ var tcs = new TaskCompletionSource();
+ if (UIDevice.CurrentDevice.CheckSystemVersion (6, 0))
+ {
+ var status = ABAddressBook.GetAuthorizationStatus();
+ if (status == ABAuthorizationStatus.Denied || status == ABAuthorizationStatus.Restricted)
+ tcs.SetResult (false);
+ else
+ {
+ if (this.addressBook == null)
+ {
+ this.addressBook = new ABAddressBook();
+ //this.provider = new ContactQueryProvider (this.addressBook);
+ }
+
+ if (status == ABAuthorizationStatus.NotDetermined)
+ {
+ this.addressBook.RequestAccess ((s,e) =>
+ {
+ tcs.SetResult (s);
+ if (!s)
+ {
+ this.addressBook.Dispose();
+ this.addressBook = null;
+ //this.provider = null;
+ }
+ });
+ }
+ else
+ tcs.SetResult (true);
+ }
+ }
+ else
+ tcs.SetResult (true);
+
+ return tcs.Task;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ CheckStatus();
+
+ return this.addressBook.GetPeople().Select (ContactHelper.GetContact).GetEnumerator();
+ }
+
+ public Contact Load (string id)
+ {
+ if (String.IsNullOrWhiteSpace (id))
+ throw new ArgumentNullException ("id");
+
+ CheckStatus();
+
+ int rowId;
+ if (!Int32.TryParse (id, out rowId))
+ throw new ArgumentException ("Not a valid contact ID", "id");
+
+ ABPerson person = this.addressBook.GetPerson (rowId);
+ if (person == null)
+ return null;
+
+ return ContactHelper.GetContact (person);
+ }
+
+ private ABAddressBook addressBook;
+ //private IQueryProvider provider;
+
+ private void CheckStatus()
+ {
+ if (UIDevice.CurrentDevice.CheckSystemVersion (6, 0))
+ {
+ var status = ABAddressBook.GetAuthorizationStatus();
+ if (status != ABAuthorizationStatus.Authorized)
+ throw new System.Security.SecurityException ("AddressBook has not been granted permission");
+ }
+
+ if (this.addressBook == null)
+ {
+ this.addressBook = new ABAddressBook();
+ //this.provider = new ContactQueryProvider (this.addressBook);
+ }
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+// Type IQueryable.ElementType
+// {
+// get { return typeof(Contact); }
+// }
+//
+// Expression IQueryable.Expression
+// {
+// get { return Expression.Constant (this); }
+// }
+//
+// IQueryProvider IQueryable.Provider
+// {
+// get { return this.provider; }
+// }
+ }
+}
\ No newline at end of file
diff --git a/MonoTouch/Xamarin.Mobile/Contacts/Contact.cs b/MonoTouch/Xamarin.Mobile/Contacts/Contact.cs
new file mode 100644
index 0000000..5348dae
--- /dev/null
+++ b/MonoTouch/Xamarin.Mobile/Contacts/Contact.cs
@@ -0,0 +1,207 @@
+//
+// Copyright 2011-2013, Xamarin Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using System;
+using System.Runtime.InteropServices;
+
+#if __UNIFIED__
+using AddressBook;
+using CoreGraphics;
+using Foundation;
+using UIKit;
+#else
+using MonoTouch.AddressBook;
+using MonoTouch.CoreGraphics;
+using MonoTouch.Foundation;
+using MonoTouch.UIKit;
+#endif
+
+using Xamarin.Media;
+
+namespace Xamarin.Contacts
+{
+ public class Contact
+ {
+ public Contact()
+ {
+ }
+
+ internal Contact (ABPerson person)
+ {
+ Id = person.Id.ToString();
+ this.person = person;
+ }
+
+ public string Id
+ {
+ get;
+ private set;
+ }
+
+ public bool IsAggregate
+ {
+ get;
+ private set;
+ }
+
+ public string DisplayName
+ {
+ get;
+ set;
+ }
+
+ public string Prefix
+ {
+ get;
+ set;
+ }
+
+ public string FirstName
+ {
+ get;
+ set;
+ }
+
+ public string MiddleName
+ {
+ get;
+ set;
+ }
+
+ public string LastName
+ {
+ get;
+ set;
+ }
+
+ public string Nickname
+ {
+ get;
+ set;
+ }
+
+ public string Suffix
+ {
+ get;
+ set;
+ }
+
+ internal List relationships = new List();
+ public IEnumerable Relationships
+ {
+ get { return this.relationships; }
+ set { this.relationships = new List (value); }
+ }
+
+ internal List addresses = new List();
+ public IEnumerable Addresses
+ {
+ get { return this.addresses; }
+ set { this.addresses = new List