<|start_filename|>Xamarin.Essentials/Map/Map.android.cs<|end_filename|>
﻿using System.Globalization;
using System.Threading.Tasks;
using Android.Content;
using AndroidUri = Android.Net.Uri;

namespace Xamarin.Essentials
{
    public static partial class Map
    {
        internal static Task PlatformOpenMapsAsync(double latitude, double longitude, MapLaunchOptions options)
        {
            var uri = string.Empty;
            var lat = latitude.ToString(CultureInfo.InvariantCulture);
            var lng = longitude.ToString(CultureInfo.InvariantCulture);

            if (options.NavigationMode == NavigationMode.None)
            {
                uri = $"geo:{lat},{lng}?q={lat},{lng}";

                if (!string.IsNullOrWhiteSpace(options.Name))
                    uri += $"({AndroidUri.Encode(options.Name)})";
            }
            else
            {
                uri = $"google.navigation:q={lat},{lng}{GetMode(options.NavigationMode)}";
            }

            StartIntent(uri);
            return Task.CompletedTask;
        }

        internal static string GetMode(NavigationMode mode)
        {
            switch (mode)
            {
                case NavigationMode.Bicycling: return "&mode=b";
                case NavigationMode.Driving: return "&mode=d";
                case NavigationMode.Walking: return "&mode=w";
            }
            return string.Empty;
        }

        internal static Task PlatformOpenMapsAsync(Placemark placemark, MapLaunchOptions options)
        {
            var uri = string.Empty;
            if (options.NavigationMode == NavigationMode.None)
            {
                uri = $"geo:0,0?q={placemark.GetEscapedAddress()}";
                if (!string.IsNullOrWhiteSpace(options.Name))
                    uri += $"({AndroidUri.Encode(options.Name)})";
            }
            else
            {
                uri = $"google.navigation:q={placemark.GetEscapedAddress()}{GetMode(options.NavigationMode)}";
            }

            StartIntent(uri);
            return Task.CompletedTask;
        }

        static void StartIntent(string uri)
        {
            var intent = new Intent(Intent.ActionView, AndroidUri.Parse(uri));
            var flags = ActivityFlags.ClearTop | ActivityFlags.NewTask;
#if __ANDROID_24__
            if (Platform.HasApiLevelN)
                flags |= ActivityFlags.LaunchAdjacent;
#endif
            intent.SetFlags(flags);

            Platform.AppContext.StartActivity(intent);
        }
    }
}


<|start_filename|>DeviceTests/DeviceTests.Shared/SecureStorage_Tests.cs<|end_filename|>
﻿using System.Threading.Tasks;
using Xamarin.Essentials;
using Xunit;

namespace DeviceTests
{
    public class SecureStorage_Tests
    {
        public SecureStorage_Tests()
        {
            SecureStorage.RemoveAll();
        }

        [Theory]
        [InlineData("test.txt", "data", true, true)]
        [InlineData("noextension", "data2", true, false)]
        [InlineData("funny*&$%@!._/\\chars", "data3", true, false)]
        [InlineData("test.txt2", "data2", false, true)]
        [InlineData("noextension2", "data22", false, false)]
        [InlineData("funny*&$%@!._/\\chars2", "data32", false, false)]
        public async Task Saves_And_Loads(string key, string data, bool emulatePreApi23, bool emulateNonEnglishLocale)
        {
#if __IOS__
            // Try the new platform specific api
            await SecureStorage.SetAsync(key, data, Security.SecAccessible.AfterFirstUnlock);

            var b = await SecureStorage.GetAsync(key);

            Assert.Equal(data, b);
#endif

#if __ANDROID__
            SecureStorage.AlwaysUseAsymmetricKeyStorage = emulatePreApi23;

            if (emulateNonEnglishLocale)
            {
                Platform.SetLocale(new Java.Util.Locale("ar"));
            }
#endif

            await SecureStorage.SetAsync(key, data);

            var c = await SecureStorage.GetAsync(key);

            Assert.Equal(data, c);
        }

