Skip to content

3_Xamarin.Forms

Yoshito Tabuchi edited this page Jul 12, 2018 · 10 revisions

PhoneTranslator.cs

using System.Text;

namespace Core
{
    public static class PhonewordTranslator
    {
        public static string ToNumber(string raw)
        {
            if (string.IsNullOrWhiteSpace(raw))
                return null;

            raw = raw.ToUpperInvariant();

            var newNumber = new StringBuilder();
            foreach (var c in raw)
            {
                if (" -0123456789".Contains(c))
                    newNumber.Append(c);
                else
                {
                    var result = TranslateToNumber(c);
                    if (result != null)
                        newNumber.Append(result);
                    // Bad character?
                    else
                        return null;
                }
            }
            return newNumber.ToString();
        }

        static bool Contains(this string keyString, char c)
        {
            return keyString.IndexOf(c) >= 0;
        }

        static readonly string[] digits = {
            "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"
        };

        static int? TranslateToNumber(char c)
        {
            for (int i = 0; i < digits.Length; i++)
            {
                if (digits[i].Contains(c))
                    return 2 + i;
            }
            return null;
        }
    }
}

MainPage.xaml

<?xml version="1.0" encoding="UTF-8" ?>
<ContentPage x:Class="XF_Phoneword.MainPage"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
             ios:Page.UseSafeArea="true">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    Android="10"
                    WinPhone="10"
                    iOS="10, 30, 10, 10" />
    </ContentPage.Padding>
    <ContentPage.Content>
        <StackLayout Spacing="15" VerticalOptions="FillAndExpand">
            <Label Text="Enter a Phoneword:" />
            <Entry x:Name="phoneNumberText" Text="1-855-XAMARIN" />
            <Button x:Name="translateButton"
                    Clicked="OnTranslate"
                    Text="Translate" />
            <Button x:Name="callButton"
                    Clicked="OnCall"
                    IsEnabled="false"
                    Text="Call" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

MainPage.xaml.cs

using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
using System;
using Xamarin.Forms;

namespace XF_Phoneword
{
    public partial class MainPage : ContentPage
    {
        string translatedNumber;

        public MainPage()
        {
            InitializeComponent();
        }

        void OnTranslate(object sender, EventArgs e)
        {
            translatedNumber = Core.PhonewordTranslator.ToNumber(phoneNumberText.Text);
            if (!string.IsNullOrWhiteSpace(translatedNumber))
            {
                callButton.IsEnabled = true;
                callButton.Text = "Call " + translatedNumber;
            }
            else
            {
                callButton.IsEnabled = false;
                callButton.Text = "Call";
            }
        }

        async void OnCall(object sender, EventArgs e)
        {
            // Alertの選択をboolで取得します。
            var call = await DisplayAlert(
              "Dial a Number",
              "Would you like to call " + translatedNumber + "?",
              "Yes",
              "No");
            if (call)
            {
                try
                {
                    // PermissionPluginを使用してPhoneのPermissionのStatusを取得します。
                    var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Phone);

                    // Permission未設定の場合は確認ダイアログを表示しPermissionの取得を確認します。
                    if (status != PermissionStatus.Granted)
                    {
                        if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Phone))
                        {
                            await DisplayAlert("Need Permission", "It will get permission of phonecall", "OK");
                        }

                        var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Phone });
                        status = results[Permission.Phone];
                    }

                    // Permissionが許可されていれば電話を掛けます。
                    if (status == PermissionStatus.Granted)
                    {
                        var dialer = DependencyService.Get<IDialer>();
                        if (dialer != null)
                        {
                            dialer.Dial(translatedNumber);
                        }
                    }
                    else if (status != PermissionStatus.Unknown)
                    {
                        await DisplayAlert("Permission Denied", "Can not continue, try again.", "OK");
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.InnerException);
                }
            }

        }
    }
}

IDialer.cs

using System;

namespace XF_Phoneword
{
    public interface IDialer
    {
        bool Dial(string number);
    }
}

Android プロジェクトでの作業

MainActivity.cs

using 追加

using Plugin.Permissions;

OnCreate 内

global::Xamarin.Forms.Forms.Init(this, bundle);
Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this, bundle);
LoadApplication(new App());
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
    PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

PhoneDialer.cs (Android)

using Android.Content;
using Android.Telephony;
using XF_Phoneword.Droid;
using System.Linq;
using Xamarin.Forms;

using Uri = Android.Net.Uri;

[assembly: Dependency(typeof(PhoneDialer))]

namespace XF_Phoneword.Droid
{
    public class PhoneDialer : IDialer
    {
        public bool Dial(string number)
        {
            var context = Android.App.Application.Context;
            if (context == null)
                return false;

            var intent = new Intent(Intent.ActionCall);
            intent.SetData(Uri.Parse("tel:" + number));

            if (IsIntentAvailable(context, intent))
            {
                context.StartActivity(intent);
                return true;
            }

            return false;
        }

        public static bool IsIntentAvailable(Context context, Intent intent)
        {
            var packageManager = context.PackageManager;

            var list = packageManager.QueryIntentServices(intent, 0)
                .Union(packageManager.QueryIntentActivities(intent, 0));

            if (list.Any())
                return true;

            var manager = TelephonyManager.FromContext(context);
            return manager.PhoneType != PhoneType.None;
        }
    }
}

iOS プロジェクトでの作業

PhoneDialer.cs (iOS)

using Foundation;
using XF_Phoneword.iOS;
using UIKit;
using Xamarin.Forms;

