Frosted glass material test

Change-Id: Ifbdd0e5cc575410ab7f9badc8089bb3c9f1e5379
Test: manual
diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp
index ca0a091..92e3efa 100644
--- a/tests/SilkFX/Android.bp
+++ b/tests/SilkFX/Android.bp
@@ -19,4 +19,10 @@
     srcs: ["**/*.java", "**/*.kt"],
     platform_apis: true,
     certificate: "platform",
+        static_libs: [
+        "androidx.core_core",
+        "androidx.appcompat_appcompat",
+        "com.google.android.material_material",
+        "androidx-constraintlayout_constraintlayout",
+    ],
 }
diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml
index ca9550a..050e9c3 100644
--- a/tests/SilkFX/AndroidManifest.xml
+++ b/tests/SilkFX/AndroidManifest.xml
@@ -39,5 +39,8 @@
         <activity android:name=".hdr.GlowActivity"
             android:label="Glow Examples"/>
 
+        <activity android:name=".materials.GlassActivity"
+            android:label="Glass Examples"/>
+
     </application>
 </manifest>
diff --git a/tests/SilkFX/res/drawable-hdpi/background1.jpeg b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
new file mode 100644
index 0000000..dcdfa7b
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background2.jpeg b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
new file mode 100644
index 0000000..dc7ce84e
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background3.jpeg b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
new file mode 100644
index 0000000..12b3429
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/noise.png b/tests/SilkFX/res/drawable-hdpi/noise.png
new file mode 100644
index 0000000..053995d
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/noise.png
Binary files differ
diff --git a/tests/SilkFX/res/layout/activity_glass.xml b/tests/SilkFX/res/layout/activity_glass.xml
new file mode 100644
index 0000000..85dab93
--- /dev/null
+++ b/tests/SilkFX/res/layout/activity_glass.xml
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+    <ImageView
+        android:id="@+id/background"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:scaleType="matrix"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:srcCompat="@drawable/background1" />
+
+    <com.android.test.silkfx.materials.GlassView
+        android:id="@+id/materialView"
+        android:layout_width="0dp"
+        android:layout_height="180dp"
+        android:layout_marginEnd="64dp"
+        android:layout_marginStart="64dp"
+        app:layout_constraintBottom_toTopOf="@+id/bottomPanel"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/bottomPanel"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/colorBackground"
+        android:paddingTop="24dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent">
+
+    <SeekBar
+        android:id="@+id/materialOpacity"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="12dp"
+        android:layout_marginEnd="12dp"
+        android:layout_marginBottom="16dp"
+        android:max="100"
+        android:progress="12"
+        app:layout_constraintBottom_toTopOf="@+id/scrimOpacityTitle"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="1.0"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <SeekBar
+        android:id="@+id/blurRadius"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:layout_marginEnd="12dp"
+        android:layout_marginStart="12dp"
+        android:max="150"
+        android:progress="50"
+        app:layout_constraintBottom_toTopOf="@+id/materialOpacityTitle"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="1.0"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <SeekBar
+        android:id="@+id/scrimOpacity"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="12dp"
+        android:layout_marginEnd="12dp"
+        android:layout_marginBottom="16dp"
+        android:max="100"
+        android:progress="50"
+        app:layout_constraintBottom_toTopOf="@+id/noiseOpacityTitle"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="1.0"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <SeekBar
+        android:id="@+id/noiseOpacity"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="12dp"
+        android:layout_marginEnd="12dp"
+        android:layout_marginBottom="24dp"
+        android:max="100"
+        android:progress="5"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.0"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <TextView
+        android:id="@+id/scrimOpacityTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="24dp"
+        android:layout_marginBottom="8dp"
+        android:text="Scrim Opacity"
+        android:textColor="@android:color/white"
+        app:layout_constraintBottom_toTopOf="@+id/scrimOpacity"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <TextView
+        android:id="@+id/materialOpacityTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="24dp"
+        android:layout_marginBottom="8dp"
+        android:text="Material Opacity"
+        android:textColor="@android:color/white"
+        app:layout_constraintBottom_toTopOf="@+id/materialOpacity"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <TextView
+        android:id="@+id/blurRadiusTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="24dp"
+        android:layout_marginBottom="8dp"
+        android:text="Blur Radius"
+        android:textColor="@android:color/white"
+        app:layout_constraintBottom_toTopOf="@+id/blurRadius"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <TextView
+        android:id="@+id/noiseOpacityTitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="24dp"
+        android:layout_marginBottom="8dp"
+        android:textColor="@android:color/white"
+        android:text="Noise Opacity"
+        app:layout_constraintBottom_toTopOf="@+id/noiseOpacity"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <ImageView
+        android:id="@+id/background1"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_marginStart="24dp"
+        android:layout_marginBottom="16dp"
+        android:foreground="?android:attr/selectableItemBackgroundBorderless"
+        android:clickable="true"
+        android:onClick="onBackgroundClick"
+        android:scaleType="centerCrop"
+        app:layout_constraintBottom_toTopOf="@+id/lightMaterialSwitch"
+        app:layout_constraintStart_toStartOf="parent"
+        android:src="@drawable/background1" />
+
+    <ImageView
+        android:id="@+id/background2"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_marginStart="8dp"
+        android:foreground="?android:attr/selectableItemBackgroundBorderless"
+        android:clickable="true"
+        android:onClick="onBackgroundClick"
+        android:scaleType="centerCrop"
+        app:layout_constraintBottom_toBottomOf="@+id/background1"
+        app:layout_constraintStart_toEndOf="@+id/background1"
+        android:src="@drawable/background2" />
+
+    <ImageView
+        android:id="@+id/background3"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_marginStart="8dp"
+        android:scaleType="centerCrop"
+        android:foreground="?android:attr/selectableItemBackgroundBorderless"
+        android:clickable="true"
+        android:onClick="onBackgroundClick"
+        app:layout_constraintBottom_toBottomOf="@+id/background1"
+        app:layout_constraintStart_toEndOf="@+id/background2"
+        android:src="@drawable/background3" />
+
+    <Switch
+        android:id="@+id/lightMaterialSwitch"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="24dp"
+        android:layout_marginBottom="8dp"
+        android:text="Light Material"
+        app:layout_constraintBottom_toTopOf="@+id/blurRadiusTitle"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <TextView
+        android:id="@+id/blurRadiusValue"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="TextView"
+        android:layout_marginLeft="8dp"
+        app:layout_constraintBottom_toBottomOf="@+id/blurRadiusTitle"
+        app:layout_constraintStart_toEndOf="@+id/blurRadiusTitle" />
+
+    <TextView
+        android:id="@+id/materialOpacityValue"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="TextView"
+        android:layout_marginLeft="8dp"
+        app:layout_constraintBottom_toBottomOf="@+id/materialOpacityTitle"
+        app:layout_constraintStart_toEndOf="@+id/materialOpacityTitle" />
+
+    <TextView
+        android:id="@+id/noiseOpacityValue"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="TextView"
+        android:layout_marginLeft="8dp"
+        app:layout_constraintBottom_toBottomOf="@+id/noiseOpacityTitle"
+        app:layout_constraintStart_toEndOf="@+id/noiseOpacityTitle" />
+
+
+    <TextView
+        android:id="@+id/scrimOpacityValue"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="TextView"
+        android:layout_marginLeft="8dp"
+        app:layout_constraintBottom_toBottomOf="@+id/scrimOpacityTitle"
+        app:layout_constraintStart_toEndOf="@+id/scrimOpacityTitle" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
index 76e62a6..9ed8d2f 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/Main.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -29,6 +29,7 @@
 import com.android.test.silkfx.app.EXTRA_LAYOUT
 import com.android.test.silkfx.app.EXTRA_TITLE
 import com.android.test.silkfx.hdr.GlowActivity