        [Theory]
        [InlineData("test.txt", "data1", "data2")]
        public async Task Saves_Same_Key_Twice(string key, string data1, string data2)
        {
            await SecureStorage.SetAsync(key, data1);
            await SecureStorage.SetAsync(key, data2);

            var c = await SecureStorage.GetAsync(key);

            Assert.Equal(data2, c);
        }

#if __ANDROID__
        [Theory]
        [InlineData("test.txt", "data")]
        public async Task Fix_Corrupt_Key(string key, string data)
        {
            // this operation is only available on API level 23+ devices
            if (!Platform.HasApiLevel(23))
                return;

            // set a valid key
            SecureStorage.AlwaysUseAsymmetricKeyStorage = true;
            await SecureStorage.SetAsync(key, data);

            // simulate corrupt the key
            var prefKey = "SecureStorageKey";
            var mainKey = "<KEY>;

            Preferences.Set(prefKey, mainKey, SecureStorage.Alias);

            var c = await SecureStorage.GetAsync(key);
            Assert.Null(c);

            // try to reset and get again
            await SecureStorage.SetAsync(key, data);
            c = await SecureStorage.GetAsync(key);

            Assert.Equal(data, c);
        }
#endif

        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        public async Task Non_Existent_Key_Returns_Null(bool emulatePreApi23)
        {
#if __ANDROID__
            SecureStorage.AlwaysUseAsymmetricKeyStorage = emulatePreApi23;
#endif
            var v = await SecureStorage.GetAsync("THIS_KEY_SHOULD_NOT_EXIST");

            Assert.Null(v);
        }

        [Theory]
        [InlineData("KEY_TO_REMOVE1", true)]
        [InlineData("KEY_TO_REMOVE2", false)]
        public async Task Remove_Key(string key, bool emulatePreApi23)
        {
#if __ANDROID__
            SecureStorage.AlwaysUseAsymmetricKeyStorage = emulatePreApi23;
#endif
            await SecureStorage.SetAsync(key, "Irrelevant Data");

            var result = SecureStorage.Remove(key);

            Assert.True(result);

            var v = await SecureStorage.GetAsync(key);

            Assert.Null(v);
        }

        [Theory]
        [InlineData(true, new[] { "KEYS_TO_REMOVEA1", "KEYS_TO_REMOVEA2" })]
        [InlineData(false, new[] { "KEYS_TO_REMOVEB1", "KEYS_TO_REMOVEB2" })]
        public async Task Remove_All_Keys(bool emulatePreApi23, string[] keys)
        {
#if __ANDROID__
            SecureStorage.AlwaysUseAsymmetricKeyStorage = emulatePreApi23;
#endif

            // Set a couple keys
            foreach (var key in keys)
                await SecureStorage.SetAsync(key, "Irrelevant Data");

            // Remove them all
            SecureStorage.RemoveAll();

            // Make sure they are all removed
            foreach (var key in keys)
                Assert.Null(await SecureStorage.GetAsync(key));
        }

#if __ANDROID__
        [Fact]
        public async Task Asymmetric_to_Symmetric_API_Upgrade()
        {
            var key = "asym_to_sym_upgrade";
            var expected = "this is the value";

            SecureStorage.RemoveAll();

            // Emulate pre api 23
            SecureStorage.AlwaysUseAsymmetricKeyStorage = true;

            await SecureStorage.SetAsync(key, expected);

            // Simulate Upgrading to API23+
            SecureStorage.AlwaysUseAsymmetricKeyStorage = false;

            var v = await SecureStorage.GetAsync(key);

            SecureStorage.RemoveAll();

            Assert.Equal(expected, v);
        }
#endif

#if __ANDROID__
        [Theory]
        [InlineData("test-key", "value1")]
        public async Task Legacy_Key(string key, string data)
        {
            var ks = new AndroidKeyStore(Platform.AppContext, SecureStorage.Alias, SecureStorage.AlwaysUseAsymmetricKeyStorage);
            var encryptedData = ks.Encrypt(data);

            var encStr = System.Convert.ToBase64String(encryptedData);
            Preferences.Set(SecureStorage.Md5Hash(key), encStr, SecureStorage.Alias);

            // Ensure we read back out the right key
            var c = await SecureStorage.GetAsync(key);

            Assert.Equal(data, c);
        }
#endif
    }
}