[assembly: Dependency(typeof(PhoneDialer))]

namespace XF_Phoneword.iOS
{
    public class PhoneDialer : IDialer
    {
        public bool Dial(string number)
        {
            return UIApplication.SharedApplication.OpenUrl (
                new NSUrl ("tel:" + number));
        }
    }
}

PhoneDialer.cs (UWP)

using Windows.ApplicationModel.Calls;
using XF_Phoneword.UWP;
using Xamarin.Forms;

[assembly: Dependency(typeof(PhoneDialer))]

namespace XF_Phoneword.UWP
{
    public class PhoneDialer : IDialer
    {
        public bool Dial(string number)
        {
            PhoneCallManager.ShowPhoneCallUI(number, "Phoneword");
            return true;
        }
    }
}

App.xaml.cs

プロパティ追加

public static List<string> PhoneNumbers { get; set; }

コンストラクタで初期化しNavigationPageで呼び出し

PhoneNumbers = new List<string>();
MainPage = new NavigationPage(new MainPage());

App.xaml.cs(完成形)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Xamarin.Forms;

namespace XF_Phoneword
{
    public partial class App : Application
    {
        public static List<string> PhoneNumbers { get; set; }

        public App()
        {
            InitializeComponent();
            PhoneNumbers = new List<string>();
            MainPage = new NavigationPage(new MainPage());
        }


        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

CallHistoryPage.cs

using System;
using Xamarin.Forms;

namespace XF_Phoneword
{
    public class CallHistoryPage : ContentPage
    {
        public CallHistoryPage()
        {
            Title = "Recent Call";
            Content = new StackLayout
            {
                VerticalOptions = LayoutOptions.FillAndExpand,
                Orientation = StackOrientation.Vertical,
                Children = {
                    new ListView
                    {
                        ItemsSource = App.PhoneNumbers,
                    }
                }
            };
        }
    }
}

MainPage.xaml

Button追加

<Button x:Name="callHistoryButton" Text="Call History" IsEnabled="False" Clicked="OnCallHistory" />

MainPage.xaml(完成形)

<?xml version="1.0" encoding="UTF-8" ?>
<ContentPage x:Class="XF_Phoneword.MainPage"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             Title="Phoneword">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    Android="10"
                    WinPhone="10"
                    iOS="10, 30, 10, 10" />
    </ContentPage.Padding>
    <ContentPage.Content>
        <StackLayout Spacing="15" VerticalOptions="FillAndExpand">
            <Label Text="Enter a Phoneword:" />
            <Entry x:Name="phoneNumberText" Text="1-855-XAMARIN" />
            <Button x:Name="translateButton"
                    Clicked="OnTranslate"
                    Text="Translate" />
            <Button x:Name="callButton"
                    Clicked="OnCall"
                    IsEnabled="false"
                    Text="Call" />
            <Button x:Name="callHistoryButton"
                    Clicked="OnCallHistory"
                    IsEnabled="False"
                    Text="Call History" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

MainPage.xaml.cs

OnCallメソッド内

App.PhoneNumbers.Add(translatedNumber);
callHistoryButton.IsEnabled = true;

OnCallHistoryメソッド追加

async void OnCallHistory(object sender, EventArgs e)
{
  await Navigation.PushAsync(new CallHistoryPage());
}

MainPage.xaml.cs(完成形)

using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
using System;
using Xamarin.Forms;

namespace XF_Phoneword
{
    public partial class MainPage : ContentPage
    {
        string translatedNumber;

        public MainPage()
        {
            InitializeComponent();
        }

        void OnTranslate(object sender, EventArgs e)
        {
            translatedNumber = Core.PhonewordTranslator.ToNumber(phoneNumberText.Text);
            if (!string.IsNullOrWhiteSpace(translatedNumber))
            {
                callButton.IsEnabled = true;
                callButton.Text = "Call " + translatedNumber;
            }
            else
            {
                callButton.IsEnabled = false;
                callButton.Text = "Call";
            }
        }

        async void OnCall(object sender, EventArgs e)
        {
            // Alertの選択をboolで取得します。
            var call = await DisplayAlert(
              "Dial a Number",
              "Would you like to call " + translatedNumber + "?",
              "Yes",
              "No");
            if (call)
            {
                try
                {
                    // PermissionPluginを使用してPhoneのPermissionのStatusを取得します。
                    var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Phone);

                    // Permission未設定の場合は確認ダイアログを表示しPermissionの取得を確認します。
                    if (status != PermissionStatus.Granted)
                    {
                        if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Phone))
                        {
                            await DisplayAlert("Need Permission", "It will get permission of phonecall", "OK");
                        }

                        var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Phone });
                        status = results[Permission.Phone];
                    }

                    // Permissionが許可されていれば電話を掛けます。
                    if (status == PermissionStatus.Granted)
                    {
                        var dialer = DependencyService.Get<IDialer>();
                        if (dialer != null)
                        {
                            App.PhoneNumbers.Add(translatedNumber);
                            callHistoryButton.IsEnabled = true;
                            dialer.Dial(translatedNumber);
                        }
                    }
                    else if (status != PermissionStatus.Unknown)
                    {
                        await DisplayAlert("Permission Denied", "Can not continue, try again.", "OK");
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.InnerException);
                }
            }
        }

        async void OnCallHistory(object sender, EventArgs e)
        {
            await Navigation.PushAsync(new CallHistoryPage());
        }
    }
}