Androidでブルーライト軽減フィルターっぽいこと

#はじめに
最近ブルーライトをカットしてくれるメガネが売られていますが、スマホアプリにもブルーライトカットを
（本当にカット出来ているかは疑問ですが）謳っているアプリや明るさ調整のアプリがいくつか有ります。
似たような機能は"端末の輝度を設定"+"更にフィルターを掛ける"で実現出来るのでは無いでしょうか。
今回は後者の"更にフィルターを掛ける"部分を実装してみます。

#実装
##acticity_main.xml
フィルターを追加するボタンとフィルターを解除するボタンの２つだけがあるシンプルなものにします。
![image](https://qiita-image-store.s3.amazonaws.com/0/68671/a7a917fa-7e6b-78d6-fc18-1fc679f0b5ce.png)

```xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="add Filter"
        android:id="@+id/ButtonAddFilter"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Remove Filter"
        android:id="@+id/ButtonRemoveFilter"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />
</RelativeLayout>
```

##MainActivity.java
２つのボタンの挙動を実装します。
それぞれ単純にサービスのスタートとストップを行うだけです。

```java
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button buttonAddFilter = (Button) findViewById(R.id.ButtonAddFilter);
        buttonAddFilter.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, FilterService.class);
                startService(intent);
            }
        });

        Button buttonRemoveFilter = (Button) findViewById(R.id.ButtonRemoveFilter);
        buttonRemoveFilter.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, FilterService.class);
                stopService(intent);
            }
        });
    }
}
```

##filter.xml
画面サイズいっぱいに広がったImageViewを置きます。

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
```
##FilterService.java
今回の肝となる部分。

```java
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;

public class FilterService extends Service {

    private View mView;
    private WindowManager mWindowManager;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        LayoutInflater layoutInflater = LayoutInflater.from(this);

        //重ねあわせするViewの設定
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,      //オーバーレイヤーに設定
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT                              //ウインドウの透明化
        );

        //WindowManagerを取得
        mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

        //レイアウトファイルから重ねあわせするViewを作成
        mView = layoutInflater.inflate(R.layout.filter, null);

        //透過率80の黒色のフィルターを指定
        //パラメータは左から(透過率,R,G,B) ココをいじれば任意のフィルターに変更可能
        mView.setBackgroundColor(Color.argb(80, 0, 0, 0));

        //Viewを画面上に重ねあわせする
        mWindowManager.addView(mView, layoutParams);

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mWindowManager.removeView(mView);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
```

##AndroidManifest.xml
忘れがちですが、こちらにも追記が必要です。
うっかりパーミッションやサービスの定義を忘れると動きません(30分くらいハマりました。。。)。

```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="sample.masaibar.filtersample" >

    <!--パーミッション定義しないと動きません-->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--サービスを定義しないとstartService出来ません-->
        <service android:name=".FilterService"/>
    </application>

</manifest>
```
#動かしてみる
アプリを起動し、左側の「ADD FILTER」ボタンを押せばフィルターがかかります。
解除したいときは「REMOVE FILTER」を押して下さい。
左がフィルター無し、右がフィルター有り。同じ輝度での対比です。
フィルターを掛けた分だけ画面が暗くなっているのが分かります。
![image](https://qiita-image-store.s3.amazonaws.com/0/68671/9701f5be-046e-4c43-18ae-4ce9995f030f.png)

実際のコードを置いておきます。
https://github.com/masaibar/FilterSample