<|start_filename|>Xamarin.Essentials/MediaPicker/MediaPicker.shared.cs<|end_filename|>
﻿using System;
using System.IO;
using System.Threading.Tasks;

namespace Xamarin.Essentials
{
    public static partial class MediaPicker
    {
        public static bool IsCaptureSupported
            => PlatformIsCaptureSupported;

        public static Task<FileResult> PickPhotoAsync(MediaPickerOptions options = null) =>
            PlatformPickPhotoAsync(options);

        public static Task<FileResult> CapturePhotoAsync(MediaPickerOptions options = null)
        {
            if (!IsCaptureSupported)
                throw new FeatureNotSupportedException();

            return PlatformCapturePhotoAsync(options);
        }

        public static Task<FileResult> PickVideoAsync(MediaPickerOptions options = null) =>
            PlatformPickVideoAsync(options);

        public static Task<FileResult> CaptureVideoAsync(MediaPickerOptions options = null)
        {
            if (!IsCaptureSupported)
                throw new FeatureNotSupportedException();

            return PlatformCaptureVideoAsync(options);
        }
    }

    public class MediaPickerOptions
    {
        public string Title { get; set; }
    }
}


<|start_filename|>Xamarin.Essentials/AssemblyInfo/AssemblyInfo.ios.tvos.watchos.macos.cs<|end_filename|>
﻿using Foundation;

#pragma warning disable CS0618 // Type or member is obsolete
[assembly: LinkerSafe]
#pragma warning restore CS0618 // Type or member is obsolete


<|start_filename|>Samples/Samples/ViewModel/ClipboardViewModel.cs<|end_filename|>
﻿using System;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;

namespace Samples.ViewModel
{
    class ClipboardViewModel : BaseViewModel
    {
        string fieldValue;
        string lastCopied;

        public ClipboardViewModel()
        {
            CopyCommand = new Command(OnCopy);
            PasteCommand = new Command(OnPaste);
            CheckCommand = new Command(OnCheck);
        }

        public ICommand CopyCommand { get; }

        public ICommand PasteCommand { get; }

        public ICommand CheckCommand { get; }

        public string FieldValue
        {
            get => fieldValue;
            set => SetProperty(ref fieldValue, value);
        }

        public string LastCopied
        {
            get => lastCopied;
            set => SetProperty(ref lastCopied, value);
        }

        public override void OnAppearing()
        {
            try
            {
                Clipboard.ClipboardContentChanged += OnClipboardContentChanged;
            }
            catch (FeatureNotSupportedException)
            {
            }
        }

        public override void OnDisappearing()
        {
            try
            {
                Clipboard.ClipboardContentChanged -= OnClipboardContentChanged;
            }
            catch (FeatureNotSupportedException)
            {
            }
        }

        void OnClipboardContentChanged(object sender, EventArgs args)
        {
            LastCopied = $"Last copied text at {DateTime.UtcNow:T}";
        }

        async void OnCopy()
        {
            await Clipboard.SetTextAsync(FieldValue);
        }

        async void OnPaste()
        {
            var text = await Clipboard.GetTextAsync();
            if (!string.IsNullOrWhiteSpace(text))
            {
                FieldValue = text;
            }
        }

        async void OnCheck()
        {
            await DisplayAlertAsync($"Has text: {Clipboard.HasText}");
        }
    }
}


<|start_filename|>Xamarin.Essentials/Types/PlatformExtensions/ColorExtensions.tizen.cs<|end_filename|>
﻿using System.Drawing;
using EColor = ElmSharp.Color;

namespace Xamarin.Essentials
{
    public static partial class ColorExtensions
    {
        public static Color ToSystemColor(this EColor color) =>
            Color.FromArgb(color.A, color.R, color.G, color.B);

        public static EColor ToPlatformColor(this Color color) =>
            new EColor(color.R, color.G, color.B, color.A);
    }
}


<|start_filename|>Xamarin.Essentials/Types/PlatformExtensions/PointExtensions.tizen.cs<|end_filename|>
﻿using System.Drawing;
using EPoint = ElmSharp.Point;

