Add SilkFX demo app
Silk prototyping area for HDR & other exploration
Test: this
Change-Id: I3b8b7d23454f26fa0842a59a4c82f503c0a58897
diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp
new file mode 100644
index 0000000..ca0a091
--- /dev/null
+++ b/tests/SilkFX/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2010 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.
+//
+
+android_test {
+ name: "SilkFX",
+ srcs: ["**/*.java", "**/*.kt"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml
new file mode 100644
index 0000000..ca9550a
--- /dev/null
+++ b/tests/SilkFX/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.silkfx">
+
+ <uses-sdk android:minSdkVersion="30"/>
+
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
+
+ <application android:label="SilkFX"
+ android:theme="@android:style/Theme.Material">
+
+ <activity android:name=".Main"
+ android:label="SilkFX Demos"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".app.CommonDemoActivity" />
+
+ <activity android:name=".hdr.GlowActivity"
+ android:label="Glow Examples"/>
+
+ </application>
+</manifest>
diff --git a/tests/SilkFX/res/drawable-nodpi/dark_notification.png b/tests/SilkFX/res/drawable-nodpi/dark_notification.png
new file mode 100644
index 0000000..6de6c2a
--- /dev/null
+++ b/tests/SilkFX/res/drawable-nodpi/dark_notification.png
Binary files differ
diff --git a/tests/SilkFX/res/drawable-nodpi/light_notification.png b/tests/SilkFX/res/drawable-nodpi/light_notification.png
new file mode 100644
index 0000000..81a67cd
--- /dev/null
+++ b/tests/SilkFX/res/drawable-nodpi/light_notification.png
Binary files differ
diff --git a/tests/SilkFX/res/layout/bling_notifications.xml b/tests/SilkFX/res/layout/bling_notifications.xml
new file mode 100644
index 0000000..6d266b7
--- /dev/null
+++ b/tests/SilkFX/res/layout/bling_notifications.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <com.android.test.silkfx.hdr.BlingyNotification
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:src="@drawable/dark_notification" />
+
+ <com.android.test.silkfx.hdr.BlingyNotification
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:src="@drawable/light_notification" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/SilkFX/res/layout/color_mode_controls.xml b/tests/SilkFX/res/layout/color_mode_controls.xml
new file mode 100644
index 0000000..c0c0bab
--- /dev/null
+++ b/tests/SilkFX/res/layout/color_mode_controls.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<com.android.test.silkfx.common.ColorModeControls
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/current_mode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/mode_default"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Default (sRGB)" />
+
+ <Button
+ android:id="@+id/mode_wide"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Wide Gamut (P3)" />
+
+ <Button
+ android:id="@+id/mode_hdr"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="HDR" />
+
+ <Button
+ android:id="@+id/mode_hdr10"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="HDR10" />
+
+ </LinearLayout>
+
+</com.android.test.silkfx.common.ColorModeControls>
\ No newline at end of file
diff --git a/tests/SilkFX/res/layout/common_base.xml b/tests/SilkFX/res/layout/common_base.xml
new file mode 100644
index 0000000..944c684
--- /dev/null
+++ b/tests/SilkFX/res/layout/common_base.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/color_mode_controls" />
+
+ <FrameLayout android:id="@+id/demo_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <com.android.test.silkfx.common.HDRIndicator
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="8dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/SilkFX/res/layout/hdr_glows.xml b/tests/SilkFX/res/layout/hdr_glows.xml
new file mode 100644
index 0000000..b6050645
--- /dev/null
+++ b/tests/SilkFX/res/layout/hdr_glows.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/color_mode_controls" />
+
+ <com.android.test.silkfx.hdr.GlowingCard
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:layout_margin="8dp" />
+
+ <com.android.test.silkfx.hdr.GlowingCard
+ android:id="@+id/card2"
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:layout_margin="8dp"/>
+
+ <com.android.test.silkfx.hdr.RadialGlow
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:layout_margin="8dp" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <com.android.test.silkfx.common.HDRIndicator
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="8dp" />
+
+</LinearLayout>
\ 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
new file mode 100644
index 0000000..76e62a6
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -0,0 +1,125 @@
+/*
+ * 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
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseExpandableListAdapter
+import android.widget.ExpandableListView
+import android.widget.TextView
+import com.android.test.silkfx.app.CommonDemoActivity
+import com.android.test.silkfx.app.EXTRA_LAYOUT
+import com.android.test.silkfx.app.EXTRA_TITLE
+import com.android.test.silkfx.hdr.GlowActivity
+import kotlin.reflect.KClass
+
+class Demo(val name: String, val makeIntent: (Context) -> Intent) {
+ constructor(name: String, activity: KClass<out Activity>) : this(name, { context ->
+ Intent(context, activity.java)
+ })
+ constructor(name: String, layout: Int) : this(name, { context ->
+ Intent(context, CommonDemoActivity::class.java).apply {
+ putExtra(EXTRA_LAYOUT, layout)
+ putExtra(EXTRA_TITLE, name)
+ }
+ })
+}
+data class DemoGroup(val groupName: String, val demos: List<Demo>)
+
+private val AllDemos = listOf(
+ DemoGroup("HDR", listOf(
+ Demo("Glow", GlowActivity::class),
+ Demo("Blingy Notifications", R.layout.bling_notifications)
+ ))
+)
+
+class Main : Activity() {
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val list = ExpandableListView(this)
+
+ setContentView(list)
+
+ val inflater = LayoutInflater.from(this)
+ list.setAdapter(object : BaseExpandableListAdapter() {
+ override fun getGroup(groupPosition: Int): DemoGroup {
+ return AllDemos[groupPosition]
+ }
+
+ override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean = true
+
+ override fun hasStableIds(): Boolean = true
+
+ override fun getGroupView(
+ groupPosition: Int,
+ isExpanded: Boolean,
+ convertView: View?,
+ parent: ViewGroup?
+ ): View {
+ val view = (convertView ?: inflater.inflate(
+ android.R.layout.simple_expandable_list_item_1, parent, false)) as TextView
+ view.text = AllDemos[groupPosition].groupName
+ return view
+ }
+
+ override fun getChildrenCount(groupPosition: Int): Int {
+ return AllDemos[groupPosition].demos.size
+ }
+
+ override fun getChild(groupPosition: Int, childPosition: Int): Demo {
+ return AllDemos[groupPosition].demos[childPosition]
+ }
+
+ override fun getGroupId(groupPosition: Int): Long = groupPosition.toLong()
+
+ override fun getChildView(
+ groupPosition: Int,
+ childPosition: Int,
+ isLastChild: Boolean,
+ convertView: View?,
+ parent: ViewGroup?
+ ): View {
+ val view = (convertView ?: inflater.inflate(
+ android.R.layout.simple_expandable_list_item_1, parent, false)) as TextView
+ view.text = AllDemos[groupPosition].demos[childPosition].name
+ return view
+ }
+
+ override fun getChildId(groupPosition: Int, childPosition: Int): Long {
+ return (groupPosition.toLong() shl 32) or childPosition.toLong()
+ }
+
+ override fun getGroupCount(): Int {
+ return AllDemos.size
+ }
+ })
+
+ list.setOnChildClickListener { _, _, groupPosition, childPosition, _ ->
+ val demo = AllDemos[groupPosition].demos[childPosition]
+ startActivity(demo.makeIntent(this))
+ return@setOnChildClickListener true
+ }
+
+ AllDemos.forEachIndexed { index, _ -> list.expandGroup(index) }
+ }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
new file mode 100644
index 0000000..89011b5
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.app
+
+import android.app.Activity
+import android.content.Context
+import android.os.Bundle
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+
+open class BaseDemoActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val inflater = LayoutInflater.from(this)
+ inflater.factory2 = object : LayoutInflater.Factory2 {
+ private val sClassPrefixList = arrayOf(
+ "android.widget.",
+ "android.webkit.",
+ "android.app.",
+ null
+ )
+ override fun onCreateView(
+ parent: View?,
+ name: String,
+ context: Context,
+ attrs: AttributeSet
+ ): View? {
+ return onCreateView(name, context, attrs)
+ }
+
+ override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
+ for (prefix in sClassPrefixList) {
+ try {
+ val view = inflater.createView(name, prefix, attrs)
+ if (view != null) {
+ if (view is WindowObserver) {
+ view.setWindow(window)
+ }
+ return view
+ }
+ } catch (e: ClassNotFoundException) { }
+ }
+ return null
+ }
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ actionBar?.setDisplayHomeAsUpEnabled(true)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ return true
+ }
+ return super.onOptionsItemSelected(item)
+ }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
new file mode 100644
index 0000000..e0a0a20
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.app
+
+import com.android.test.silkfx.R
+import android.os.Bundle
+import android.view.LayoutInflater
+
+const val EXTRA_LAYOUT = "layout"
+const val EXTRA_TITLE = "title"
+
+class CommonDemoActivity : BaseDemoActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val extras = intent.extras ?: return finish()
+
+ val layout = extras.getInt(EXTRA_LAYOUT, -1)
+ if (layout == -1) {
+ finish()
+ return
+ }
+ val title = extras.getString(EXTRA_TITLE, "SilkFX")
+ window.setTitle(title)
+
+ setContentView(R.layout.common_base)
+ actionBar?.title = title
+ LayoutInflater.from(this).inflate(layout, findViewById(R.id.demo_container), true)
+ }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt b/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
new file mode 100644
index 0000000..3d989a5
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.app
+
+import android.view.Window
+
+interface WindowObserver {
+ fun setWindow(window: Window)
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt b/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
new file mode 100644
index 0000000..4b85953
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.common
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.ColorSpace
+import android.util.AttributeSet
+import android.view.View
+
+open class BaseDrawingView : View {
+ val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
+ val bt2020 = ColorSpace.get(ColorSpace.Named.BT2020)
+ val lab = ColorSpace.get(ColorSpace.Named.CIE_LAB)
+
+ val density: Float
+ val dp: Int.() -> Float
+
+ fun color(red: Float, green: Float, blue: Float, alpha: Float = 1f): Long {
+ return Color.pack(red, green, blue, alpha, scRGB)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ setWillNotDraw(false)
+ isClickable = true
+ density = resources.displayMetrics.density
+ dp = { this * density }
+ }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
new file mode 100644
index 0000000..c3d689c
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.common
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.hardware.display.DisplayManager
+import android.util.AttributeSet
+import android.view.Window
+import android.widget.Button
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.test.silkfx.R
+import com.android.test.silkfx.app.WindowObserver
+import java.lang.Exception
+
+class ColorModeControls : LinearLayout, WindowObserver {
+ private val COLOR_MODE_HDR10 = 3
+
+ constructor(context: Context) : this(context, null)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ displayManager = context.getSystemService(DisplayManager::class.java)!!
+ }
+
+ private var window: Window? = null
+ private var currentMode: TextView? = null
+ private val displayManager: DisplayManager
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ val window = window ?: throw IllegalStateException("Failed to attach window")
+
+ currentMode = findViewById(R.id.current_mode)!!
+ setColorMode(window.colorMode)
+
+ findViewById<Button>(R.id.mode_default)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_DEFAULT)
+ }
+ findViewById<Button>(R.id.mode_wide)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT)
+ }
+ findViewById<Button>(R.id.mode_hdr)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_HDR)
+ }
+ findViewById<Button>(R.id.mode_hdr10)!!.setOnClickListener {
+ setColorMode(COLOR_MODE_HDR10)
+ }
+ }
+
+ private fun setColorMode(newMode: Int) {
+ val window = window!!
+ // Need to do this before setting the colorMode, as setting the colorMode will
+ // trigger the attribute change listener
+ if (newMode == ActivityInfo.COLOR_MODE_HDR ||
+ newMode == COLOR_MODE_HDR10) {
+ setBrightness(1.0f)
+ } else {
+ setBrightness(.4f)
+ }
+ window.colorMode = newMode
+ currentMode?.run {
+ text = "Current Mode: " + when (newMode) {
+ ActivityInfo.COLOR_MODE_DEFAULT -> "Default/SRGB"
+ ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT -> "Wide Gamut"
+ ActivityInfo.COLOR_MODE_HDR -> "HDR (sdr white point 150)"
+ COLOR_MODE_HDR10 -> "HDR10 (sdr white point 150)"
+ else -> "Unknown"
+ }
+ }
+ }
+
+ override fun setWindow(window: Window) {
+ this.window = window
+ }
+
+ private fun setBrightness(level: Float) {
+ // To keep window state in sync
+ window?.attributes?.screenBrightness = level
+ invalidate()
+ // To force an 'immediate' snap to what we want
+ // Imperfect, but close enough, synchronization by waiting for frame commit to set the value
+ viewTreeObserver.registerFrameCommitCallback {
+ try {
+ displayManager.setTemporaryBrightness(level)
+ } catch (ex: Exception) {
+ // Ignore a permission denied rejection - it doesn't meaningfully change much
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt b/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
new file mode 100644
index 0000000..f42161f
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.common
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorSpace
+import android.graphics.Paint
+import android.graphics.RectF
+import android.util.AttributeSet
+import android.view.View
+
+class HDRIndicator(context: Context) : View(context) {
+ constructor(context: Context, attrs: AttributeSet?) : this(context)
+
+ val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ val paint = Paint()
+ paint.isAntiAlias = true
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+ paint.textSize = height.toFloat()
+
+ canvas.drawColor(Color.pack(1f, 1f, 1f, 1f, scRGB))
+
+ paint.setColor(Color.pack(1.1f, 1.1f, 1.1f, 1f, scRGB))
+ canvas.drawText("H", rect.left, rect.bottom, paint)
+ paint.setColor(Color.pack(1.2f, 1.2f, 1.2f, 1f, scRGB))
+ canvas.drawText("D", rect.left + height.toFloat(), rect.bottom, paint)
+ paint.setColor(Color.pack(1.3f, 1.3f, 1.3f, 1f, scRGB))
+ canvas.drawText("R", rect.left + height.toFloat() * 2, rect.bottom, paint)
+ }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
new file mode 100644
index 0000000..e517c3c
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
@@ -0,0 +1,99 @@
+/*
+ * 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.hdr
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.LinearGradient
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.Shader
+import android.graphics.drawable.BitmapDrawable
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+
+class BlingyNotification : BaseDrawingView {
+
+ private val image: Bitmap?
+ private val bounds = Rect()
+ private val paint = Paint()
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ val typed = context.obtainStyledAttributes(attrs, intArrayOf(android.R.attr.src))
+ val drawable = typed.getDrawable(0)
+ image = if (drawable is BitmapDrawable) {
+ drawable.bitmap
+ } else {
+ null
+ }
+ typed.recycle()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val image = image ?: return super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+ val widthMode = MeasureSpec.getMode(widthMeasureSpec)
+ val heightMode = MeasureSpec.getMode(heightMeasureSpec)
+
+ // Currently only used in this mode, so that's all we'll bother to support
+ if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
+ val width = MeasureSpec.getSize(widthMeasureSpec)
+
+ var height = image.height * width / image.width
+ if (heightMode == MeasureSpec.AT_MOST) {
+ height = minOf(MeasureSpec.getSize(heightMeasureSpec), height)
+ }
+ setMeasuredDimension(width, height)
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ bounds.set(0, 0, w, h)
+ paint.shader = LinearGradient(0f, 0f, w.toFloat(), 0f,
+ longArrayOf(
+ color(1f, 1f, 1f, 0f),
+ color(1f, 1f, 1f, .4f),
+ color(2f, 2f, 2f, .8f),
+ color(1f, 1f, 1f, .4f),
+ color(1f, 1f, 1f, 0f)
+ ),
+ floatArrayOf(.2f, .4f, .5f, .6f, .8f),
+ Shader.TileMode.CLAMP)
+ paint.blendMode = BlendMode.PLUS
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ val image = image ?: return
+
+ canvas.drawBitmap(image, null, bounds, null)
+
+ canvas.save()
+ val frac = ((drawingTime % 2000) / 300f) - 1f
+ canvas.translate(width * frac, 0f)
+ canvas.rotate(-45f)
+ canvas.drawPaint(paint)
+ canvas.restore()
+ invalidate()
+ }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
new file mode 100644
index 0000000..64dbb22
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.hdr
+
+import android.os.Bundle
+import com.android.test.silkfx.R
+import com.android.test.silkfx.app.BaseDemoActivity
+
+class GlowActivity : BaseDemoActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.hdr_glows)
+ findViewById<GlowingCard>(R.id.card2)!!.setGlowIntensity(4f)
+ }
+}
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
new file mode 100644
index 0000000..b388bb6
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.hdr
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.LinearGradient
+import android.graphics.Paint
+import android.graphics.RectF
+import android.graphics.Shader
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+
+class GlowingCard : BaseDrawingView {
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ val radius: Float
+ var COLOR_MAXIMIZER = 1f
+
+ init {
+ radius = 10.dp()
+ }
+
+ fun setGlowIntensity(multiplier: Float) {
+ COLOR_MAXIMIZER = multiplier
+ invalidate()
+ }
+
+ override fun setPressed(pressed: Boolean) {
+ super.setPressed(pressed)
+ invalidate()
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ val paint = Paint()
+ paint.isAntiAlias = true
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+ val glowColor = Color.pack(.5f * COLOR_MAXIMIZER, .4f * COLOR_MAXIMIZER,
+ .75f * COLOR_MAXIMIZER, 1f, scRGB)
+
+ if (isPressed) {
+ paint.setColor(Color.pack(2f, 2f, 2f, 1f, scRGB))
+ paint.strokeWidth = 4.dp()
+ paint.style = Paint.Style.FILL
+ paint.shader = LinearGradient(rect.left, rect.bottom, rect.right, rect.top,
+ glowColor,
+ Color.pack(0f, 0f, 0f, 0f, scRGB),
+ Shader.TileMode.CLAMP)
+ canvas.drawRoundRect(rect, radius, radius, paint)
+ }
+
+ rect.inset(3.dp(), 3.dp())
+
+ paint.setColor(Color.pack(.14f, .14f, .14f, .8f, scRGB))
+ paint.style = Paint.Style.FILL
+ paint.shader = null
+ canvas.drawRoundRect(rect, radius, radius, paint)
+
+ rect.inset(5.dp(), 5.dp())
+ paint.textSize = 14.dp()
+ paint.isFakeBoldText = true
+
+ paint.color = Color.WHITE
+ canvas.drawText("glow = scRGB{${Color.red(glowColor)}, ${Color.green(glowColor)}, " +
+ "${Color.blue(glowColor)}}", rect.left, rect.centerY(), paint)
+ canvas.drawText("(press to activate)", rect.left, rect.bottom, paint)
+ }
+}
\ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
new file mode 100644
index 0000000..599585e
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.hdr
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RadialGradient
+import android.graphics.RectF
+import android.graphics.Shader
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+import kotlin.math.min
+
+class RadialGlow : BaseDrawingView {
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ var glowToggle = false
+
+ val glowColor = color(4f, 3.3f, 2.8f)
+ val bgColor = color(.15f, .15f, .15f)
+ val fgColor = color(.51f, .52f, .50f, .4f)
+ var glow: RadialGradient
+
+ init {
+ glow = RadialGradient(0f, 0f, 100.dp(), glowColor, bgColor, Shader.TileMode.CLAMP)
+ isClickable = true
+ setOnClickListener {
+ glowToggle = !glowToggle
+ invalidate()
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ glow = RadialGradient(0f, 0f,
+ min(w, h).toFloat(), glowColor, bgColor, Shader.TileMode.CLAMP)
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ val radius = 10.dp()
+
+ val paint = Paint()
+ paint.isDither = true
+ paint.isAntiAlias = true
+ paint.textSize = 18.dp()
+ paint.textAlign = Paint.Align.CENTER
+
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+
+ paint.setColor(bgColor)
+ canvas.drawRoundRect(rect, radius, radius, paint)
+
+ if (glowToggle) {
+ paint.shader = glow
+ canvas.save()
+ val frac = (drawingTime % 5000) / 5000f
+ canvas.translate(rect.width() * frac, rect.height() - (rect.height() * frac))
+ canvas.drawPaint(paint)
+ canvas.restore()
+ paint.shader = null
+ invalidate()
+ }
+
+ paint.setColor(fgColor)
+ val innerRect = RectF(rect)
+ innerRect.inset(rect.width() / 4, rect.height() / 4)
+ canvas.drawRoundRect(innerRect, radius, radius, paint)
+
+ paint.setColor(color(1f, 1f, 1f))
+ canvas.drawText("Tap to toggle animation", rect.centerX(), innerRect.top - 4.dp(), paint)
+ canvas.drawText("Outside text", rect.centerX(), rect.bottom - 4.dp(), paint)
+ canvas.drawText("Inside text", innerRect.centerX(), innerRect.bottom - 4.dp(), paint)
+ }
+}
\ No newline at end of file