+import com.android.test.silkfx.materials.GlassActivity
 import kotlin.reflect.KClass
 
 class Demo(val name: String, val makeIntent: (Context) -> Intent) {
@@ -48,6 +49,9 @@
         DemoGroup("HDR", listOf(
                 Demo("Glow", GlowActivity::class),
                 Demo("Blingy Notifications", R.layout.bling_notifications)
+        )),
+        DemoGroup("Materials", listOf(
+                Demo("Glass", GlassActivity::class)
         ))
 )
 
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
new file mode 100644
index 0000000..6f5ddac
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.silkfx.materials
+
+import android.app.Activity
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.os.Bundle
+import android.util.TypedValue
+import android.view.View
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.Switch
+import android.widget.TextView
+import com.android.test.silkfx.R
+
+class GlassActivity : Activity(), SeekBar.OnSeekBarChangeListener {
+
+    lateinit var backgroundButton1: ImageView
+    lateinit var backgroundButton2: ImageView
+    lateinit var backgroundButton3: ImageView
+    lateinit var backgroundView: ImageView
+    lateinit var materialView: GlassView
+    lateinit var lightMaterialSwitch: Switch
+    lateinit var noiseOpacitySeekBar: SeekBar
+    lateinit var materialOpacitySeekBar: SeekBar
+    lateinit var scrimOpacitySeekBar: SeekBar
+    lateinit var blurRadiusSeekBar: SeekBar
+    lateinit var noiseOpacityValue: TextView
+    lateinit var materialOpacityValue: TextView
+    lateinit var scrimOpacityValue: TextView
+    lateinit var blurRadiusValue: TextView
+
+    lateinit var background: Bitmap
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_glass)
+        backgroundButton1 = requireViewById(R.id.background1)
+        backgroundButton2 = requireViewById(R.id.background2)
+        backgroundButton3 = requireViewById(R.id.background3)
+        backgroundView = requireViewById(R.id.background)
+        lightMaterialSwitch = requireViewById(R.id.lightMaterialSwitch)
+        materialView = requireViewById(R.id.materialView)
+        materialOpacitySeekBar = requireViewById(R.id.materialOpacity)
+        blurRadiusSeekBar = requireViewById(R.id.blurRadius)
+        noiseOpacitySeekBar = requireViewById(R.id.noiseOpacity)
+        scrimOpacitySeekBar = requireViewById(R.id.scrimOpacity)
+        noiseOpacityValue = requireViewById(R.id.noiseOpacityValue)
+        materialOpacityValue = requireViewById(R.id.materialOpacityValue)
+        scrimOpacityValue = requireViewById(R.id.scrimOpacityValue)
+        blurRadiusValue = requireViewById(R.id.blurRadiusValue)
+
+        background = BitmapFactory.decodeResource(resources, R.drawable.background1)
+        backgroundView.setImageBitmap(background)
+        materialView.backgroundBitmap = background
+
+        blurRadiusSeekBar.setOnSeekBarChangeListener(this)
+        materialOpacitySeekBar.setOnSeekBarChangeListener(this)
+        noiseOpacitySeekBar.setOnSeekBarChangeListener(this)
+        scrimOpacitySeekBar.setOnSeekBarChangeListener(this)
+
+        arrayOf(blurRadiusSeekBar, materialOpacitySeekBar, noiseOpacitySeekBar,
+                scrimOpacitySeekBar).forEach {
+            it.setOnSeekBarChangeListener(this)
+            onProgressChanged(it, it.progress, fromUser = false)
+        }
+
+        lightMaterialSwitch.setOnCheckedChangeListener { _, isChecked ->
+            materialView.color = if (isChecked) Color.WHITE else Color.BLACK
+        }
+    }
+
+    override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+        when (seekBar) {
+            blurRadiusSeekBar -> {
+                materialView.blurRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                progress.toFloat(), resources.displayMetrics)
+                blurRadiusValue.text = progress.toString()
+            }
+            materialOpacitySeekBar -> {
+                materialView.materialOpacity = progress / seekBar.max.toFloat()
+                materialOpacityValue.text = progress.toString()
+            }
+            noiseOpacitySeekBar -> {
+                materialView.noiseOpacity = progress / seekBar.max.toFloat()
+                noiseOpacityValue.text = progress.toString()
+            }
+            scrimOpacitySeekBar -> {
+                materialView.scrimOpacity = progress / seekBar.max.toFloat()
+                scrimOpacityValue.text = progress.toString()
+            }
+            else -> throw IllegalArgumentException("Unknown seek bar")
+        }
+    }
+
+    override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+
+    fun onBackgroundClick(view: View) {
+        val resource = when (view) {
+            backgroundButton1 -> R.drawable.background1
+            backgroundButton2 -> R.drawable.background2
+            backgroundButton3 -> R.drawable.background3
+            else -> throw IllegalArgumentException("Invalid button")
+        }
+
+        background = BitmapFactory.decodeResource(resources, resource)
+        backgroundView.setImageBitmap(background)
+        materialView.backgroundBitmap = background
+    }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
new file mode 100644
index 0000000..e100959
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.silkfx.materials
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.BitmapShader
+import android.graphics.BlendMode
+import android.graphics.BlurShader
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.Shader
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewOutlineProvider
+import com.android.test.silkfx.R
+
+class GlassView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) {
+
+    var noise = BitmapFactory.decodeResource(resources, R.drawable.noise)
+    var materialPaint = Paint()
+    var scrimPaint = Paint()
+    var noisePaint = Paint()
+    var blurPaint = Paint()
+
+    val src = Rect()
+    val dst = Rect()
+
+    var backgroundBitmap: Bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+    set(value) {
+        field = value
+        invalidate()
+    }
+
+    var noiseOpacity = 0.0f
+    set(value) {
+        field = value
+        noisePaint.alpha = (value * 255).toInt()
+        invalidate()
+    }
+
+    var materialOpacity = 0.0f
+    set(value) {
+        field = value
+        materialPaint.alpha = (value * 255).toInt()
+        invalidate()
+    }
+
+    var scrimOpacity = 0.5f
+        set(value) {
+            field = value
+            scrimPaint.alpha = (value * 255).toInt()
+            invalidate()
+        }
+
+    var color = Color.BLACK
+    set(value) {
+        field = value
+        var alpha = materialPaint.alpha
+        materialPaint.color = color
+        materialPaint.alpha = alpha
+
+        alpha = scrimPaint.alpha
+        scrimPaint.color = color
+        scrimPaint.alpha = alpha
+        invalidate()
+    }
+
+    var blurRadius = 150f
+    set(value) {
+        field = value
+        blurPaint.shader = BlurShader(value, value, null)
+        invalidate()
+    }
+
+    init {
+        materialPaint.blendMode = BlendMode.SOFT_LIGHT
+        noisePaint.blendMode = BlendMode.SOFT_LIGHT
+        noisePaint.shader = BitmapShader(noise, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
+        scrimPaint.alpha = (scrimOpacity * 255).toInt()
+        noisePaint.alpha = (noiseOpacity * 255).toInt()
+        materialPaint.alpha = (materialOpacity * 255).toInt()
+        blurPaint.shader = BlurShader(blurRadius, blurRadius, null)
+        outlineProvider = object : ViewOutlineProvider() {
+            override fun getOutline(view: View?, outline: Outline?) {
+                outline?.setRoundRect(Rect(0, 0, width, height), 100f)
+            }
+        }
+        clipToOutline = true
+    }
+
+    override fun onDraw(canvas: Canvas?) {
+        src.set(left, top, right, bottom)
+        dst.set(0, 0, width, height)
+        canvas?.drawBitmap(backgroundBitmap, src, dst, blurPaint)
+        canvas?.drawRect(dst, materialPaint)
+        canvas?.drawRect(dst, noisePaint)
+        canvas?.drawRect(dst, scrimPaint)
+    }
+}
\ No newline at end of file