namespace Xamarin.Essentials
{
    public static class PointExtensions
    {
        public static Point ToSystemPoint(this EPoint point) =>
            new Point(point.X, point.Y);

        public static PointF ToSystemPointF(this EPoint point) =>
            new PointF(point.X, point.Y);

        public static EPoint ToPlatformPoint(this Point point) =>
            new EPoint() { X = point.X, Y = point.Y };

        public static EPoint ToPlatformPoint(this PointF point) =>
            ToPlatformPointF(point);

        public static EPoint ToPlatformPointF(this PointF point) =>
            new EPoint() { X = (int)point.X, Y = (int)point.Y };
    }
}


<|start_filename|>Xamarin.Essentials/Types/Shared/Utils.shared.cs<|end_filename|>
﻿using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Xamarin.Essentials
{
    static class Utils
    {
        internal static Version ParseVersion(string version)
        {
            if (Version.TryParse(version, out var number))
                return number;

            if (int.TryParse(version, out var major))
                return new Version(major, 0);

            return new Version(0, 0);
        }

        internal static CancellationToken TimeoutToken(CancellationToken cancellationToken, TimeSpan timeout)
        {
            // create a new linked cancellation token source
            var cancelTokenSrc = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

            // if a timeout was given, make the token source cancel after it expires
            if (timeout > TimeSpan.Zero)
                cancelTokenSrc.CancelAfter(timeout);

            // our Cancel method will handle the actual cancellation logic
            return cancelTokenSrc.Token;
        }

        internal static async Task<T> WithTimeout<T>(Task<T> task, TimeSpan timeSpan)
        {
            var retTask = await Task.WhenAny(task, Task.Delay(timeSpan))
                .ConfigureAwait(false);

            return retTask is Task<T> ? task.Result : default(T);
        }
    }
}


<|start_filename|>Xamarin.Essentials/Types/PlatformExtensions/ColorExtensions.macos.cs<|end_filename|>
﻿using System;
using System.Drawing;
using AppKit;

namespace Xamarin.Essentials
{
    public static partial class ColorExtensions
    {
        public static Color ToSystemColor(this NSColor color)
        {
            if (color == null)
                throw new ArgumentNullException(nameof(color));

            // make sure the colorspace is valid for RGBA
            // we can't check as the check will throw if it is invalid
            color = color.UsingColorSpace(NSColorSpace.SRGBColorSpace);

            color.GetRgba(out var red, out var green, out var blue, out var alpha);
            return Color.FromArgb((int)Math.Round(alpha * 255), (int)Math.Round(red * 255), (int)Math.Round(green * 255), (int)Math.Round(blue * 255));
        }

        public static NSColor ToPlatformColor(this Color color) =>
            NSColor.FromRgba(color.R, color.G, color.B, color.A);
    }
}


<|start_filename|>Xamarin.Essentials/MediaPicker/MediaPicker.uwp.cs<|end_filename|>
﻿using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Media.Capture;
using Windows.Storage.Pickers;

namespace Xamarin.Essentials
{
    public static partial class MediaPicker
    {
        static bool PlatformIsCaptureSupported
            => true;

        static Task<FileResult> PlatformPickPhotoAsync(MediaPickerOptions options)
            => PickAsync(options, true);

        static Task<FileResult> PlatformPickVideoAsync(MediaPickerOptions options)
            => PickAsync(options, false);

        static async Task<FileResult> PickAsync(MediaPickerOptions options, bool photo)
        {
            var picker = new FileOpenPicker();

            var defaultTypes = photo ? FilePickerFileType.Images.Value : FilePickerFileType.Videos.Value;

            // set picker properties
            foreach (var filter in defaultTypes.Select(t => t.TrimStart('*')))
                picker.FileTypeFilter.Add(filter);
            picker.SuggestedStartLocation = photo ? PickerLocationId.PicturesLibrary : PickerLocationId.VideosLibrary;
            picker.ViewMode = PickerViewMode.Thumbnail;

            // show the picker
            var result = await picker.PickSingleFileAsync();

            // cancelled
            if (result == null)
                return null;

            // picked
            return new FileResult(result);
        }

        static Task<FileResult> PlatformCapturePhotoAsync(MediaPickerOptions options)
            => CaptureAsync(options, true);

