rksoftware

Visual Studio とか C# とかが好きです

Xamarin Forms で画面をスリープしないようにする

Xamarin Forms で画面を消灯しないようにするには、良い Plugin がないようです。
Xam.Plugins.ManageSleep という Plugin がありましたが、残念ながら Android の画面が消灯してしまいます。

■ 概要

iOS と Android で画面を消灯しないようにする機能を実装し、DependencyService で共通コードから呼び出します。

■ コード

早速コードです。今回は XFKeepScreen というプロジェクト名で作っています。
iOS
UIApplication.SharedApplication.IdleTimerDisabled の値を設定しているだけのシンプルなコードです。

using UIKit;
using XFKeepScreen.iOS;

[assembly: Xamarin.Forms.Dependency(typeof(KeppScreenOn))]
namespace XFKeepScreen.iOS
{
    public class KeppScreenOn : IKeepScreenOn
    {
        public void Set(bool keepOn) => UIApplication.SharedApplication.InvokeOnMainThread(() =>
                                UIApplication.SharedApplication.IdleTimerDisabled = keepOn);
    }
}

Android
こちらは少し複雑になっています。WindowManagerFlags.KeepScreenOn フラグを設定するだけの簡単な処理なのですが、厄介なのは設定する際に Activity のインスタンスが必要な点です。
今回は MainActivityOnCreate の中で static フィールドに確保するようにしています。
実は Activity のインスタンスは Xamarin.Forms.Forms.Context プロパティで簡単に取得することもできるのですが、残念なことにこのプロパティは Obsolete とされています。 動作はしますが警告になってしまうため今回は使用していません。

using Android.App;
using Android.Content.PM;
using Android.Views;
using Android.OS;
using XFKeepScreen.Droid;

[assembly: Xamarin.Forms.Dependency(typeof(KeppScreenOn))]
namespace XFKeepScreen.Droid
{
    [Activity(Label = "XFKeepScreen", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true,
                 ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);

            // ここで Activity を static フィールドに確保している
            KeppScreenOn.SetActivity(this);

            LoadApplication(new App());
        }
    }

    public class KeppScreenOn : IKeepScreenOn
    {
        // Activity を static フィールドに確保
        private static Activity _mainActivity;
        public static void SetActivity(Activity activity) => _mainActivity = activity;

        // KeepScreenOn を設定
        public void Set(bool keepOn) => _mainActivity.RunOnUiThread(() =>
        {
            if (keepOn)
                _mainActivity.Window.AddFlags(WindowManagerFlags.KeepScreenOn);
            else
                _mainActivity.Window.ClearFlags(WindowManagerFlags.KeepScreenOn);
        });
    }
}

共通コード
DependencyService で IKeepScreenOn の実装を取り出し、Set メソッドで ON/OFF を設定します。

using System.Threading.Tasks;
using Xamarin.Forms;

namespace XFKeepScreen
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            // UI の構築。KeepScreenOn の使い方とは直接関係ない
            var sl = (StackLayout)(this.Content = new StackLayout());
            var button = new Button() { Text = "button" };
            sl.Children.Add(button);

            // この処理内が KeepScreenOn の使い方
            button.Clicked += async (sender, e) =>
            {
                var keepScreenOn = DependencyService.Get<IKeepScreenOn>();
                keepScreenOn.Set(true);

                // ...ここに時間のかかる処理...

                keepScreenOn.Set(false);
            };
        }
    }

    public interface IKeepScreenOn
    {
        void Set(bool keepOn);
    }
}

■ Dependency Service について

今回利用している Dependency Service については次を参考にしてください。