Xamarin StudioとGenymotionでAndroid開発 - Part2: Hello, Android

[Windows7にインストールした](http://qiita.com/masato/items/3f534de55935be6d5993)XamarinStudioを使ってXamarin.Androidのサンプルを実装します。[Hello, Android](http://developer.xamarin.com/guides/android/getting_started/hello,android/hello,android_quickstart/)のチュートリアルを使います。手順ではプロジェクト名が`Phoneword_Droid`ですが、`Phoneword.Android`に変更してnamespaceにも使います。完成したコードはGitHubの[PhoneWord](https://github.com/masato/PhoneWord)のリポジトリにあります。


## Getting Started

Xamarin DevelopersのGetting Startedを開きます。

* [Getting Started with Android](http://developer.xamarin.com/guides/android/getting_started/)
* [Hello, Android](http://developer.xamarin.com/guides/android/getting_started/hello,android/)
* [Part 1: Quickstart](http://developer.xamarin.com/guides/android/getting_started/hello,android/hello,android_quickstart/)

## Xamarin App Icons & Launch Screens set

プロジェクトに追加するアインコンの[Xamarin App Icons & Launch Screens set](http://developer.xamarin.com/guides/android/getting_started/hello,android/Resources/XamarinAppIconsAndLaunchImages.zip)のzipファイルをダウンロードして解凍します。


## PhoneWordソリューションの作成

PhoneWordソリューションを作成します。

* New Solution... -> その他 > 空のソリューション

![xamarin-studio-solution.png](https://qiita-image-store.s3.amazonaws.com/0/43745/4298f738-51b2-e4a1-6553-ba5eefd4578a.png)

## PhoneWord.Androidプロジェクトの作成

新しいプロジェクトのダイアログを表示します。

* PhoneWordソリューションのギアアインコン -> 追加 -> 新しいプロジェクトを追加

PhoneWord.Androidプロジェクトを作成します。

* C# -> Android -> Android Applicationテンプレート


![xamarin-studio-project.png](https://qiita-image-store.s3.amazonaws.com/0/43745/792c4249-1a3a-78ba-6f15-6bf24b5514b2.png)

## Main.axmlの編集

デザイン サーフェイスを開きます。

* Resourcesフォルダ -> layoutフォルダ ->  Main.axmlをダブルクリック

Buttonを選択して、Deleteキーを押して削除します。

Toolboxから、Text (Large) コントロールを、デザイン サーフェイスへドラッグ＆ドロップします。Text (Large) コントロールを選択して、プロパティ パッドでTextプロパティを編集します。

* Text property: Enter a Phoneword:

Plain Text コントロールを、 デザイン サーフェイスへ、Text (Large)コントロールの下にドラッグ＆ドロップします。

* Plain Text コントロールを選択し、Id プロパティとTextプロパティ変更する
* Id property: @+id/PhoneNumberText
* Text property: 1-855-XAMARIN

Toolboxから、Button コントロールを、デザイン サーフェイスへ、Plain Text コントロールの下にドラッグ＆ドロップします。

* Buttonコントロールを選択して、 プロパティ パッドから、Id プロパティとTextプロパティ変更する
* Id property: @+id/TranslateButton
* Text property: Translate


Toolboxから、Button コントロールを、デザイン サーフェイスへ、TranslateButtonの下にドラッグ＆ドロップします。

* Buttonコントロールを選択して、 プロパティ パッドから、Id プロパティとTextプロパティ変更する
* Id property: @+id/CallButton
* Text property: Call

ここまでの作業を`Ctrl + s`で保存します。

![xamarin-studio-Main.png](https://qiita-image-store.s3.amazonaws.com/0/43745/f6b922d9-f0ae-72f0-639b-cfcad214ed9c.png)


## PhoneTranslator.cs の追加

PhoneTranslator.csを追加して、電話番号を英数字から数字に変換するコードを記述します。

* PhoneWordソリューション  -> PhoneWord.Android プロジェクト
* ギアアインコン -> 追加 -> General -> 新しいファイルを追加
* General -> 空のクラス
* 名前: PhoneTranslator

![xamarin-studio-PhoneTranslator.png](https://qiita-image-store.s3.amazonaws.com/0/43745/ca6cac38-cc6d-0bf2-3628-529dfa169814.png)


以下のようにPhoneTranslator.csを作成します。

```csharp:PhoneTranslator.cs

using System.Text;
using System;

namespace PhoneWord.Android
{
    public static class PhonewordTranslator
    {
        public static string ToNumber(string raw)
        {
            if (string.IsNullOrWhiteSpace(raw))
                return "";
            else
                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);
                }
                // otherwise we've skipped a non-numeric char
            }
            return newNumber.ToString();
        }
        static bool Contains (this string keyString, char c)
        {
            return keyString.IndexOf(c) >= 0;
        }
        static int? TranslateToNumber(char c)
        {
            if ("ABC".Contains(c))
                return 2;
            else if ("DEF".Contains(c))
                return 3;
            else if ("GHI".Contains(c))
                return 4;
            else if ("JKL".Contains(c))
                return 5;
            else if ("MNO".Contains(c))
                return 6;
            else if ("PQRS".Contains(c))
                return 7;
            else if ("TUV".Contains(c))
                return 8;
            else if ("WXYZ".Contains(c))
                return 9;
            return null;
        }
    }
}
```

`Ctrl + s`でPhoneTranslator.csを保存します。

## MainActivity.cs

PhoneWordソリューション から、MainActivity.csをダブルクリックして、ユーザーインタフェースの記述をします。以下のような状態のOnCreateメソッドに追加してコードを書いていきます。

``` csharp:MainActivity.cs
using System;

using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;

namespace Phoneword.Android
{
    [Activity (Label = "Phoneword.Android", MainLauncher = true)]
    public class MainActivity : Activity
    {
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);

            // Set our view from the "main" layout resource
            SetContentView (Resource.Layout.Main);

        }
    }
}
```

OnCreateメソッドにコントローラーへの参照を追加します。

``` csharp:MainActivity.cs
// Get our UI controls from the loaded layout
EditText phoneNumberText = FindViewById<EditText>(Resource.Id.PhoneNumberText);
Button translateButton = FindViewById<Button>(Resource.Id.TranslateButton);
Button callButton = FindViewById<Button>(Resource.Id.CallButton);
```

TranslateButtonのイベントリスナーを追加します。

``` csharp:MainActivity.cs
// Disable the "Call" button
callButton.Enabled = false;

// Add code to translate number
string translatedNumber = string.Empty;

translateButton.Click += (object sender, EventArgs e) =>
    {
        // Translate user’s alphanumeric phone number to numeric
        //translatedNumber = Core.PhonewordTranslator.ToNumber(phoneNumberText.Text);
        translatedNumber = PhoneWord.Android.PhonewordTranslator.ToNumber(phoneNumberText.Text);

        if (String.IsNullOrWhiteSpace(translatedNumber))
        {
            callButton.Text = "Call";
            callButton.Enabled = false;
        }
        else
        {
            callButton.Text = "Call " + translatedNumber;
            callButton.Enabled = true;
        }
   };
```

CallButtonのイベントリスナーを追加しますが、namespaceを定義しているため以下のように`using Uri = Android.Net.Uri;`を追加します。

``` csharp:MainActivity.cs
using Uri = Android.Net.Uri;
...
callButton.Click += (object sender, EventArgs e) =>
{
    // On "Call" button click, try to dial phone number.
    var callDialog = new AlertDialog.Builder(this);
    callDialog.SetMessage("Call " + translatedNumber + "?");
    callDialog.SetNeutralButton("Call", delegate {
           // Create intent to dial phone
           var callIntent = new Intent(Intent.ActionCall);
           //callIntent.SetData(Android.Net.Uri.Parse("tel:" + translatedNumber));
           callIntent.SetData(Uri.Parse("tel:" + translatedNumber));
           StartActivity(callIntent);
       });
    callDialog.SetNegativeButton("Cancel", delegate { });

    // Show the alert dialog to the user and wait for response.
    callDialog.Show();
};
```

## AndroidManifest.xmlにphone callパーミッションを追加

AndroidManifest.xmlが見つからない場合は、一度ソリューションを閉じて開き直します。

* PhoneWordソリューション -> Properties -> AndroidManifest.xml
* Required Permissions -> Call Phone にチェック


![xamarin-studio-CallPhone.png](https://qiita-image-store.s3.amazonaws.com/0/43745/1c93ce1d-f7b9-94e8-d1e5-a7bece279c18.png)

## ビルド

ビルドに成功するとXamarin Studioの上部メッセージ欄に「ビルド成功」のメッセージが表示されます。

* メニュー -> ビルド -> すべてビルド

![xamarin-studio-build.png](https://qiita-image-store.s3.amazonaws.com/0/43745/fadb486e-86e5-94ce-2994-0c5c043fb712.png)

## MainActivity.csのLabel編集

スクリーンのトップに表示されるLabelを編集します。

``` csharp:MainActivity.cs
namespace PhoneWord.Android
{
    [Activity (Label = "PhoneWord", MainLauncher = true)]
    public class MainActivity : Activity
    {
        ...
    }
}
```

## AndroidManifest.xmlにアプリ名とアイコンを追加

* Application name: Phoneword

デフォルトのIcon.pngを右クリックして削除します。

* Resource -> drawble -> Icon.pngを右クリックして削除 -> Delete

ダウンロードして解凍したXamarin App Icons setのフォルダからアイコンをコピーします。

* Resource -> drawbleを右クリック -> 追加 -> ファイルを追加

ダイアログでCopy the file to the directoryを選択します。

* XamarinAppIconsAndLaunchImages -> Xamarin App Icons and Launch Images -> Android  drawable -> Icon.png

## drawable-* フォルダを追加

残りのdrawable-* フォルダのIcon.pngをすべてフォルダごとコピーします。

* Resourceを右クリック -> 追加 ->  Add Existing Folder


![xamarin-studio-all-Icons.png](https://qiita-image-store.s3.amazonaws.com/0/43745/e25f618b-e493-3c2a-1be0-189364d38055.png)

AndroidManifest.xmlにアイコンを追加します。

* AndroidManifest.xml ->  Application icon -> @drawable/iconを選択

## Genymotionを起動

一覧から`Google Nexus 4 - 4.4.4 - (API19) - 768x1280`を起動します。

![genymotion-list.png](https://qiita-image-store.s3.amazonaws.com/0/43745/53c293e5-c08f-d935-c8a1-31f8d5bea881.png)

エミュレータが起動しました。

![genymotion-nexus4-virtual-device.png](https://qiita-image-store.s3.amazonaws.com/0/43745/16cf5cba-bfc7-b951-7c95-c6b2ea8c147c.png)

Xamarin Studioのデバイスの選択ボックスからGenymotionのデバイスを選択します。

* Phisical Devices -> Genymo...(API19)

Xamarin Studioの左上の再生ボタンをクリックしてDebug実行します。

![genymotion-nexus4-api19.png](https://qiita-image-store.s3.amazonaws.com/0/43745/b6bf99b7-cc78-4155-2ef1-03267969c4bf.png)

## Genymotionのエミュレータで確認

PhoneWordアイコンをタップしてアプリを起動します。


![genymotion-phoneword-initial.png](https://qiita-image-store.s3.amazonaws.com/0/43745/ad7be0d9-789a-9e2e-0d54-ebdcb24dfa4f.png)

Translateボタンを押します。Callボタンがアクティブになり、数値に変換された電話番号が表示されました。


![genymotion-phoneword-translate.png](https://qiita-image-store.s3.amazonaws.com/0/43745/4d2f0dc9-0869-3c16-5909-9d5c554d962f.png)

Callボタンを押します。電話をかけるダイアログが表示されました。


![genymotion-phoneword-call.png](https://qiita-image-store.s3.amazonaws.com/0/43745/92588afd-10cb-94ef-0bc2-f7a540552ca9.png)


## Git

[Version Control in Xamarin Studio](http://forums.xamarin.com/discussion/13221/version-control-in-xamarin-studio)を参考にして、PhoneWordソリューションディレクトリに`.gitignore`を作成します。

``` bash:.gitignore
#Autosave files
*~

# Build/test output
obj
bin
test-results

# VS sometimes writes these for no apparent reason
_UpgradeReport_Files
UpgradeLog.*

# Per-user data
*.DS_Store
*.sln.cache
*.suo
*.userprefs
*.usertasks
*.user

# ReSharper
*_Resharper.*
*.Resharper

# dotCover
*.dotCover
```

ローカルにGitのリポジトリを作成してcommitします。

``` bash
> cd C:\Users\masato\Documents\Projects\PhoneWord
> git init
> git add -A
> git commit -m "initilal commit"
```

GitHubにリモートリポジトリを作成して追加します。

``` bash
$ git remote add origin https://github.com/masato/PhoneWord.git
$ git push -u origin master
Username for 'https://github.com': masato
Password for 'https://masato@github.com':
Counting objects: 33, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (24/24), done.
Writing objects: 100% (33/33), 28.82 KiB | 0 bytes/s, done.
Total 33 (delta 4), reused 0 (delta 0)
To https://github.com/masato/PhoneWord.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.
```