        static Task<FileResult> PlatformCaptureVideoAsync(MediaPickerOptions options)
            => CaptureAsync(options, false);

        static async Task<FileResult> CaptureAsync(MediaPickerOptions options, bool photo)
        {
            var captureUi = new CameraCaptureUI();

            if (photo)
                captureUi.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg;
            else
                captureUi.VideoSettings.Format = CameraCaptureUIVideoFormat.Mp4;

            var file = await captureUi.CaptureFileAsync(photo ? CameraCaptureUIMode.Photo : CameraCaptureUIMode.Video);

            if (file != null)
                return new FileResult(file);

            return null;
        }
    }
}


<|start_filename|>Xamarin.Essentials/SecureStorage/SecureStorage.tizen.cs<|end_filename|>
﻿using System.Text;
using System.Threading.Tasks;
using Tizen.Security.SecureRepository;

namespace Xamarin.Essentials
{
    public partial class SecureStorage
    {
        static Task<string> PlatformGetAsync(string key)
        {
            try
            {
                // The null parameter here is not the default value as you might expect, but
                // a password
                return Task.FromResult(Encoding.UTF8.GetString(DataManager.Get(key, null)));
            }
            catch (System.InvalidOperationException)
            {
                // The DataManager.Get call throws an exception if key does not exist. Not logging
                // anything since this is an expected and normal situation (if the key did not exist).
                return Task.FromResult<string>(null);
            }
            catch
            {
                Tizen.Log.Error(Platform.CurrentPackage.Label, "Failed to load data.");
                throw;
            }
        }

        static Task PlatformSetAsync(string key, string data)
        {
            try
            {
                try
                {
                    // Remove the key in case it already exists, otherwise DataManager.Save will throw an exception.
                    // There is no way to check if a key exists without throwing an exception, so there is
                    // no point in checking whether the key exists prior to attempting to remove it.
                    DataManager.RemoveAlias(key);
                }
                catch
                {
                    // Not logging anything since this is an expected and normal situation (if the key did not exist).
                }

                DataManager.Save(key, Encoding.UTF8.GetBytes(data), new Policy());

                return Task.CompletedTask;
            }
            catch
            {
                Tizen.Log.Error(Platform.CurrentPackage.Label, "Failed to save data.");
                throw;
            }
        }

        static void PlatformRemoveAll()
        {
            try
            {
                foreach (var key in DataManager.GetAliases())
                {
                    DataManager.RemoveAlias(key);
                }
            }
            catch
            {
                Tizen.Log.Info(Platform.CurrentPackage.Label, "No save data.");
            }
        }

        static bool PlatformRemove(string key)
        {
            try
            {
                DataManager.RemoveAlias(key);
                return true;
            }
            catch
            {
                Tizen.Log.Info(Platform.CurrentPackage.Label, "Failed to remove data.");
                return false;
            }
        }
    }
}


<|start_filename|>Xamarin.Essentials/FileSystem/FileSystem.shared.cs<|end_filename|>
﻿using System;
using System.IO;
using System.Threading.Tasks;

namespace Xamarin.Essentials
{
    public static partial class FileSystem
    {
        public static string CacheDirectory
            => PlatformCacheDirectory;

        public static string AppDataDirectory
            => PlatformAppDataDirectory;

        public static Task<Stream> OpenAppPackageFileAsync(string filename)
            => PlatformOpenAppPackageFileAsync(filename);

        internal static class MimeTypes
        {
            internal const string All = "*/*";

            internal const string ImageAll = "image/*";
            internal const string ImagePng = "image/png";
            internal const string ImageJpg = "image/jpeg";

            internal const string VideoAll = "video/*";

            internal const string EmailMessage = "message/rfc822";

            internal const string Pdf = "application/pdf";

            internal const string TextPlain = "text/plain";

            internal const string OctetStream = "application/octet-stream";
        }

        internal static class Extensions
        {
            internal const string Png = ".png";
            internal const string Jpg = ".jpg";
            internal const string Jpeg = ".jpeg";
            internal const string Gif = ".gif";
            internal const string Bmp = ".bmp";

            internal const string Avi = ".avi";
            internal const string Flv = ".flv";
            internal const string Gifv = ".gifv";
            internal const string Mp4 = ".mp4";
            internal const string M4v = ".m4v";
            internal const string Mpg = ".mpg";
            internal const string Mpeg = ".mpeg";
            internal const string Mp2 = ".mp2";
            internal const string Mkv = ".mkv";
            internal const string Mov = ".mov";
            internal const string Qt = ".qt";
            internal const string Wmv = ".wmv";

            internal const string Pdf = ".pdf";

            internal static string[] AllImage =>
                new[] { Png, Jpg, Jpeg, Gif, Bmp };

            internal static string[] AllJpeg =>
                new[] { Jpg, Jpeg };

            internal static string[] AllVideo =>
                new[] { Mp4, Mov, Avi, Wmv, M4v, Mpg, Mpeg, Mp2, Mkv, Flv, Gifv, Qt };

            internal static string Clean(string extension, bool trimLeadingPeriod = false)
            {
                if (string.IsNullOrWhiteSpace(extension))
                    return string.Empty;

                extension = extension.TrimStart('*');
                extension = extension.TrimStart('.');

                if (!trimLeadingPeriod)
                    extension = "." + extension;

                return extension;
            }
        }
    }

    public abstract partial class FileBase
    {
        internal const string DefaultContentType = FileSystem.MimeTypes.OctetStream;

        string contentType;

        // The caller must setup FullPath at least!!!
        internal FileBase()
        {
        }

        internal FileBase(string fullPath)
        {
            if (fullPath == null)
                throw new ArgumentNullException(nameof(fullPath));
            if (string.IsNullOrWhiteSpace(fullPath))
                throw new ArgumentException("The file path cannot be an empty string.", nameof(fullPath));
            if (string.IsNullOrWhiteSpace(Path.GetFileName(fullPath)))
                throw new ArgumentException("The file path must be a file path.", nameof(fullPath));

            FullPath = fullPath;
        }

        public FileBase(FileBase file)
        {
            FullPath = file.FullPath;
            ContentType = file.ContentType;
            FileName = file.FileName;
            PlatformInit(file);
        }

        internal FileBase(string fullPath, string contentType)
            : this(fullPath)
        {
            FullPath = fullPath;
            ContentType = contentType;
        }

        public string FullPath { get; internal set; }

        public string ContentType
        {
            get => GetContentType();
            set => contentType = value;
        }

        internal string GetContentType()
        {
            // try the provided type
            if (!string.IsNullOrWhiteSpace(contentType))
                return contentType;

            // try get from the file extension
            var ext = Path.GetExtension(FullPath);
            if (!string.IsNullOrWhiteSpace(ext))
            {
                var content = PlatformGetContentType(ext);
                if (!string.IsNullOrWhiteSpace(content))
                    return content;
            }

            return DefaultContentType;
        }

        string fileName;

        public string FileName
        {
            get => GetFileName();
            set => fileName = value;
        }

        internal string GetFileName()
        {
            // try the provided file name
            if (!string.IsNullOrWhiteSpace(fileName))
                return fileName;

            // try get from the path
            if (!string.IsNullOrWhiteSpace(FullPath))
                return Path.GetFileName(FullPath);

            // this should never happen as the path is validated in the constructor
            throw new InvalidOperationException($"Unable to determine the file name from '{FullPath}'.");
        }

        public Task<Stream> OpenReadAsync()
            => PlatformOpenReadAsync();
    }

    public class ReadOnlyFile : FileBase
    {
        public ReadOnlyFile(string fullPath)
            : base(fullPath)
        {
        }

        public ReadOnlyFile(string fullPath, string contentType)
            : base(fullPath, contentType)
        {
        }

        public ReadOnlyFile(FileBase file)
            : base(file)
        {
        }
    }

    public partial class FileResult : FileBase
    {
        // The caller must setup FullPath at least!!!
        internal FileResult()
        {
        }

        public FileResult(string fullPath)
            : base(fullPath)
        {
        }

        public FileResult(string fullPath, string contentType)
            : base(fullPath, contentType)
        {
        }

        public FileResult(FileBase file)
            : base(file)
        {
        }
    }
}
