Fixed bug: Not everyone has home controls yet, or pets.
Fixes: 156301524
Test: # to enable controls component
adb shell am start -n com.android.egg.test/com.android.egg.neko.NekoActivationActivity
# manual step: activate controls from GlobalActions
# to visit the cat list
adb shell am start -n com.android.egg.test/com.android.egg.neko.NekoLand
# to check on the status of the food bowl job (once
# the food bowl control has been tapped)
adb shell cmd jobscheduler get-job-state com.android.egg.test 42
# to trigger the food immediately
adb shell cmd jobscheduler run com.android.egg.test 42
Change-Id: I985a930bb5dd56d99eb57a340e4affe08c09724b
diff --git a/packages/EasterEgg/Android.bp b/packages/EasterEgg/Android.bp
index 43ed810..b858ab0 100644
--- a/packages/EasterEgg/Android.bp
+++ b/packages/EasterEgg/Android.bp
@@ -23,11 +23,23 @@
name: "EasterEgg",
+ platform_apis: true,
certificate: "platform",
- sdk_version: "current",
-
optimize: {
enabled: false,
- }
+ },
+
+ static_libs: [
+ "androidx.core_core",
+ "androidx.recyclerview_recyclerview",
+ "androidx.annotation_annotation",
+ "kotlinx-coroutines-android",
+ "kotlinx-coroutines-core",
+ //"kotlinx-coroutines-reactive",
+ ],
+
+ manifest: "AndroidManifest.xml",
+
+ kotlincflags: ["-Xjvm-default=enable"],
}
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 7f76a45..57c459b 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -6,19 +6,24 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <!-- used for cat notifications -->
+ <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+ <!-- used to save cat images -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <!-- controls -->
+ <uses-permission android:name="android.permission.BIND_CONTROLS" />
+
<application
- android:icon="@drawable/q_icon"
+ android:icon="@drawable/icon"
android:label="@string/app_name">
+
<activity android:name=".quares.QuaresActivity"
android:icon="@drawable/q_icon"
android:label="@string/q_egg_name"
+ android:exported="true"
android:theme="@style/QuaresTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.DEFAULT" />
- <!-- <category android:name="android.intent.category.LAUNCHER" /> -->
- <category android:name="com.android.internal.category.PLATLOGO" />
</intent-filter>
</activity>
<activity
@@ -26,15 +31,86 @@
android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
android:icon="@drawable/p_icon"
android:label="@string/p_egg_name"
+ android:exported="true"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
-
- <!-- <category android:name="android.intent.category.DEFAULT" /> -->
- <!-- <category android:name="android.intent.category.LAUNCHER" /> -->
- <!-- <category android:name="com.android.internal.category.PLATLOGO" /> -->
</intent-filter>
</activity>
+
+ <!-- Android N easter egg bits -->
+ <activity android:name=".neko.NekoLand"
+ android:theme="@android:style/Theme.Material.NoActionBar"
+ android:exported="true"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <!-- This is where the magic happens -->
+ <service
+ android:name=".neko.NekoService"
+ android:enabled="true"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true" >
+ </service>
+
+ <!-- Used to show over lock screen -->
+ <activity android:name=".neko.NekoLockedActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
+ android:showOnLockScreen="true" />
+
+ <!-- Used to enable easter egg -->
+ <activity android:name=".neko.NekoActivationActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@android:style/Theme.NoDisplay"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.android.internal.category.PLATLOGO" />
+ </intent-filter>
+ </activity>
+
+ <!-- The quick settings tile, disabled by default -->
+ <service
+ android:name=".neko.NekoTile"
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
+ android:icon="@drawable/stat_icon"
+ android:enabled="false"
+ android:label="@string/default_tile_name">
+ <intent-filter>
+ <action android:name="android.service.quicksettings.action.QS_TILE" />
+ </intent-filter>
+ </service>
+
+ <service android:name=".neko.NekoControlsService"
+ android:permission="android.permission.BIND_CONTROLS"
+ android:label="@string/r_egg_name"
+ android:icon="@drawable/ic_fullcat_icon"
+ android:enabled="false"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.service.controls.ControlsProviderService" />
+ </intent-filter>
+ </service>
+
+ <!-- FileProvider for sending pictures -->
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="com.android.egg.fileprovider"
+ android:grantUriPermissions="true"
+ android:exported="false">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/filepaths" />
+ </provider>
</application>
</manifest>
diff --git a/packages/EasterEgg/build.gradle b/packages/EasterEgg/build.gradle
new file mode 100644
index 0000000..20b4698
--- /dev/null
+++ b/packages/EasterEgg/build.gradle
@@ -0,0 +1,82 @@
+buildscript {
+ ext.kotlin_version = '1.3.71'
+
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:4.0.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+final String ANDROID_ROOT = "${rootDir}/../../../.."
+
+android {
+ compileSdkVersion COMPILE_SDK
+ buildToolsVersion BUILD_TOOLS_VERSION
+
+ defaultConfig {
+ applicationId "com.android.egg"
+ minSdkVersion 28
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ sourceSets {
+ main {
+ res.srcDirs = ['res']
+ java.srcDirs = ['src']
+ manifest.srcFile 'AndroidManifest.xml'
+ }
+ }
+
+ signingConfigs {
+ debug.storeFile file("${ANDROID_ROOT}/vendor/google/certs/devkeys/platform.keystore")
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.core:core-ktx:1.2.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
+ implementation "androidx.recyclerview:recyclerview:${ANDROID_X_VERSION}"
+ implementation "androidx.dynamicanimation:dynamicanimation:${ANDROID_X_VERSION}"
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ androidTestImplementation "androidx.annotation:annotation:${ANDROID_X_VERSION}"
+}
+
diff --git a/packages/EasterEgg/gradle.properties b/packages/EasterEgg/gradle.properties
new file mode 100644
index 0000000..e8e6450
--- /dev/null
+++ b/packages/EasterEgg/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+android.enableJetifier=true
+kotlin.code.style=official
+
+ANDROID_X_VERSION=1+
+COMPILE_SDK=android-30
+BUILD_TOOLS_VERSION=28.0.3
diff --git a/packages/EasterEgg/res/drawable/android_11_dial.xml b/packages/EasterEgg/res/drawable/android_11_dial.xml
new file mode 100644
index 0000000..73fd37f
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android_11_dial.xml
@@ -0,0 +1,63 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:pathData="M77.773,51.064h-1.583c-0.217,0 -0.393,-0.176 -0.393,-0.393v-1.46c0,-0.217 0.176,-0.393 0.393,-0.393h3.466c0.217,0 0.393,0.176 0.393,0.393v9.921c0,0.217 -0.176,0.393 -0.393,0.393h-1.49c-0.217,0 -0.393,-0.176 -0.393,-0.393V51.064z"
+ android:fillColor="#F86734"/>
+ <path
+ android:pathData="M83.598,51.064h-1.583c-0.217,0 -0.393,-0.176 -0.393,-0.393v-1.46c0,-0.217 0.176,-0.393 0.393,-0.393h3.466c0.217,0 0.393,0.176 0.393,0.393v9.921c0,0.217 -0.176,0.393 -0.393,0.393h-1.49c-0.217,0 -0.393,-0.176 -0.393,-0.393V51.064z"
+ android:fillColor="#F86734"/>
+ <path
+ android:pathData="M70.044,75.974m-0.644,0a0.644,0.644 0,1 1,1.288 0a0.644,0.644 0,1 1,-1.288 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M56.896,80.985m-0.718,0a0.718,0.718 0,1 1,1.436 0a0.718,0.718 0,1 1,-1.436 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M43.408,78.881m-0.795,0a0.795,0.795 0,1 1,1.59 0a0.795,0.795 0,1 1,-1.59 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M32.419,70.115m-0.874,0a0.874,0.874 0,1 1,1.748 0a0.874,0.874 0,1 1,-1.748 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M27.306,56.992m-0.954,0a0.954,0.954 0,1 1,1.908 0a0.954,0.954 0,1 1,-1.908 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M29.313,43.489m-1.036,0a1.036,1.036 0,1 1,2.072 0a1.036,1.036 0,1 1,-2.072 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M37.988,32.445m-1.118,0a1.118,1.118 0,1 1,2.236 0a1.118,1.118 0,1 1,-2.236 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M51.137,27.064m-1.201,0a1.201,1.201 0,1 1,2.402 0a1.201,1.201 0,1 1,-2.402 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M64.553,28.868m-1.284,0a1.284,1.284 0,1 1,2.568 0a1.284,1.284 0,1 1,-2.568 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M75.522,37.652m-1.368,0a1.368,1.368 0,1 1,2.736 0a1.368,1.368 0,1 1,-2.736 0"
+ android:fillColor="#d7effe"/>
+ <path
+ android:pathData="M87.942,115.052l-47.557,-47.557l26.869,-26.87l47.557,47.558z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:startY="56.087"
+ android:startX="55.8464"
+ android:endY="100.0297"
+ android:endX="99.7891"
+ android:type="linear">
+ <item android:offset="0" android:color="#3F000000"/>
+ <item android:offset="1" android:color="#00000000"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:pathData="M53.928,54.17m-18.999,0a18.999,18.999 0,1 1,37.998 0a18.999,18.999 0,1 1,-37.998 0"
+ android:fillColor="#3ddc84"/>
+ <path
+ android:pathData="M66.353,54.17m-3.185,0a3.185,3.185 0,1 1,6.37 0a3.185,3.185 0,1 1,-6.37 0"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/back.xml b/packages/EasterEgg/res/drawable/back.xml
new file mode 100644
index 0000000..b55d65c
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/back.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="back" android:fillColor="#FF000000" android:pathData="M37.1,22c-1.1,0 -1.9,0.8 -1.9,1.9v5.6c0,1.1 0.8,1.9 1.9,1.9H39v-1.9v-5.6V22H37.1z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/belly.xml b/packages/EasterEgg/res/drawable/belly.xml
new file mode 100644
index 0000000..8b0e9af
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/belly.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="belly" android:fillColor="#FF000000" android:pathData="M20.5,25c-3.6,0 -6.5,2.9 -6.5,6.5V38h13v-6.5C27,27.9 24.1,25 20.5,25z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/body.xml b/packages/EasterEgg/res/drawable/body.xml
new file mode 100644
index 0000000..8608720
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/body.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="body" android:fillColor="#FF000000" android:pathData="M9,20h30v18h-30z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/bowtie.xml b/packages/EasterEgg/res/drawable/bowtie.xml
new file mode 100644
index 0000000..33fa921
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/bowtie.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="bowtie" android:fillColor="#FF000000" android:pathData="M29,16.8l-10,5l0,-5l10,5z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/cap.xml b/packages/EasterEgg/res/drawable/cap.xml
new file mode 100644
index 0000000..d8b4cc5
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/cap.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="cap" android:fillColor="#FF000000" android:pathData="M27.2,3.8c-1,-0.2 -2.1,-0.3 -3.2,-0.3s-2.1,0.1 -3.2,0.3c0.2,1.3 1.5,2.2 3.2,2.2C25.6,6.1 26.9,5.1 27.2,3.8z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/collar.xml b/packages/EasterEgg/res/drawable/collar.xml
new file mode 100644
index 0000000..5e4d0fd
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/collar.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="collar" android:fillColor="#FF000000" android:pathData="M9,18.4h30v1.7h-30z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/face_spot.xml b/packages/EasterEgg/res/drawable/face_spot.xml
new file mode 100644
index 0000000..a89fb4f
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/face_spot.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="face_spot" android:fillColor="#FF000000" android:pathData="M19.5,15.2a4.5,3.2 0,1 0,9 0a4.5,3.2 0,1 0,-9 0z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/food_bits.xml b/packages/EasterEgg/res/drawable/food_bits.xml
new file mode 100644
index 0000000..1b2bb6f
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/food_bits.xml
@@ -0,0 +1,33 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M19.1,34l-3.5,1.3c-1,0.4,-2.2,-0.1,-2.6,-1.1l-1.2,-3c-0.4,-1,0.1,-2.2,1.1,-2.6l3.5,-1.3c1,-0.4,2.2,0.1,2.6,1.1l1.2,3 C20.6,32.4,20.1,33.6,19.1,34z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M25.2,28.1L22.9,28c-0.8,0,-1.5,-0.7,-1.4,-1.6l0.1,-2c0,-0.8,0.7,-1.5,1.6,-1.4l2.4,0.1c0.8,0,1.5,0.7,1.4,1.6l-0.1,2 C26.8,27.5,26.1,28.1,25.2,28.1z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18.7,23.1L16.5,23c-0.5,0,-0.9,-0.4,-0.8,-0.9l0.1,-2.2c0,-0.5,0.4,-0.9,0.9,-0.8l2.2,0.1c0.5,0,0.9,0.4,0.8,0.9 l-0.1,2.2C19.6,22.8,19.2,23.1,18.7,23.1z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M32.2,35.3l-3.6,-1.8c-1,-0.5,-1.4,-1.7,-0.9,-2.7l1.6,-3.1c0.5,-1,1.7,-1.4,2.7,-0.9l3.6,1.8c1,0.5,1.4,1.7,0.9,2.7 l-1.6,3.1C34.4,35.4,33.2,35.7,32.2,35.3z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/food_chicken.xml b/packages/EasterEgg/res/drawable/food_chicken.xml
new file mode 100644
index 0000000..95b2fb5
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/food_chicken.xml
@@ -0,0 +1,39 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M9,12v14h10V11H9z M11.7,16.3c-0.7,0,-1.3,-0.6,-1.3,-1.3s0.6,-1.3,1.3,-1.3S13,14.3,13,15S12.4,16.3,11.7,16.3z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M5.7,20.1l1.6,-3.0l-1.6,-3.0l4.4,3.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M19.0,6.0l-2.3,2.3l-2.7,-2.6l-2.7,2.6l-2.3,-2.3l0.0,4.0l10.0,0.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M9,25c0,8.3,6.7,15,15,15s15,-6.7,15,-15H9z M29.9,31.5h-11v-1h12L29.9,31.5z M31.9,29.5h-13v-1h14L31.9,29.5z M33.9,27.5 h-15v-1h16L33.9,27.5z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M27.0,38.6h2.0v6.0h-2.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17.4,44.6l-2.1999998,0.0l4.4000006,-6.0l2.1999989,0.0z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/food_cookie.xml b/packages/EasterEgg/res/drawable/food_cookie.xml
new file mode 100644
index 0000000..74dd134
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/food_cookie.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <group>
+ <path
+ android:fillColor="#55FFFFFF"
+ android:fillType="evenOdd"
+ android:pathData="M5.71 18.29A8.99 8.99 0 0 0 22 13c0-3-1.46-5.65-3.71-7.29A8.99 8.99 0 0 0 2 11c0 3 1.46 5.65 3.71 7.29z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:fillType="evenOdd"
+ android:pathData="M7.25 19.18A8.5 8.5 0 0 0 19.19 7.24 9 9 0 0 1 7.24 19.19z"/>
+ <path
+ android:fillColor="#55FFFFFF"
+ android:pathData="M10.5 3a0.5 0.5 0 1 1 1 0v2.05a0.5 0.5 0 1 1-1 0V3zm3.1 0.42a0.5 0.5 0 0 1 0.93 0.39l-0.8 1.88A0.5 0.5 0 1 1 12.8 5.3l0.8-1.88zm2.7 1.57a0.5 0.5 0 1 1 0.71 0.7l-1.45 1.46a0.5 0.5 0 0 1-0.7-0.71l1.44-1.45zm1.9 2.5a0.5 0.5 0 0 1 0.38 0.92l-1.9 0.77a0.5 0.5 0 0 1-0.37-0.93l1.9-0.77zM19 10.5a0.5 0.5 0 1 1 0 1h-2.05a0.5 0.5 0 0 1 0-1H19zm-0.42 3.1a0.5 0.5 0 0 1-0.39 0.93l-1.88-0.8a0.5 0.5 0 1 1 0.39-0.92l1.88 0.8zm-1.57 2.7a0.5 0.5 0 1 1-0.7 0.71l-1.46-1.45a0.5 0.5 0 0 1 0.71-0.7l1.45 1.44zm-2.5 1.9a0.5 0.5 0 1 1-0.92 0.38l-0.77-1.9a0.5 0.5 0 0 1 0.93-0.37l0.77 1.9zM11.5 19a0.5 0.5 0 1 1-1 0v-2.05a0.5 0.5 0 0 1 1 0V19zm-3.1-0.42a0.5 0.5 0 0 1-0.93-0.39l0.8-1.88A0.5 0.5 0 0 1 9.2 16.7l-0.8 1.88zm-2.7-1.57a0.5 0.5 0 1 1-0.71-0.7l1.45-1.46a0.5 0.5 0 0 1 0.7 0.71L5.7 17.01zm-1.9-2.48a0.5 0.5 0 0 1-0.38-0.92l1.88-0.8a0.5 0.5 0 0 1 0.4 0.92l-1.9 0.8zM3 11.5a0.5 0.5 0 1 1 0-1h2.05a0.5 0.5 0 1 1 0 1H3zm0.42-3.1A0.5 0.5 0 0 1 3.8 7.46l1.88 0.8A0.5 0.5 0 1 1 5.3 9.2L3.42 8.4zm1.57-2.7a0.5 0.5 0 1 1 0.7-0.71l1.46 1.45a0.5 0.5 0 0 1-0.71 0.7L4.99 5.7zm2.5-1.9A0.5 0.5 0 0 1 8.4 3.41l0.77 1.9a0.5 0.5 0 0 1-0.93 0.37L7.48 3.8z"/>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/food_dish.xml b/packages/EasterEgg/res/drawable/food_dish.xml
new file mode 100644
index 0000000..3fff6a9
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/food_dish.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M24,13.8C11.3,13.8,1,18.3,1,24c0,5.7,10.3,10.2,23,10.2S47,29.7,47,24C47,18.3,36.7,13.8,24,13.8z M33.7,26.6 c1.1,-0.6,1.8,-1.3,1.8,-2c0,-2.1,-5.2,-3.8,-11.7,-3.8s-11.7,1.7,-11.7,3.8c0,0.6,0.4,1.2,1.2,1.7c-1.7,-0.8,-2.8,-1.7,-2.8,-2.8 c0,-2.5,6,-4.5,13.4,-4.5s13.4,2,13.4,4.5C37.4,24.7,36,25.8,33.7,26.6z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/food_donut.xml b/packages/EasterEgg/res/drawable/food_donut.xml
new file mode 100644
index 0000000..eaf831e
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/food_donut.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M24,4.5c-10.5,0,-19,8.5,-19,19s8.5,19,19,19s19,-8.5,19,-19S34.5,4.5,24,4.5z M35.2,15.5l1.6,-1.1 c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1c0.2,0.3,0.1,0.6,-0.1,0.8l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1 C34.9,16.1,35,15.7,35.2,15.5z M32.7,10.7c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6l-0.2,2c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0 c-0.3,0,-0.5,-0.3,-0.5,-0.6L32.7,10.7z M31.7,15.1l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1c0,0.2,-0.1,0.5,-0.4,0.5l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1C31.3,15.4,31.5,15.2,31.7,15.1z M28.8,10.6l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 c0.2,0.3,0.1,0.6,-0.1,0.8l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1C28.4,11.1,28.5,10.8,28.8,10.6z M25.8,6 c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6l-0.2,2c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0c-0.3,0,-0.5,-0.3,-0.5,-0.6L25.8,6z M20.7,6.5l1.9,-0.7c0.3,-0.1,0.6,0,0.7,0.3l0,0.1c0.1,0.3,0,0.6,-0.3,0.7l-1.9,0.7c-0.3,0.1,-0.6,0,-0.7,-0.3l0,-0.1 C20.3,6.9,20.4,6.6,20.7,6.5z M19.9,10.9l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1c0,0.2,-0.1,0.5,-0.4,0.5l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1C19.5,11.1,19.7,10.9,19.9,10.9z M16,10.9L16,10.9c0.2,-0.3,0.4,-0.4,0.6,-0.3l1.3,0.7 c0.2,0.1,0.3,0.4,0.2,0.6L18,12c-0.1,0.2,-0.4,0.3,-0.6,0.2l-1.3,-0.7C15.9,11.4,15.8,11.1,16,10.9z M15.8,18.5c0.2,0,0.4,0.1,0.5,0.4 l0,0.1c0,0.2,-0.1,0.4,-0.4,0.5l-1.5,0.2c-0.2,0,-0.4,-0.1,-0.5,-0.4l0,-0.1c0,-0.2,0.1,-0.4,0.4,-0.5L15.8,18.5z M14,21.8l-1.6,1.1 c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 C14.3,21.3,14.3,21.6,14,21.8z M12.4,12L12.4,12c0.3,-0.2,0.5,-0.2,0.7,-0.1l1,1.1c0.2,0.2,0.2,0.4,0,0.6L14,13.7 c-0.2,0.2,-0.4,0.2,-0.6,0l-1,-1.1C12.2,12.4,12.2,12.1,12.4,12z M8.3,24.5c0,0.3,-0.3,0.5,-0.6,0.5l-0.1,0c-0.3,0,-0.5,-0.3,-0.5,-0.6 l0.2,-2c0,-0.3,0.3,-0.5,0.6,-0.5l0.1,0c0.3,0,0.5,0.3,0.5,0.6L8.3,24.5z M8.5,16.2v-0.1c0,-0.3,0.2,-0.6,0.6,-0.6h2 c0.3,0,0.6,0.2,0.6,0.6v0.1c0,0.3,-0.2,0.6,-0.6,0.6H9C8.7,16.7,8.5,16.5,8.5,16.2z M10.3,20.7c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1 c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1c0.2,0.3,0.1,0.6,-0.1,0.8L10.3,20.7z M11.3,28.3l0,-0.1 c-0.1,-0.3,0,-0.6,0.3,-0.7l1.9,-0.7c0.3,-0.1,0.6,0,0.7,0.3l0,0.1c0.1,0.3,0,0.6,-0.3,0.7L12,28.6C11.7,28.7,11.4,28.6,11.3,28.3z M14.4,33c0,0.2,-0.2,0.4,-0.4,0.4h-1.5c-0.2,0,-0.4,-0.2,-0.4,-0.4v-0.1c0,-0.2,0.2,-0.4,0.4,-0.4H14c0.2,0,0.4,0.2,0.4,0.4V33z M17.9,35.2 l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1l-0.1,-0.1c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1 C18.2,34.7,18.2,35.1,17.9,35.2z M20.7,33.8l-0.1,0.1c-0.1,0.3,-0.5,0.4,-0.8,0.2l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1 c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1C20.7,33.2,20.8,33.5,20.7,33.8z M17.5,23.5c0,-3.6,2.9,-6.5,6.5,-6.5s6.5,2.9,6.5,6.5 c0,3.6,-2.9,6.5,-6.5,6.5S17.5,27.1,17.5,23.5z M27.4,35.7l-1.9,0.7c-0.3,0.1,-0.6,0,-0.7,-0.3l0,-0.1c-0.1,-0.3,0,-0.6,0.3,-0.7l1.9,-0.7 c0.3,-0.1,0.6,0,0.7,0.3l0,0.1C27.9,35.3,27.7,35.6,27.4,35.7z M29.7,32.7l-1.4,0.5c-0.2,0.1,-0.5,0,-0.5,-0.3l0,-0.1 c-0.1,-0.2,0,-0.5,0.3,-0.5l1.4,-0.5c0.2,-0.1,0.5,0,0.5,0.3l0,0.1C30,32.3,29.9,32.6,29.7,32.7z M32.8,35.5l-0.1,0.1 c-0.1,0.3,-0.5,0.4,-0.8,0.2l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1C32.8,34.9,32.9,35.2,32.8,35.5z M33.7,30.9c0,0.2,-0.2,0.4,-0.5,0.4l-0.1,0c-0.2,0,-0.4,-0.2,-0.4,-0.5l0.1,-1.5c0,-0.2,0.2,-0.4,0.5,-0.4l0.1,0c0.2,0,0.4,0.2,0.4,0.5 L33.7,30.9z M34.5,26.5l-1.3,0.9c-0.2,0.1,-0.5,0.1,-0.6,-0.1l-0.1,-0.1c-0.1,-0.2,-0.1,-0.5,0.1,-0.6l1.3,-0.9c0.2,-0.1,0.5,-0.1,0.6,0.1 l0.1,0.1C34.8,26.1,34.7,26.3,34.5,26.5z M35.6,20.6l-1.7,-1c-0.3,-0.1,-0.4,-0.5,-0.2,-0.8l0.1,-0.1c0.1,-0.3,0.5,-0.4,0.8,-0.2l1.7,1 c0.3,0.1,0.4,0.5,0.2,0.8l-0.1,0.1C36.2,20.6,35.8,20.7,35.6,20.6z M38.6,27.1l-1.6,1.1c-0.3,0.2,-0.6,0.1,-0.8,-0.1L36.1,28 c-0.2,-0.3,-0.1,-0.6,0.1,-0.8l1.6,-1.1c0.3,-0.2,0.6,-0.1,0.8,0.1l0.1,0.1C38.9,26.6,38.8,27,38.6,27.1z M39,19.4l-1.5,0.2 c-0.2,0,-0.5,-0.1,-0.5,-0.4l0,-0.1c0,-0.2,0.1,-0.5,0.4,-0.5l1.5,-0.2c0.2,0,0.5,0.1,0.5,0.4l0,0.1C39.4,19.1,39.2,19.3,39,19.4z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/food_sysuituna.xml b/packages/EasterEgg/res/drawable/food_sysuituna.xml
new file mode 100644
index 0000000..28cf4a2
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/food_sysuituna.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M46,18.4l-5.8,4.6c-3.9,-3.2,-8.9,-5.6,-14.6,-6.3l1.2,-6l-7.3,5.9C12.5,17.2,6.4,20,2,24.3l7.2,1.4L2,27 c4.3,4.2,10.4,7.1,17.3,7.6l3.1,2.5L22,34.8c7.1,0,13.5,-2.5,18.2,-6.5l5.8,4.6l-1.4,-7.2L46,18.4z M14.3,24.8l-0.6,0.6l-1.1,-1.1 l-1.1,1.1l-0.6,-0.6l1.1,-1.1l-1.1,-1.1l0.6,-0.6l1.1,1.1l1.1,-1.1l0.6,0.6l-1.1,1.1L14.3,24.8z M18.8,29.1c0.7,-0.8,1.1,-2.2,1.1,-3.8 c0,-1.6,-0.4,-3,-1.1,-3.8c1.1,0.5,1.9,2,1.9,3.8S19.9,28.5,18.8,29.1z M20.7,29.1c0.7,-0.8,1.1,-2.2,1.1,-3.8c0,-1.6,-0.4,-3,-1.1,-3.8 c1.1,0.5,1.9,2,1.9,3.8S21.8,28.5,20.7,29.1z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/foot1.xml b/packages/EasterEgg/res/drawable/foot1.xml
new file mode 100644
index 0000000..0d90859
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/foot1.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="foot1" android:fillColor="#FF000000" android:pathData="M11.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/foot2.xml b/packages/EasterEgg/res/drawable/foot2.xml
new file mode 100644
index 0000000..364ba0c
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/foot2.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="foot2" android:fillColor="#FF000000" android:pathData="M18.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/foot3.xml b/packages/EasterEgg/res/drawable/foot3.xml
new file mode 100644
index 0000000..e3a512a
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/foot3.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="foot3" android:fillColor="#FF000000" android:pathData="M29.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/foot4.xml b/packages/EasterEgg/res/drawable/foot4.xml
new file mode 100644
index 0000000..66b78fa
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/foot4.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="foot4" android:fillColor="#FF000000" android:pathData="M36.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/head.xml b/packages/EasterEgg/res/drawable/head.xml
new file mode 100644
index 0000000..df600a8
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/head.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="head" android:fillColor="#FF000000" android:pathData="M9,18.5c0,-8.3 6.8,-15 15,-15s15,6.7 15,15H9z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_bowl.xml b/packages/EasterEgg/res/drawable/ic_bowl.xml
new file mode 100644
index 0000000..d55565d9
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_bowl.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M3,19L21,19"
+ android:strokeWidth="2"
+ android:strokeColor="#FF8000"/>
+ <path
+ android:pathData="M7,12L4.5,19H19.5L17,12H7Z"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2"
+ android:strokeColor="#FF8000"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M7.5257,18.8419L9.5257,12.8419"
+ android:strokeColor="#FF8000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_close.xml b/packages/EasterEgg/res/drawable/ic_close.xml
new file mode 100644
index 0000000..60ea36b
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_close.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_foodbowl_filled.xml b/packages/EasterEgg/res/drawable/ic_foodbowl_filled.xml
new file mode 100644
index 0000000..54961af
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_foodbowl_filled.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M3,19L21,19"
+ android:strokeWidth="2"
+ android:strokeColor="#FF8000"/>
+ <path
+ android:pathData="M9,9m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#FF8000"/>
+ <path
+ android:pathData="M12,9m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#FF8000"/>
+ <path
+ android:pathData="M15,9m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#FF8000"/>
+ <path
+ android:pathData="M13.5,7m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#FF8000"/>
+ <path
+ android:pathData="M10.5,7m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#FF8000"/>
+ <path
+ android:pathData="M6.0583,11.6637C6.2004,11.2657 6.5774,11 7,11H17C17.4226,11 17.7996,11.2657 17.9418,11.6637L19.8476,17H4.1524L6.0583,11.6637ZM7.5,12L6,16H7L8.5,12H7.5Z"
+ android:fillColor="#FF8000"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_fullcat_icon.xml b/packages/EasterEgg/res/drawable/ic_fullcat_icon.xml
new file mode 100644
index 0000000..5dca3d1
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_fullcat_icon.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+ <path
+ android:pathData="M15.38,1.02l5.12,5.32l-6.32,2.72l1.2,-8.04z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M32.63,1.02l-5.13,5.32l6.32,2.72l-1.19,-8.04z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M33.82,9.06l-4.77,-1.82l3.58,-6.22l1.19,8.04z"
+ android:fillColor="#666"/>
+ <path
+ android:pathData="M15.38,1.02l3.57,6.22l-4.77,1.82l1.2,-8.04z"
+ android:fillColor="#666"/>
+ <path
+ android:pathData="M9,18.5a15,15 0,0 1,30 0Z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M19.5,15.25a4.5,3.25 0,1 0,9 0a4.5,3.25 0,1 0,-9 0z"
+ android:fillColor="#fff"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.5,11c0,1.73 -3,1.73 -3,0S20.5,9.35 20.5,11Z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M30.5,11c0,1.73 -3,1.73 -3,0S30.5,9.35 30.5,11Z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M25.15,13c0,1.28 -2.3,1.28 -2.3,0S25.15,11.73 25.15,13Z"/>
+ <path
+ android:pathData="M29,14.29a2.78,2.78 0,0 1,-2.33 1.41A2.75,2.75 0,0 1,24 13"
+ android:strokeWidth="1.25"
+ android:fillColor="#00000000"
+ android:strokeColor="#000"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M24,13a2.66,2.66 0,0 1,-2.67 2.69A2.53,2.53 0,0 1,19 14.29"
+ android:strokeWidth="1.25"
+ android:fillColor="#00000000"
+ android:strokeColor="#000"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M9,20h30v18h-30z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M11.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="M9,37h5v6h-5z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M29.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="M27,37h5v6h-5z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M36.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="M34,37h5v6h-5z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M18.5,43m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="M16,37h5v6h-5z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M35,35.5h5.9a3.8,3.8 0,0 0,3.8 -3.8V25.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#808080"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M40,38l0,-5l-1,0l0,5l1,0z"
+ android:fillColor="#666"/>
+ <path
+ android:pathData="M20.5,25A6.47,6.47 0,0 0,14 31.5V38H27V31.5A6.47,6.47 0,0 0,20.5 25Z"
+ android:fillColor="#fff"/>
+ <path
+ android:pathData="M16,38h5v1h-5z"
+ android:fillColor="#666"/>
+ <path
+ android:pathData="M9,18.5h30v1.5h-30z"
+ android:fillColor="#3ddc84"/>
+ <path
+ android:pathData="M29,16.75l-10,5l0,-5l10,5l0,-5z"
+ android:fillColor="#3ddc84"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_share.xml b/packages/EasterEgg/res/drawable/ic_share.xml
new file mode 100644
index 0000000..8cebc7e
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_share.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M18.0,16.08c-0.76,0.0 -1.4,0.3 -1.9,0.77L8.91,12.7c0.05,-0.2 0.09,-0.4 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.5,0.5 1.2,0.81 2.0,0.81 1.66,0.0 3.0,-1.34 3.0,-3.0s-1.34,-3.0 -3.0,-3.0 -3.0,1.34 -3.0,3.0c0.0,0.2 0.0,0.4 0.0,0.7L8.04,9.81C7.5,9.31 6.79,9.0 6.0,9.0c-1.66,0.0 -3.0,1.34 -3.0,3.0s1.34,3.0 3.0,3.0c0.79,0.0 1.5,-0.31 2.04,-0.81l7.12,4.16c0.0,0.21 0.0,0.43 0.0,0.65 0.0,1.61 1.31,2.92 2.92,2.92 1.61,0.0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_toy_ball.xml b/packages/EasterEgg/res/drawable/ic_toy_ball.xml
new file mode 100644
index 0000000..411084b
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_toy_ball.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF4080"/>
+ <path
+ android:pathData="M12,9C12.5523,9 13,8.5523 13,8C13,7.4477 12.5523,7 12,7V9ZM7,12C7,12.5523 7.4477,13 8,13C8.5523,13 9,12.5523 9,12H7ZM12,7C10.6748,7 9.4332,7.6526 8.5429,8.5429C7.6526,9.4332 7,10.6748 7,12H9C9,11.3252 9.3475,10.5668 9.9571,9.9571C10.5668,9.3475 11.3252,9 12,9V7Z"
+ android:fillColor="#FF4080"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_toy_fish.xml b/packages/EasterEgg/res/drawable/ic_toy_fish.xml
new file mode 100644
index 0000000..bb01e9f
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_toy_fish.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M14.8492,8.9498C15.7483,9.8489 16.132,11.201 15.9095,12.7581C15.6871,14.3155 14.8589,16.0111 13.435,17.435C12.0111,18.8589 10.3155,19.6871 8.7581,19.9096C7.201,20.132 5.8488,19.7484 4.9497,18.8493C4.0506,17.9501 3.667,16.598 3.8894,15.0409C4.1119,13.4835 4.9401,11.7879 6.364,10.364C7.7879,8.9401 9.4835,8.1119 11.0409,7.8895C12.598,7.667 13.9501,8.0506 14.8492,8.9498Z"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF4080"/>
+ <path
+ android:pathData="M7,15m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#FF4080"/>
+ <path
+ android:pathData="M14.5,8L17.5,3C17.5,3 18,4.5 19,6C20,7.5 21.5,8.5 21.5,8.5L16.5,10"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF4080"/>
+ <path
+ android:pathData="M8.5,4.5L6.5,10L10,7.5L8.5,4.5Z"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2"
+ android:fillColor="#FF4080"
+ android:strokeColor="#FF4080"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_toy_laser.xml b/packages/EasterEgg/res/drawable/ic_toy_laser.xml
new file mode 100644
index 0000000..8fe84ff
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_toy_laser.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M12.866,3.5C12.6874,3.1906 12.3573,3 12,3C11.6427,3 11.3126,3.1906 11.134,3.5L2.4737,18.5C2.2951,18.8094 2.2951,19.1906 2.4737,19.5C2.6523,19.8094 2.9825,20 3.3398,20H20.6603C21.0175,20 21.3476,19.8094 21.5263,19.5C21.7049,19.1906 21.7049,18.8094 21.5263,18.5L12.866,3.5Z"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF4080"/>
+ <path
+ android:pathData="M8,13.5h11v1h-11z"
+ android:fillColor="#FF4080"/>
+ <path
+ android:pathData="M11.5,10h1v8h-1z"
+ android:fillColor="#FF4080"/>
+ <path
+ android:pathData="M8.86,11.4883l0.6283,-0.6283l5.6547,5.6547l-0.6283,0.6283z"
+ android:fillColor="#FF4080"/>
+ <path
+ android:pathData="M9.4883,17.143l-0.6283,-0.6283l5.6547,-5.6547l0.6283,0.6283z"
+ android:fillColor="#FF4080"/>
+ <path
+ android:pathData="M12,14m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"
+ android:fillColor="#FF4080"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_toy_mouse.xml b/packages/EasterEgg/res/drawable/ic_toy_mouse.xml
new file mode 100644
index 0000000..ba3dc33
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_toy_mouse.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M14.8492,8.9498C15.7483,9.8489 16.132,11.201 15.9095,12.7581C15.6871,14.3155 14.8589,16.0111 13.435,17.435C12.0111,18.8589 10.3155,19.6871 8.7581,19.9096C7.201,20.132 5.8488,19.7484 4.9497,18.8493C4.0506,17.9501 3.667,16.598 3.8894,15.0409C4.1119,13.4835 4.9401,11.7879 6.364,10.364C7.7879,8.9401 9.4835,8.1119 11.0409,7.8895C12.598,7.667 13.9501,8.0506 14.8492,8.9498Z"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF4080"/>
+ <path
+ android:pathData="M3.5,11.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF4080"/>
+ <path
+ android:pathData="M7.5,7.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF4080"/>
+ <path
+ android:pathData="M7,15m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#FF4080"/>
+ <path
+ android:pathData="M9,13m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#FF4080"/>
+ <path
+ android:pathData="M22,4C22,3.4477 21.5523,3 21,3C20.4477,3 20,3.4477 20,4L22,4ZM15,9C14.873,9.9919 14.8735,9.992 14.874,9.992C14.8742,9.9921 14.8747,9.9921 14.8751,9.9922C14.8759,9.9923 14.8768,9.9924 14.8778,9.9925C14.8798,9.9928 14.8821,9.993 14.8848,9.9934C14.8902,9.994 14.8971,9.9948 14.9054,9.9958C14.922,9.9976 14.9442,10 14.9718,10.0026C15.027,10.0079 15.1036,10.0143 15.1985,10.02C15.3881,10.0312 15.6534,10.0396 15.9697,10.0294C16.5957,10.0092 17.455,9.9156 18.3326,9.6062C19.2147,9.2951 20.1482,8.7534 20.8583,7.8203C21.5743,6.8795 22,5.6234 22,4L20,4C20,5.2607 19.6757,6.0717 19.2667,6.6091C18.8518,7.1543 18.2853,7.5021 17.6674,7.72C17.045,7.9395 16.4043,8.0144 15.9053,8.0304C15.6591,8.0384 15.4556,8.0317 15.3171,8.0235C15.248,8.0194 15.1957,8.0149 15.1629,8.0118C15.1466,8.0102 15.1352,8.009 15.129,8.0083C15.126,8.008 15.1242,8.0077 15.1239,8.0077C15.1237,8.0077 15.1239,8.0077 15.1244,8.0078C15.1247,8.0078 15.125,8.0078 15.1254,8.0079C15.1256,8.0079 15.126,8.008 15.1262,8.008C15.1266,8.008 15.127,8.0081 15,9Z"
+ android:fillColor="#FF4080"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_water.xml b/packages/EasterEgg/res/drawable/ic_water.xml
new file mode 100644
index 0000000..7d94b24
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_water.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M17.654,7.563L12,2L6.346,7.563C5.6036,8.2877 5.0136,9.1533 4.6108,10.1094C4.2079,11.0654 4.0002,12.0924 4,13.1299C4,15.2516 4.8429,17.2863 6.3432,18.7866C7.8434,20.2869 9.8783,21.1299 12,21.1299C14.1217,21.1299 16.1566,20.2869 17.6569,18.7866C19.1572,17.2863 20,15.2516 20,13.1299C20,12.0924 19.7925,11.0654 19.3896,10.1094C18.9867,9.1533 18.3966,8.2875 17.654,7.563V7.563ZM12,19C10.4265,19.0152 8.9113,18.4056 7.7865,17.3052C6.6617,16.2048 6.0192,14.7033 6,13.1299C5.9996,12.3577 6.1541,11.5933 6.4543,10.8818C6.7546,10.1704 7.1945,9.5262 7.748,8.9878L12,4.8061L16.252,8.9888C16.8056,9.5269 17.2456,10.171 17.5458,10.8823C17.8461,11.5936 18.0005,12.3578 18,13.1299C17.9807,14.7033 17.3383,16.2048 16.2135,17.3052C15.0887,18.4056 13.5735,19.0152 12,19Z"
+ android:fillColor="#0080FF"/>
+ <path
+ android:pathData="M16,12C15.7348,12 15.4804,12.1054 15.2929,12.293C15.1054,12.4805 15,12.7348 15,13C15,13.7956 14.6839,14.5585 14.1213,15.1211C13.5587,15.6837 12.7956,16 12,16C11.7348,16 11.4804,16.1054 11.2929,16.293C11.1054,16.4805 11,16.7348 11,17C11,17.2652 11.1054,17.5195 11.2929,17.707C11.4804,17.8946 11.7348,18 12,18C13.3256,17.9984 14.5964,17.471 15.5338,16.5337C16.4711,15.5964 16.9984,14.3256 17,13C17,12.7348 16.8946,12.4805 16.7071,12.293C16.5196,12.1054 16.2652,12 16,12Z"
+ android:fillColor="#0080FF"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_water_filled.xml b/packages/EasterEgg/res/drawable/ic_water_filled.xml
new file mode 100644
index 0000000..eed171d
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_water_filled.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M17.654,7.563L12,2L6.346,7.563C5.6036,8.2877 5.0136,9.1533 4.6108,10.1094C4.2079,11.0654 4.0002,12.0924 4,13.1299C4.0174,15.2343 4.87,17.2458 6.3703,18.7217C7.8705,20.1975 9.8956,21.017 12,21C14.1044,21.017 16.1295,20.1975 17.6297,18.7217C19.13,17.2458 19.9826,15.2343 20,13.1299C20,12.0924 19.7925,11.0654 19.3896,10.1094C18.9867,9.1533 18.3966,8.2875 17.654,7.563V7.563ZM12,18C11.7348,18 11.4804,17.8946 11.2929,17.707C11.1054,17.5195 11,17.2652 11,17C11,16.7348 11.1054,16.4805 11.2929,16.293C11.4804,16.1054 11.7348,16 12,16C12.7956,16 13.5587,15.6837 14.1213,15.1211C14.6839,14.5585 15,13.7956 15,13C15,12.7348 15.1054,12.4805 15.2929,12.293C15.4804,12.1054 15.7348,12 16,12C16.2652,12 16.5196,12.1054 16.7071,12.293C16.8946,12.4805 17,12.7348 17,13C16.9984,14.3256 16.4711,15.5964 15.5338,16.5337C14.5964,17.471 13.3256,17.9984 12,18Z"
+ android:fillColor="#0080FF"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/ic_waterbowl_filled.xml b/packages/EasterEgg/res/drawable/ic_waterbowl_filled.xml
new file mode 100644
index 0000000..28b1fa8
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/ic_waterbowl_filled.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M3,19L21,19"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"/>
+ <path
+ android:pathData="M6.0583,11.6637C6.2004,11.2657 6.5774,11 7,11H17C17.4226,11 17.7996,11.2657 17.9418,11.6637L19.8476,17H4.1524L6.0583,11.6637ZM7.5,12L6,16H7L8.5,12H7.5Z"
+ android:fillColor="#000000"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M13.4135,6.3907L12,5L10.5865,6.3907C10.4009,6.5719 10.2534,6.7883 10.1527,7.0273C10.052,7.2663 10.0001,7.5231 10,7.7825C10.0044,8.3086 10.2175,8.8115 10.5926,9.1804C10.9676,9.5494 11.4739,9.7543 12,9.75C12.5261,9.7543 13.0324,9.5494 13.4074,9.1804C13.7825,8.8115 13.9956,8.3086 14,7.7825C14,7.5231 13.9481,7.2664 13.8474,7.0273C13.7467,6.7883 13.5991,6.5719 13.4135,6.3907V6.3907ZM12,9C11.9337,9 11.8701,8.9736 11.8232,8.9268C11.7763,8.8799 11.75,8.8163 11.75,8.75C11.75,8.6837 11.7763,8.6201 11.8232,8.5732C11.8701,8.5264 11.9337,8.5 12,8.5C12.1989,8.5 12.3897,8.4209 12.5303,8.2803C12.671,8.1396 12.75,7.9489 12.75,7.75C12.75,7.6837 12.7763,7.6201 12.8232,7.5732C12.8701,7.5264 12.9337,7.5 13,7.5C13.0663,7.5 13.1299,7.5264 13.1768,7.5732C13.2237,7.6201 13.25,7.6837 13.25,7.75C13.2496,8.0814 13.1178,8.3991 12.8834,8.6334C12.6491,8.8678 12.3314,8.9996 12,9Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml
new file mode 100644
index 0000000..7f8d4fa
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/icon.xml
@@ -0,0 +1,19 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/icon_bg"/>
+ <foreground android:drawable="@drawable/android_11_dial"/>
+</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/icon_bg.xml b/packages/EasterEgg/res/drawable/icon_bg.xml
index 659f98b..31b2a7f 100644
--- a/packages/EasterEgg/res/drawable/icon_bg.xml
+++ b/packages/EasterEgg/res/drawable/icon_bg.xml
@@ -1,8 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2018 The Android Open Source Project
+Copyright (C) 2018 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,4 +14,5 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/q_clue_text" />
+ android:color="#073042" />
+
diff --git a/packages/EasterEgg/res/drawable/left_ear.xml b/packages/EasterEgg/res/drawable/left_ear.xml
new file mode 100644
index 0000000..2b98736
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/left_ear.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="left_ear" android:fillColor="#FF000000" android:pathData="M15.4,1l5.1000004,5.3l-6.3,2.8000002z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/left_ear_inside.xml b/packages/EasterEgg/res/drawable/left_ear_inside.xml
new file mode 100644
index 0000000..1d947ed
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/left_ear_inside.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="left_ear_inside" android:fillColor="#FF000000" android:pathData="M15.4,1l3.5,6.2l-4.7,1.9z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/left_eye.xml b/packages/EasterEgg/res/drawable/left_eye.xml
new file mode 100644
index 0000000..4dde1b6
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/left_eye.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="left_eye" android:fillColor="#FF000000" android:pathData="M20.5,11c0,1.7 -3,1.7 -3,0C17.5,9.3 20.5,9.3 20.5,11z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/leg1.xml b/packages/EasterEgg/res/drawable/leg1.xml
new file mode 100644
index 0000000..d72c746
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/leg1.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="leg1" android:fillColor="#FF000000" android:pathData="M9,37h5v6h-5z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/leg2.xml b/packages/EasterEgg/res/drawable/leg2.xml
new file mode 100644
index 0000000..a772a87
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/leg2.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="leg2" android:fillColor="#FF000000" android:pathData="M16,37h5v6h-5z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/leg2_shadow.xml b/packages/EasterEgg/res/drawable/leg2_shadow.xml
new file mode 100644
index 0000000..b01bd69
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/leg2_shadow.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="leg2_shadow" android:fillColor="#FF000000" android:pathData="M16,37h5v3h-5z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/leg3.xml b/packages/EasterEgg/res/drawable/leg3.xml
new file mode 100644
index 0000000..d471236
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/leg3.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="leg3" android:fillColor="#FF000000" android:pathData="M27,37h5v6h-5z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/leg4.xml b/packages/EasterEgg/res/drawable/leg4.xml
new file mode 100644
index 0000000..e5868eb
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/leg4.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="leg4" android:fillColor="#FF000000" android:pathData="M34,37h5v6h-5z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/mouth.xml b/packages/EasterEgg/res/drawable/mouth.xml
new file mode 100644
index 0000000..ddcf2e8
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/mouth.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="mouth"
+ android:strokeColor="#FF000000"
+ android:strokeWidth="1.2"
+ android:strokeLineCap="round"
+ android:pathData="M29,14.3c-0.4,0.8 -1.3,1.4 -2.3,1.4c-1.4,0 -2.7,-1.3 -2.7,-2.7
+ M24,13c0,1.5 -1.2,2.7 -2.7,2.7c-1,0 -1.9,-0.5 -2.3,-1.4"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/nose.xml b/packages/EasterEgg/res/drawable/nose.xml
new file mode 100644
index 0000000..d403cd1
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/nose.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="nose" android:fillColor="#FF000000" android:pathData="M25.2,13c0,1.3 -2.3,1.3 -2.3,0S25.2,11.7 25.2,13z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/octo_bg.xml b/packages/EasterEgg/res/drawable/octo_bg.xml
new file mode 100644
index 0000000..1e46cf4
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/octo_bg.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient android:angle="-90"
+ android:startColor="#FF205090"
+ android:endColor="#FF001040"
+ android:type="linear"
+ />
+</shape>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/right_ear.xml b/packages/EasterEgg/res/drawable/right_ear.xml
new file mode 100644
index 0000000..b9fb4d1
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/right_ear.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="right_ear" android:fillColor="#FF000000" android:pathData="M32.6,1l-5.0999985,5.3l6.299999,2.8000002z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/right_ear_inside.xml b/packages/EasterEgg/res/drawable/right_ear_inside.xml
new file mode 100644
index 0000000..86b6e34
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/right_ear_inside.xml
@@ -0,0 +1,23 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+
+ <path android:name="right_ear_inside" android:fillColor="#FF000000" android:pathData="M33.8,9.1l-4.7,-1.9l3.5,-6.2z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/right_eye.xml b/packages/EasterEgg/res/drawable/right_eye.xml
new file mode 100644
index 0000000..a1871a6
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/right_eye.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="right_eye" android:fillColor="#FF000000" android:pathData="M30.5,11c0,1.7 -3,1.7 -3,0C27.5,9.3 30.5,9.3 30.5,11z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/stat_icon.xml b/packages/EasterEgg/res/drawable/stat_icon.xml
new file mode 100644
index 0000000..608cb20
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/stat_icon.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,2C6.5,2 2,6.5 2,12c0,5.5 4.5,10 10,10s10,-4.5 10,-10C22,6.5 17.5,2 12,2zM5.5,11c0,-1.6 3,-1.6 3,0C8.5,12.7 5.5,12.7 5.5,11zM17.5,14.6c-0.6,1 -1.7,1.7 -2.9,1.7c-1.1,0 -2,-0.6 -2.6,-1.4c-0.6,0.9 -1.6,1.4 -2.7,1.4c-1.3,0 -2.3,-0.7 -2.9,-1.8c-0.2,-0.3 0,-0.7 0.3,-0.8c0.3,-0.2 0.7,0 0.8,0.3c0.3,0.7 1,1.1 1.8,1.1c0.9,0 1.6,-0.5 1.9,-1.3c-0.2,-0.2 -0.4,-0.4 -0.4,-0.7c0,-1.3 2.3,-1.3 2.3,0c0,0.3 -0.2,0.6 -0.4,0.7c0.3,0.8 1.1,1.3 1.9,1.3c0.8,0 1.5,-0.6 1.8,-1.1c0.2,-0.3 0.6,-0.4 0.9,-0.2C17.6,13.9 17.7,14.3 17.5,14.6zM15.5,11c0,-1.6 3,-1.6 3,0C18.5,12.7 15.5,12.7 15.5,11z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M5.2,1.0l4.1000004,4.2l-5.0,2.1000004z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18.8,1.0l-4.0999994,4.2l5.000001,2.1000004z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/tail.xml b/packages/EasterEgg/res/drawable/tail.xml
new file mode 100644
index 0000000..0cca23c
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/tail.xml
@@ -0,0 +1,26 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="tail"
+ android:strokeColor="#FF000000"
+ android:strokeWidth="5"
+ android:strokeLineCap="round"
+ android:pathData="M35,35.5h5.9c2.1,0 3.8,-1.7 3.8,-3.8v-6.2"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/tail_cap.xml b/packages/EasterEgg/res/drawable/tail_cap.xml
new file mode 100644
index 0000000..b82f6f9
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/tail_cap.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="tail_cap" android:fillColor="#FF000000" android:pathData="M42.2,25.5c0,-1.4 1.1,-2.5 2.5,-2.5s2.5,1.1 2.5,2.5H42.2z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/tail_shadow.xml b/packages/EasterEgg/res/drawable/tail_shadow.xml
new file mode 100644
index 0000000..bb1ff12
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/tail_shadow.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path android:name="tail_shadow" android:fillColor="#FF000000" android:pathData="M40,38l0,-5l-1,0l0,5z"/>
+</vector>
diff --git a/packages/EasterEgg/res/layout/activity_paint.xml b/packages/EasterEgg/res/layout/activity_paint.xml
index a4c17af..8e916b0 100644
--- a/packages/EasterEgg/res/layout/activity_paint.xml
+++ b/packages/EasterEgg/res/layout/activity_paint.xml
@@ -16,7 +16,7 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- xmlns:app="http://schemas.android.com/apk/res/com.android.egg"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#666"
@@ -45,4 +45,4 @@
/>
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/packages/EasterEgg/res/layout/cat_view.xml b/packages/EasterEgg/res/layout/cat_view.xml
new file mode 100644
index 0000000..85b494d
--- /dev/null
+++ b/packages/EasterEgg/res/layout/cat_view.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 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:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:gravity="center_horizontal"
+ android:clipToPadding="false">
+
+ <FrameLayout
+ android:layout_width="96dp"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="10dp"
+ android:layout_gravity="center"
+ android:scaleType="fitCenter" />
+
+ <LinearLayout
+ android:id="@+id/contextGroup"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="invisible"
+ android:layout_gravity="bottom">
+
+ <ImageView
+ android:id="@android:id/shareText"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:padding="8dp"
+ android:src="@drawable/ic_share"
+ android:scaleType="fitCenter"
+ android:background="#40000000"/>
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <ImageView
+ android:id="@android:id/closeButton"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:padding="4dp"
+ android:src="@drawable/ic_close"
+ android:scaleType="fitCenter"
+ android:background="#40000000"/>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:gravity="center"/>
+</LinearLayout>
+
diff --git a/packages/EasterEgg/res/layout/edit_text.xml b/packages/EasterEgg/res/layout/edit_text.xml
new file mode 100644
index 0000000..9f7ac802
--- /dev/null
+++ b/packages/EasterEgg/res/layout/edit_text.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 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.
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="20dp"
+ android:paddingEnd="20dp">
+
+ <EditText
+ android:id="@android:id/edit"
+ android:maxLines="1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/layout/food_layout.xml b/packages/EasterEgg/res/layout/food_layout.xml
new file mode 100644
index 0000000..d0ca0c8
--- /dev/null
+++ b/packages/EasterEgg/res/layout/food_layout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 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:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:paddingLeft="4dp" android:paddingRight="4dp"
+ android:paddingBottom="6dp" android:paddingTop="6dp">
+ <ImageView
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:id="@+id/icon"
+ android:tint="?android:attr/colorControlNormal"/>
+ <TextView android:layout_width="64dp" android:layout_height="wrap_content"
+ android:gravity="top|center_horizontal"
+ android:id="@+id/text" />
+</LinearLayout>
diff --git a/packages/EasterEgg/res/layout/neko_activity.xml b/packages/EasterEgg/res/layout/neko_activity.xml
new file mode 100644
index 0000000..c258137
--- /dev/null
+++ b/packages/EasterEgg/res/layout/neko_activity.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2016 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/holder"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/EasterEgg/res/values/cat_strings.xml b/packages/EasterEgg/res/values/cat_strings.xml
new file mode 100644
index 0000000..5214fc1
--- /dev/null
+++ b/packages/EasterEgg/res/values/cat_strings.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="notification_name" translatable="false">Android Neko</string>
+ <string name="notification_channel_name" translatable="false">New cats</string>
+ <string name="default_tile_name" translatable="false">\????</string>
+ <string name="notification_title" translatable="false">A cat is here.</string>
+ <string name="default_cat_name" translatable="false">Cat #%s</string>
+ <string name="directory_name" translatable="false">Cats</string>
+ <string name="confirm_delete" translatable="false">Forget %s?</string>
+ <string-array name="food_names" translatable="false">
+ <item>Empty dish</item>
+ <item>Bits</item>
+ <item>Fish</item>
+ <item>Chicken</item>
+ <item>Treat</item>
+ </string-array>
+ <array name="food_icons">
+ <item>@drawable/food_dish</item>
+ <item>@drawable/food_bits</item>
+ <item>@drawable/food_sysuituna</item>
+ <item>@drawable/food_chicken</item>
+ <item>@drawable/food_cookie</item>
+ </array>
+ <integer-array name="food_intervals">
+ <item>0</item>
+ <item>15</item>
+ <item>30</item>
+ <item>60</item>
+ <item>120</item>
+ </integer-array>
+ <integer-array name="food_new_cat_prob">
+ <item>0</item>
+ <item>5</item>
+ <item>35</item>
+ <item>65</item>
+ <item>90</item>
+ </integer-array>
+ <string-array name="cat_messages" translatable="false">
+ <item>😸</item>
+ <item>😹</item>
+ <item>😺</item>
+ <item>😻</item>
+ <item>😼</item>
+ <item>😽</item>
+ <item>😾</item>
+ <item>😿</item>
+ <item>🙀</item>
+ <item>💩</item>
+ <item>🐁</item>
+ </string-array>
+ <string-array name="rare_cat_messages" translatable="false">
+ <item>🍩</item>
+ <item>🍭</item>
+ <item>🍫</item>
+ <item>🍨</item>
+ <item>🔔</item>
+ <item>🐝</item>
+ <item>🍪</item>
+ <item>🥧</item>
+ </string-array>
+ <string name="control_toy_title" translatable="false">Toy</string>
+ <string name="control_toy_subtitle" translatable="false">Tap to use</string>
+ <string name="control_toy_status" translatable="false">Cat attracted!</string>
+ <string name="control_water_title" translatable="false">Water bubbler</string>
+ <string name="control_water_subtitle" translatable="false">Swipe to fill</string>
+ <string name="control_food_title" translatable="false">Food bowl</string>
+ <string name="control_food_subtitle" translatable="false">Tap to refill</string>
+ <string name="control_food_status_full" translatable="false">Full</string>
+ <string name="control_food_status_empty" translatable="false">Empty</string>
+</resources>
+
diff --git a/packages/EasterEgg/res/values/dimens.xml b/packages/EasterEgg/res/values/dimens.xml
new file mode 100644
index 0000000..e9dcebd
--- /dev/null
+++ b/packages/EasterEgg/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2016 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <dimen name="neko_display_size">64dp</dimen>
+</resources>
diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml
index b95ec6b..25f9421 100644
--- a/packages/EasterEgg/res/values/strings.xml
+++ b/packages/EasterEgg/res/values/strings.xml
@@ -14,11 +14,13 @@
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <string name="app_name" translatable="false">Android Q Easter Egg</string>
+ <string name="app_name" translatable="false">Android R Easter Egg</string>
<!-- name of the Q easter egg, a nonogram-style icon puzzle -->
<string name="q_egg_name" translatable="false">Icon Quiz</string>
<!-- name of the P easter egg, a humble paint program -->
<string name="p_egg_name" translatable="false">PAINT.APK</string>
+
+ <string name="r_egg_name" translatable="false">Cat Controls</string>
</resources>
diff --git a/packages/EasterEgg/res/xml/filepaths.xml b/packages/EasterEgg/res/xml/filepaths.xml
new file mode 100644
index 0000000..2130025
--- /dev/null
+++ b/packages/EasterEgg/res/xml/filepaths.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 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.
+-->
+<paths>
+ <external-path name="cats" path="Pictures/Cats" />
+</paths>
\ No newline at end of file
diff --git a/packages/EasterEgg/src/com/android/egg/neko/Cat.java b/packages/EasterEgg/src/com/android/egg/neko/Cat.java
new file mode 100644
index 0000000..cd59a73
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/Cat.java
@@ -0,0 +1,524 @@
+/*
+ * 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.egg.neko;
+
+import static com.android.egg.neko.NekoLand.CHAN_ID;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Person;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+
+import com.android.egg.R;
+import com.android.internal.logging.MetricsLogger;
+
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+/** It's a cat. */
+public class Cat extends Drawable {
+ public static final long[] PURR = {0, 40, 20, 40, 20, 40, 20, 40, 20, 40, 20, 40};
+
+ public static final boolean ALL_CATS_IN_ONE_CONVERSATION = true;
+
+ public static final String GLOBAL_SHORTCUT_ID = "com.android.egg.neko:allcats";
+ public static final String SHORTCUT_ID_PREFIX = "com.android.egg.neko:cat:";
+
+ private Random mNotSoRandom;
+ private Bitmap mBitmap;
+ private long mSeed;
+ private String mName;
+ private int mBodyColor;
+ private int mFootType;
+ private boolean mBowTie;
+ private String mFirstMessage;
+
+ private synchronized Random notSoRandom(long seed) {
+ if (mNotSoRandom == null) {
+ mNotSoRandom = new Random();
+ mNotSoRandom.setSeed(seed);
+ }
+ return mNotSoRandom;
+ }
+
+ public static final float frandrange(Random r, float a, float b) {
+ return (b - a) * r.nextFloat() + a;
+ }
+
+ public static final Object choose(Random r, Object... l) {
+ return l[r.nextInt(l.length)];
+ }
+
+ public static final int chooseP(Random r, int[] a) {
+ return chooseP(r, a, 1000);
+ }
+
+ public static final int chooseP(Random r, int[] a, int sum) {
+ int pct = r.nextInt(sum);
+ final int stop = a.length - 2;
+ int i = 0;
+ while (i < stop) {
+ pct -= a[i];
+ if (pct < 0) break;
+ i += 2;
+ }
+ return a[i + 1];
+ }
+
+ public static final int getColorIndex(int q, int[] a) {
+ for (int i = 1; i < a.length; i += 2) {
+ if (a[i] == q) {
+ return i / 2;
+ }
+ }
+ return -1;
+ }
+
+ public static final int[] P_BODY_COLORS = {
+ 180, 0xFF212121, // black
+ 180, 0xFFFFFFFF, // white
+ 140, 0xFF616161, // gray
+ 140, 0xFF795548, // brown
+ 100, 0xFF90A4AE, // steel
+ 100, 0xFFFFF9C4, // buff
+ 100, 0xFFFF8F00, // orange
+ 5, 0xFF29B6F6, // blue..?
+ 5, 0xFFFFCDD2, // pink!?
+ 5, 0xFFCE93D8, // purple?!?!?
+ 4, 0xFF43A047, // yeah, why not green
+ 1, 0, // ?!?!?!
+ };
+
+ public static final int[] P_COLLAR_COLORS = {
+ 250, 0xFFFFFFFF,
+ 250, 0xFF000000,
+ 250, 0xFFF44336,
+ 50, 0xFF1976D2,
+ 50, 0xFFFDD835,
+ 50, 0xFFFB8C00,
+ 50, 0xFFF48FB1,
+ 50, 0xFF4CAF50,
+ };
+
+ public static final int[] P_BELLY_COLORS = {
+ 750, 0,
+ 250, 0xFFFFFFFF,
+ };
+
+ public static final int[] P_DARK_SPOT_COLORS = {
+ 700, 0,
+ 250, 0xFF212121,
+ 50, 0xFF6D4C41,
+ };
+
+ public static final int[] P_LIGHT_SPOT_COLORS = {
+ 700, 0,
+ 300, 0xFFFFFFFF,
+ };
+
+ private CatParts D;
+
+ public static void tint(int color, Drawable... ds) {
+ for (Drawable d : ds) {
+ if (d != null) {
+ d.mutate().setTint(color);
+ }
+ }
+ }
+
+ public static boolean isDark(int color) {
+ final int r = (color & 0xFF0000) >> 16;
+ final int g = (color & 0x00FF00) >> 8;
+ final int b = color & 0x0000FF;
+ return (r + g + b) < 0x80;
+ }
+
+ public Cat(Context context, long seed) {
+ D = new CatParts(context);
+ mSeed = seed;
+
+ setName(context.getString(R.string.default_cat_name,
+ String.valueOf(mSeed % 1000)));
+
+ final Random nsr = notSoRandom(seed);
+
+ // body color
+ mBodyColor = chooseP(nsr, P_BODY_COLORS);
+ if (mBodyColor == 0) mBodyColor = Color.HSVToColor(new float[]{
+ nsr.nextFloat() * 360f, frandrange(nsr, 0.5f, 1f), frandrange(nsr, 0.5f, 1f)});
+
+ tint(mBodyColor, D.body, D.head, D.leg1, D.leg2, D.leg3, D.leg4, D.tail,
+ D.leftEar, D.rightEar, D.foot1, D.foot2, D.foot3, D.foot4, D.tailCap);
+ tint(0x20000000, D.leg2Shadow, D.tailShadow);
+ if (isDark(mBodyColor)) {
+ tint(0xFFFFFFFF, D.leftEye, D.rightEye, D.mouth, D.nose);
+ }
+ tint(isDark(mBodyColor) ? 0xFFEF9A9A : 0x20D50000, D.leftEarInside, D.rightEarInside);
+
+ tint(chooseP(nsr, P_BELLY_COLORS), D.belly);
+ tint(chooseP(nsr, P_BELLY_COLORS), D.back);
+ final int faceColor = chooseP(nsr, P_BELLY_COLORS);
+ tint(faceColor, D.faceSpot);
+ if (!isDark(faceColor)) {
+ tint(0xFF000000, D.mouth, D.nose);
+ }
+
+ mFootType = 0;
+ if (nsr.nextFloat() < 0.25f) {
+ mFootType = 4;
+ tint(0xFFFFFFFF, D.foot1, D.foot2, D.foot3, D.foot4);
+ } else {
+ if (nsr.nextFloat() < 0.25f) {
+ mFootType = 2;
+ tint(0xFFFFFFFF, D.foot1, D.foot3);
+ } else if (nsr.nextFloat() < 0.25f) {
+ mFootType = 3; // maybe -2 would be better? meh.
+ tint(0xFFFFFFFF, D.foot2, D.foot4);
+ } else if (nsr.nextFloat() < 0.1f) {
+ mFootType = 1;
+ tint(0xFFFFFFFF, (Drawable) choose(nsr, D.foot1, D.foot2, D.foot3, D.foot4));
+ }
+ }
+
+ tint(nsr.nextFloat() < 0.333f ? 0xFFFFFFFF : mBodyColor, D.tailCap);
+
+ final int capColor = chooseP(nsr, isDark(mBodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS);
+ tint(capColor, D.cap);
+ //tint(chooseP(nsr, isDark(bodyColor) ? P_LIGHT_SPOT_COLORS : P_DARK_SPOT_COLORS), D.nose);
+
+ final int collarColor = chooseP(nsr, P_COLLAR_COLORS);
+ tint(collarColor, D.collar);
+ mBowTie = nsr.nextFloat() < 0.1f;
+ tint(mBowTie ? collarColor : 0, D.bowtie);
+
+ String[] messages = context.getResources().getStringArray(
+ nsr.nextFloat() < 0.1f ? R.array.rare_cat_messages : R.array.cat_messages);
+ mFirstMessage = (String) choose(nsr, (Object[]) messages);
+ if (nsr.nextFloat() < 0.5f) mFirstMessage = mFirstMessage + mFirstMessage + mFirstMessage;
+ }
+
+ public static Cat fromShortcutId(Context context, String shortcutId) {
+ if (shortcutId.startsWith(SHORTCUT_ID_PREFIX)) {
+ return new Cat(context, Long.parseLong(shortcutId.replace(SHORTCUT_ID_PREFIX, "")));
+ }
+ return null;
+ }
+
+ public static Cat create(Context context) {
+ return new Cat(context, Math.abs(ThreadLocalRandom.current().nextInt()));
+ }
+
+ public Notification.Builder buildNotification(Context context) {
+ final Bundle extras = new Bundle();
+ extras.putString("android.substName", context.getString(R.string.notification_name));
+
+ final Icon notificationIcon = createNotificationLargeIcon(context);
+
+ final Intent intent = new Intent(Intent.ACTION_MAIN)
+ .setClass(context, NekoLand.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ ShortcutInfo shortcut = new ShortcutInfo.Builder(context, getShortcutId())
+ .setActivity(intent.getComponent())
+ .setIntent(intent)
+ .setShortLabel(getName())
+ .setIcon(createShortcutIcon(context))
+ .setLongLived(true)
+ .build();
+ context.getSystemService(ShortcutManager.class).addDynamicShortcuts(List.of(shortcut));
+
+ Notification.BubbleMetadata bubbs = new Notification.BubbleMetadata.Builder()
+ .setIntent(
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE))
+ .setIcon(notificationIcon)
+ .setSuppressNotification(false)
+ .setDesiredHeight(context.getResources().getDisplayMetrics().heightPixels)
+ .build();
+
+ return new Notification.Builder(context, CHAN_ID)
+ .setSmallIcon(Icon.createWithResource(context, R.drawable.stat_icon))
+ .setLargeIcon(notificationIcon)
+ .setColor(getBodyColor())
+ .setContentTitle(context.getString(R.string.notification_title))
+ .setShowWhen(true)
+ .setCategory(Notification.CATEGORY_STATUS)
+ .setContentText(getName())
+ .setContentIntent(
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE))
+ .setAutoCancel(true)
+ .setStyle(new Notification.MessagingStyle(createPerson())
+ .addMessage(mFirstMessage, System.currentTimeMillis(), createPerson())
+ .setConversationTitle(getName())
+ )
+ .setBubbleMetadata(bubbs)
+ .setShortcutId(getShortcutId())
+ .addExtras(extras);
+ }
+
+ private Person createPerson() {
+ return new Person.Builder()
+ .setName(getName())
+ .setBot(true)
+ .setKey(getShortcutId())
+ .build();
+ }
+
+ public long getSeed() {
+ return mSeed;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ final int w = Math.min(canvas.getWidth(), canvas.getHeight());
+ final int h = w;
+
+ if (mBitmap == null || mBitmap.getWidth() != w || mBitmap.getHeight() != h) {
+ mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ final Canvas bitCanvas = new Canvas(mBitmap);
+ slowDraw(bitCanvas, 0, 0, w, h);
+ }
+ canvas.drawBitmap(mBitmap, 0, 0, null);
+ }
+
+ private void slowDraw(Canvas canvas, int x, int y, int w, int h) {
+ for (int i = 0; i < D.drawingOrder.length; i++) {
+ final Drawable d = D.drawingOrder[i];
+ if (d != null) {
+ d.setBounds(x, y, x + w, y + h);
+ d.draw(canvas);
+ }
+ }
+
+ }
+
+ public Bitmap createBitmap(int w, int h) {
+ if (mBitmap != null && mBitmap.getWidth() == w && mBitmap.getHeight() == h) {
+ return mBitmap.copy(mBitmap.getConfig(), true);
+ }
+ Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ slowDraw(new Canvas(result), 0, 0, w, h);
+ return result;
+ }
+
+ public static Icon recompressIcon(Icon bitmapIcon) {
+ if (bitmapIcon.getType() != Icon.TYPE_BITMAP) return bitmapIcon;
+ try {
+ final Bitmap bits = (Bitmap) Icon.class.getDeclaredMethod("getBitmap").invoke(bitmapIcon);
+ final ByteArrayOutputStream ostream = new ByteArrayOutputStream(
+ bits.getWidth() * bits.getHeight() * 2); // guess 50% compression
+ final boolean ok = bits.compress(Bitmap.CompressFormat.PNG, 100, ostream);
+ if (!ok) return null;
+ return Icon.createWithData(ostream.toByteArray(), 0, ostream.size());
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+ return bitmapIcon;
+ }
+ }
+
+ public Icon createNotificationLargeIcon(Context context) {
+ final Resources res = context.getResources();
+ final int w = res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
+ final int h = res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
+ return recompressIcon(createIcon(context, w, h));
+ }
+
+ public Icon createShortcutIcon(Context context) {
+ // shortcuts do not support compressed bitmaps
+ final Resources res = context.getResources();
+ final int w = res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
+ final int h = res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
+ return createIcon(context, w, h);
+ }
+
+ public Icon createIcon(Context context, int w, int h) {
+ Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(result);
+ float[] hsv = new float[3];
+ Color.colorToHSV(mBodyColor, hsv);
+ hsv[2] = (hsv[2] > 0.5f)
+ ? (hsv[2] - 0.25f)
+ : (hsv[2] + 0.25f);
+ //final Paint pt = new Paint();
+ //pt.setColor(Color.HSVToColor(hsv));
+ //float r = w/2;
+ //canvas.drawCircle(r, r, r, pt);
+ // int m = w/10;
+
+ // Adaptive bitmaps!
+ canvas.drawColor(Color.HSVToColor(hsv));
+ int m = w / 4;
+
+ slowDraw(canvas, m, m, w - m - m, h - m - m);
+
+ return Icon.createWithAdaptiveBitmap(result);
+ }
+
+ @Override
+ public void setAlpha(int i) {
+
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public void setName(String name) {
+ this.mName = name;
+ }
+
+ public int getBodyColor() {
+ return mBodyColor;
+ }
+
+ public void logAdd(Context context) {
+ logCatAction(context, "egg_neko_add");
+ }
+
+ public void logRename(Context context) {
+ logCatAction(context, "egg_neko_rename");
+ }
+
+ public void logRemove(Context context) {
+ logCatAction(context, "egg_neko_remove");
+ }
+
+ public void logShare(Context context) {
+ logCatAction(context, "egg_neko_share");
+ }
+
+ private void logCatAction(Context context, String prefix) {
+ MetricsLogger.count(context, prefix, 1);
+ MetricsLogger.histogram(context, prefix + "_color",
+ getColorIndex(mBodyColor, P_BODY_COLORS));
+ MetricsLogger.histogram(context, prefix + "_bowtie", mBowTie ? 1 : 0);
+ MetricsLogger.histogram(context, prefix + "_feet", mFootType);
+ }
+
+ public String getShortcutId() {
+ return ALL_CATS_IN_ONE_CONVERSATION
+ ? GLOBAL_SHORTCUT_ID
+ : (SHORTCUT_ID_PREFIX + mSeed);
+ }
+
+ public static class CatParts {
+ public Drawable leftEar;
+ public Drawable rightEar;
+ public Drawable rightEarInside;
+ public Drawable leftEarInside;
+ public Drawable head;
+ public Drawable faceSpot;
+ public Drawable cap;
+ public Drawable mouth;
+ public Drawable body;
+ public Drawable foot1;
+ public Drawable leg1;
+ public Drawable foot2;
+ public Drawable leg2;
+ public Drawable foot3;
+ public Drawable leg3;
+ public Drawable foot4;
+ public Drawable leg4;
+ public Drawable tail;
+ public Drawable leg2Shadow;
+ public Drawable tailShadow;
+ public Drawable tailCap;
+ public Drawable belly;
+ public Drawable back;
+ public Drawable rightEye;
+ public Drawable leftEye;
+ public Drawable nose;
+ public Drawable bowtie;
+ public Drawable collar;
+ public Drawable[] drawingOrder;
+
+ public CatParts(Context context) {
+ body = context.getDrawable(R.drawable.body);
+ head = context.getDrawable(R.drawable.head);
+ leg1 = context.getDrawable(R.drawable.leg1);
+ leg2 = context.getDrawable(R.drawable.leg2);
+ leg3 = context.getDrawable(R.drawable.leg3);
+ leg4 = context.getDrawable(R.drawable.leg4);
+ tail = context.getDrawable(R.drawable.tail);
+ leftEar = context.getDrawable(R.drawable.left_ear);
+ rightEar = context.getDrawable(R.drawable.right_ear);
+ rightEarInside = context.getDrawable(R.drawable.right_ear_inside);
+ leftEarInside = context.getDrawable(R.drawable.left_ear_inside);
+ faceSpot = context.getDrawable(R.drawable.face_spot);
+ cap = context.getDrawable(R.drawable.cap);
+ mouth = context.getDrawable(R.drawable.mouth);
+ foot4 = context.getDrawable(R.drawable.foot4);
+ foot3 = context.getDrawable(R.drawable.foot3);
+ foot1 = context.getDrawable(R.drawable.foot1);
+ foot2 = context.getDrawable(R.drawable.foot2);
+ leg2Shadow = context.getDrawable(R.drawable.leg2_shadow);
+ tailShadow = context.getDrawable(R.drawable.tail_shadow);
+ tailCap = context.getDrawable(R.drawable.tail_cap);
+ belly = context.getDrawable(R.drawable.belly);
+ back = context.getDrawable(R.drawable.back);
+ rightEye = context.getDrawable(R.drawable.right_eye);
+ leftEye = context.getDrawable(R.drawable.left_eye);
+ nose = context.getDrawable(R.drawable.nose);
+ collar = context.getDrawable(R.drawable.collar);
+ bowtie = context.getDrawable(R.drawable.bowtie);
+ drawingOrder = getDrawingOrder();
+ }
+
+ private Drawable[] getDrawingOrder() {
+ return new Drawable[]{
+ collar,
+ leftEar, leftEarInside, rightEar, rightEarInside,
+ head,
+ faceSpot,
+ cap,
+ leftEye, rightEye,
+ nose, mouth,
+ tail, tailCap, tailShadow,
+ foot1, leg1,
+ foot2, leg2,
+ foot3, leg3,
+ foot4, leg4,
+ leg2Shadow,
+ body, belly,
+ bowtie
+ };
+ }
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/Food.java b/packages/EasterEgg/src/com/android/egg/neko/Food.java
new file mode 100644
index 0000000..aeffc4a
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/Food.java
@@ -0,0 +1,61 @@
+/*
+ * 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.egg.neko;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Icon;
+
+import com.android.egg.R;
+
+public class Food {
+ private final int mType;
+
+ private static int[] sIcons;
+ private static String[] sNames;
+
+ public Food(int type) {
+ mType = type;
+ }
+
+ public Icon getIcon(Context context) {
+ if (sIcons == null) {
+ TypedArray icons = context.getResources().obtainTypedArray(R.array.food_icons);
+ sIcons = new int[icons.length()];
+ for (int i = 0; i < sIcons.length; i++) {
+ sIcons[i] = icons.getResourceId(i, 0);
+ }
+ icons.recycle();
+ }
+ return Icon.createWithResource(context, sIcons[mType]);
+ }
+
+ public String getName(Context context) {
+ if (sNames == null) {
+ sNames = context.getResources().getStringArray(R.array.food_names);
+ }
+ return sNames[mType];
+ }
+
+ public long getInterval(Context context) {
+ return context.getResources().getIntArray(R.array.food_intervals)[mType];
+ }
+
+ public int getType() {
+ return mType;
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
new file mode 100644
index 0000000..df461c6
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.egg.neko;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.internal.logging.MetricsLogger;
+
+public class NekoActivationActivity extends Activity {
+ private static final String R_EGG_UNLOCK_SETTING = "egg_mode_r";
+
+ private void toastUp(String s) {
+ Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT);
+ toast.show();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ final PackageManager pm = getPackageManager();
+ final ComponentName cn = new ComponentName(this, NekoControlsService.class);
+ final boolean componentEnabled = pm.getComponentEnabledSetting(cn)
+ == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ if (Settings.System.getLong(getContentResolver(),
+ R_EGG_UNLOCK_SETTING, 0) == 0) {
+ if (componentEnabled) {
+ Log.v("Neko", "Disabling controls.");
+ pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ MetricsLogger.histogram(this, "egg_neko_enable", 0);
+ toastUp("\uD83D\uDEAB");
+ } else {
+ Log.v("Neko", "Controls already disabled.");
+ }
+ } else {
+ if (!componentEnabled) {
+ Log.v("Neko", "Enabling controls.");
+ pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ MetricsLogger.histogram(this, "egg_neko_enable", 1);
+ toastUp("\uD83D\uDC31");
+ } else {
+ Log.v("Neko", "Controls already enabled.");
+ }
+ }
+ finish();
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoControlsService.kt b/packages/EasterEgg/src/com/android/egg/neko/NekoControlsService.kt
new file mode 100644
index 0000000..56f599a
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoControlsService.kt
@@ -0,0 +1,323 @@
+/*
+ * 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.egg.neko
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.content.res.ColorStateList
+import android.graphics.drawable.Icon
+import android.service.controls.Control
+import android.service.controls.ControlsProviderService
+import android.service.controls.DeviceTypes
+import android.service.controls.actions.ControlAction
+import android.service.controls.actions.FloatAction
+import android.service.controls.templates.ControlButton
+import android.service.controls.templates.RangeTemplate
+import android.service.controls.templates.StatelessTemplate
+import android.service.controls.templates.ToggleTemplate
+import android.text.SpannableStringBuilder
+import android.text.style.ForegroundColorSpan
+import android.util.Log
+import androidx.annotation.RequiresApi
+import com.android.internal.logging.MetricsLogger
+import java.util.Random
+import java.util.concurrent.Flow
+import java.util.function.Consumer
+
+import com.android.egg.R
+
+const val CONTROL_ID_WATER = "water"
+const val CONTROL_ID_FOOD = "food"
+const val CONTROL_ID_TOY = "toy"
+
+const val FOOD_SPAWN_CAT_DELAY_MINS = 5L
+
+const val COLOR_FOOD_FG = 0xFFFF8000.toInt()
+const val COLOR_FOOD_BG = COLOR_FOOD_FG and 0x40FFFFFF.toInt()
+const val COLOR_WATER_FG = 0xFF0080FF.toInt()
+const val COLOR_WATER_BG = COLOR_WATER_FG and 0x40FFFFFF.toInt()
+const val COLOR_TOY_FG = 0xFFFF4080.toInt()
+const val COLOR_TOY_BG = COLOR_TOY_FG and 0x40FFFFFF.toInt()
+
+val P_TOY_ICONS = intArrayOf(
+ 1, R.drawable.ic_toy_mouse,
+ 1, R.drawable.ic_toy_fish,
+ 1, R.drawable.ic_toy_ball,
+ 1, R.drawable.ic_toy_laser
+)
+
+@RequiresApi(30)
+fun Control_toString(control: Control): String {
+ val hc = String.format("0x%08x", control.hashCode())
+ return ("Control($hc id=${control.controlId}, type=${control.deviceType}, " +
+ "title=${control.title}, template=${control.controlTemplate})")
+}
+
+@RequiresApi(30)
+public class NekoControlsService : ControlsProviderService(), PrefState.PrefsListener {
+ private val TAG = "NekoControls"
+
+ private val controls = HashMap<String, Control>()
+ private val publishers = ArrayList<UglyPublisher>()
+ private val rng = Random()
+
+ private var lastToyIcon: Icon? = null
+
+ private lateinit var prefs: PrefState
+
+ override fun onCreate() {
+ super.onCreate()
+
+ prefs = PrefState(this)
+ prefs.setListener(this)
+
+ createDefaultControls()
+ }
+
+ override fun onPrefsChanged() {
+ createDefaultControls()
+ }
+
+ private fun createDefaultControls() {
+ val foodState: Int = prefs.foodState
+ if (foodState != 0) {
+ NekoService.registerJobIfNeeded(this, FOOD_SPAWN_CAT_DELAY_MINS)
+ }
+
+ val water = prefs.waterState
+
+ controls[CONTROL_ID_WATER] = makeWaterBowlControl(water)
+ controls[CONTROL_ID_FOOD] = makeFoodBowlControl(foodState != 0)
+ controls[CONTROL_ID_TOY] = makeToyControl(currentToyIcon(), false)
+ }
+
+ private fun currentToyIcon(): Icon {
+ val icon = lastToyIcon ?: randomToyIcon()
+ lastToyIcon = icon
+ return icon
+ }
+
+ private fun randomToyIcon(): Icon {
+ return Icon.createWithResource(resources, Cat.chooseP(rng, P_TOY_ICONS, 4))
+ }
+
+ private fun colorize(s: CharSequence, color: Int): CharSequence {
+ val ssb = SpannableStringBuilder(s)
+ ssb.setSpan(ForegroundColorSpan(color), 0, s.length, 0)
+ return ssb
+ }
+
+ private fun makeToyControl(icon: Icon?, thrown: Boolean): Control {
+ return Control.StatefulBuilder(CONTROL_ID_TOY, getPendingIntent())
+ .setDeviceType(DeviceTypes.TYPE_UNKNOWN)
+ .setCustomIcon(icon)
+ // ?.setTint(COLOR_TOY_FG)) // TODO(b/159559045): uncomment when fixed
+ .setCustomColor(ColorStateList.valueOf(COLOR_TOY_BG))
+ .setTitle(colorize(getString(R.string.control_toy_title), COLOR_TOY_FG))
+ .setStatusText(colorize(
+ if (thrown) getString(R.string.control_toy_status) else "",
+ COLOR_TOY_FG))
+ .setControlTemplate(StatelessTemplate("toy"))
+ .setStatus(Control.STATUS_OK)
+ .setSubtitle(if (thrown) "" else getString(R.string.control_toy_subtitle))
+ .setAppIntent(getAppIntent())
+ .build()
+ }
+
+ private fun makeWaterBowlControl(fillLevel: Float): Control {
+ return Control.StatefulBuilder(CONTROL_ID_WATER, getPendingIntent())
+ .setDeviceType(DeviceTypes.TYPE_KETTLE)
+ .setTitle(colorize(getString(R.string.control_water_title), COLOR_WATER_FG))
+ .setCustomColor(ColorStateList.valueOf(COLOR_WATER_BG))
+ .setCustomIcon(Icon.createWithResource(resources,
+ if (fillLevel >= 100f) R.drawable.ic_water_filled else R.drawable.ic_water))
+ //.setTint(COLOR_WATER_FG)) // TODO(b/159559045): uncomment when fixed
+ .setControlTemplate(RangeTemplate("waterlevel", 0f, 200f, fillLevel, 10f,
+ "%.0f mL"))
+ .setStatus(Control.STATUS_OK)
+ .setSubtitle(if (fillLevel == 0f) getString(R.string.control_water_subtitle) else "")
+ .build()
+ }
+
+ private fun makeFoodBowlControl(filled: Boolean): Control {
+ return Control.StatefulBuilder(CONTROL_ID_FOOD, getPendingIntent())
+ .setDeviceType(DeviceTypes.TYPE_UNKNOWN)
+ .setCustomColor(ColorStateList.valueOf(COLOR_FOOD_BG))
+ .setTitle(colorize(getString(R.string.control_food_title), COLOR_FOOD_FG))
+ .setCustomIcon(Icon.createWithResource(resources,
+ if (filled) R.drawable.ic_foodbowl_filled else R.drawable.ic_bowl))
+ // .setTint(COLOR_FOOD_FG)) // TODO(b/159559045): uncomment when fixed
+ .setStatusText(
+ if (filled) colorize(
+ getString(R.string.control_food_status_full), 0xCCFFFFFF.toInt())
+ else colorize(
+ getString(R.string.control_food_status_empty), 0x80FFFFFF.toInt()))
+ .setControlTemplate(ToggleTemplate("foodbowl", ControlButton(filled, "Refill")))
+ .setStatus(Control.STATUS_OK)
+ .setSubtitle(if (filled) "" else getString(R.string.control_food_subtitle))
+ .build()
+ }
+
+ private fun getPendingIntent(): PendingIntent {
+ val intent = Intent(Intent.ACTION_MAIN)
+ .setClass(this, NekoLand::class.java)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ return PendingIntent.getActivity(this, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
+ }
+
+ private fun getAppIntent(): PendingIntent {
+ return getPendingIntent()
+ }
+
+
+ override fun performControlAction(
+ controlId: String,
+ action: ControlAction,
+ consumer: Consumer<Int>
+ ) {
+ when (controlId) {
+ CONTROL_ID_FOOD -> {
+ // refill bowl
+ controls[CONTROL_ID_FOOD] = makeFoodBowlControl(true)
+ Log.v(TAG, "Bowl refilled. (Registering job.)")
+ NekoService.registerJob(this, FOOD_SPAWN_CAT_DELAY_MINS)
+ MetricsLogger.histogram(this, "egg_neko_offered_food", 11)
+ prefs.foodState = 11
+ }
+ CONTROL_ID_TOY -> {
+ Log.v(TAG, "Toy tossed.")
+ controls[CONTROL_ID_TOY] =
+ makeToyControl(currentToyIcon(), true)
+ // TODO: re-enable toy
+ Thread() {
+ Thread.sleep((1 + Random().nextInt(4)) * 1000L)
+ NekoService.getExistingCat(prefs)?.let {
+ NekoService.notifyCat(this, it)
+ }
+ controls[CONTROL_ID_TOY] = makeToyControl(randomToyIcon(), false)
+ pushControlChanges()
+ }.start()
+ }
+ CONTROL_ID_WATER -> {
+ if (action is FloatAction) {
+ controls[CONTROL_ID_WATER] = makeWaterBowlControl(action.newValue)
+ Log.v(TAG, "Water level set to " + action.newValue)
+ prefs.waterState = action.newValue
+ }
+ }
+ else -> {
+ return
+ }
+ }
+ consumer.accept(ControlAction.RESPONSE_OK)
+ pushControlChanges()
+ }
+
+ private fun pushControlChanges() {
+ Thread() {
+ publishers.forEach { it.refresh() }
+ }.start()
+ }
+
+ private fun makeStateless(c: Control?): Control? {
+ if (c == null) return null
+ return Control.StatelessBuilder(c.controlId, c.appIntent)
+ .setTitle(c.title)
+ .setSubtitle(c.subtitle)
+ .setStructure(c.structure)
+ .setDeviceType(c.deviceType)
+ .setCustomIcon(c.customIcon)
+ .setCustomColor(c.customColor)
+ .build()
+ }
+
+ override fun createPublisherFor(list: MutableList<String>): Flow.Publisher<Control> {
+ createDefaultControls()
+
+ val publisher = UglyPublisher(list, true)
+ publishers.add(publisher)
+ return publisher
+ }
+
+ override fun createPublisherForAllAvailable(): Flow.Publisher<Control> {
+ createDefaultControls()
+
+ val publisher = UglyPublisher(controls.keys, false)
+ publishers.add(publisher)
+ return publisher
+ }
+
+ private inner class UglyPublisher(
+ val controlKeys: Iterable<String>,
+ val indefinite: Boolean
+ ) : Flow.Publisher<Control> {
+ val subscriptions = ArrayList<UglySubscription>()
+
+ private inner class UglySubscription(
+ val initialControls: Iterator<Control>,
+ var subscriber: Flow.Subscriber<in Control>?
+ ) : Flow.Subscription {
+ override fun cancel() {
+ Log.v(TAG, "cancel subscription: $this for subscriber: $subscriber " +
+ "to publisher: $this@UglyPublisher")
+ subscriber = null
+ unsubscribe(this)
+ }
+
+ override fun request(p0: Long) {
+ (0 until p0).forEach { _ ->
+ if (initialControls.hasNext()) {
+ send(initialControls.next())
+ } else {
+ if (!indefinite) subscriber?.onComplete()
+ }
+ }
+ }
+
+ fun send(c: Control) {
+ Log.v(TAG, "sending update: " + Control_toString(c) + " => " + subscriber)
+ subscriber?.onNext(c)
+ }
+ }
+
+ override fun subscribe(subscriber: Flow.Subscriber<in Control>) {
+ Log.v(TAG, "subscribe to publisher: $this by subscriber: $subscriber")
+ val sub = UglySubscription(controlKeys.mapNotNull { controls[it] }.iterator(),
+ subscriber)
+ subscriptions.add(sub)
+ subscriber.onSubscribe(sub)
+ }
+
+ fun unsubscribe(sub: UglySubscription) {
+ Log.v(TAG, "no more subscriptions, removing subscriber: $sub")
+ subscriptions.remove(sub)
+ if (subscriptions.size == 0) {
+ Log.v(TAG, "no more subscribers, removing publisher: $this")
+ publishers.remove(this)
+ }
+ }
+
+ fun refresh() {
+ controlKeys.mapNotNull { controls[it] }.forEach { control ->
+ subscriptions.forEach { sub ->
+ sub.send(control)
+ }
+ }
+ }
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java b/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java
new file mode 100644
index 0000000..2bd2228
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoDialog.java
@@ -0,0 +1,109 @@
+/*
+ * 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.egg.neko;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.egg.R;
+
+import java.util.ArrayList;
+
+public class NekoDialog extends Dialog {
+
+ private final Adapter mAdapter;
+
+ public NekoDialog(@NonNull Context context) {
+ super(context, android.R.style.Theme_Material_Dialog_NoActionBar);
+ RecyclerView view = new RecyclerView(getContext());
+ mAdapter = new Adapter(getContext());
+ view.setLayoutManager(new GridLayoutManager(getContext(), 2));
+ view.setAdapter(mAdapter);
+ final float dp = context.getResources().getDisplayMetrics().density;
+ final int pad = (int)(16*dp);
+ view.setPadding(pad, pad, pad, pad);
+ setContentView(view);
+ }
+
+ private void onFoodSelected(Food food) {
+ PrefState prefs = new PrefState(getContext());
+ int currentState = prefs.getFoodState();
+ if (currentState == 0 && food.getType() != 0) {
+ NekoService.registerJob(getContext(), food.getInterval(getContext()));
+ }
+// MetricsLogger.histogram(getContext(), "egg_neko_offered_food", food.getType());
+ prefs.setFoodState(food.getType());
+ dismiss();
+ }
+
+ private class Adapter extends RecyclerView.Adapter<Holder> {
+
+ private final Context mContext;
+ private final ArrayList<Food> mFoods = new ArrayList<>();
+
+ public Adapter(Context context) {
+ mContext = context;
+ int[] foods = context.getResources().getIntArray(R.array.food_names);
+ // skip food 0, you can't choose it
+ for (int i=1; i<foods.length; i++) {
+ mFoods.add(new Food(i));
+ }
+ }
+
+ @Override
+ public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new Holder(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.food_layout, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(final Holder holder, int position) {
+ final Food food = mFoods.get(position);
+ ((ImageView) holder.itemView.findViewById(R.id.icon))
+ .setImageIcon(food.getIcon(mContext));
+ ((TextView) holder.itemView.findViewById(R.id.text))
+ .setText(food.getName(mContext));
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onFoodSelected(mFoods.get(holder.getAdapterPosition()));
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return mFoods.size();
+ }
+ }
+
+ public static class Holder extends RecyclerView.ViewHolder {
+
+ public Holder(View itemView) {
+ super(itemView);
+ }
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java b/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java
new file mode 100644
index 0000000..8ed8087
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoLand.java
@@ -0,0 +1,340 @@
+/*
+ * 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.egg.neko;
+
+import android.Manifest;
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.core.content.FileProvider;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.egg.R;
+import com.android.egg.neko.PrefState.PrefsListener;
+import com.android.internal.logging.MetricsLogger;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class NekoLand extends Activity implements PrefsListener {
+ public static String CHAN_ID = "EGG";
+
+ public static boolean DEBUG = false;
+ public static boolean DEBUG_NOTIFICATIONS = false;
+
+ private static final int EXPORT_BITMAP_SIZE = 600;
+
+ private static final int STORAGE_PERM_REQUEST = 123;
+
+ private static boolean CAT_GEN = false;
+ private PrefState mPrefs;
+ private CatAdapter mAdapter;
+ private Cat mPendingShareCat;
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.neko_activity);
+ final ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setLogo(Cat.create(this));
+ actionBar.setDisplayUseLogoEnabled(false);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+
+ mPrefs = new PrefState(this);
+ mPrefs.setListener(this);
+ final RecyclerView recyclerView = findViewById(R.id.holder);
+ mAdapter = new CatAdapter();
+ recyclerView.setAdapter(mAdapter);
+ recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
+ int numCats = updateCats();
+ MetricsLogger.histogram(this, "egg_neko_visit_gallery", numCats);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mPrefs.setListener(null);
+ }
+
+ private int updateCats() {
+ Cat[] cats;
+ if (CAT_GEN) {
+ cats = new Cat[50];
+ for (int i = 0; i < cats.length; i++) {
+ cats[i] = Cat.create(this);
+ }
+ } else {
+ final float[] hsv = new float[3];
+ List<Cat> list = mPrefs.getCats();
+ Collections.sort(list, new Comparator<Cat>() {
+ @Override
+ public int compare(Cat cat, Cat cat2) {
+ Color.colorToHSV(cat.getBodyColor(), hsv);
+ float bodyH1 = hsv[0];
+ Color.colorToHSV(cat2.getBodyColor(), hsv);
+ float bodyH2 = hsv[0];
+ return Float.compare(bodyH1, bodyH2);
+ }
+ });
+ cats = list.toArray(new Cat[0]);
+ }
+ mAdapter.setCats(cats);
+ return cats.length;
+ }
+
+ private void onCatClick(Cat cat) {
+ if (CAT_GEN) {
+ mPrefs.addCat(cat);
+ new AlertDialog.Builder(NekoLand.this)
+ .setTitle("Cat added")
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ } else {
+ showNameDialog(cat);
+ }
+ }
+
+ private void onCatRemove(Cat cat) {
+ cat.logRemove(this);
+ mPrefs.removeCat(cat);
+ }
+
+ private void showNameDialog(final Cat cat) {
+ final Context context = new ContextThemeWrapper(this,
+ android.R.style.Theme_Material_Light_Dialog_NoActionBar);
+ // TODO: Move to XML, add correct margins.
+ View view = LayoutInflater.from(context).inflate(R.layout.edit_text, null);
+ final EditText text = (EditText) view.findViewById(android.R.id.edit);
+ text.setText(cat.getName());
+ text.setSelection(cat.getName().length());
+ final int size = context.getResources()
+ .getDimensionPixelSize(android.R.dimen.app_icon_size);
+ Drawable catIcon = cat.createIcon(this, size, size).loadDrawable(this);
+ new AlertDialog.Builder(context)
+ .setTitle(" ")
+ .setIcon(catIcon)
+ .setView(view)
+ .setPositiveButton(android.R.string.ok, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ cat.logRename(context);
+ cat.setName(text.getText().toString().trim());
+ mPrefs.addCat(cat);
+ }
+ }).show();
+ }
+
+ @Override
+ public void onPrefsChanged() {
+ updateCats();
+ }
+
+ private class CatAdapter extends RecyclerView.Adapter<CatHolder> {
+
+ private Cat[] mCats;
+
+ public void setCats(Cat[] cats) {
+ mCats = cats;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public CatHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new CatHolder(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.cat_view, parent, false));
+ }
+
+ private void setContextGroupVisible(final CatHolder holder, boolean vis) {
+ final View group = holder.contextGroup;
+ if (vis && group.getVisibility() != View.VISIBLE) {
+ group.setAlpha(0);
+ group.setVisibility(View.VISIBLE);
+ group.animate().alpha(1.0f).setDuration(333);
+ Runnable hideAction = new Runnable() {
+ @Override
+ public void run() {
+ setContextGroupVisible(holder, false);
+ }
+ };
+ group.setTag(hideAction);
+ group.postDelayed(hideAction, 5000);
+ } else if (!vis && group.getVisibility() == View.VISIBLE) {
+ group.removeCallbacks((Runnable) group.getTag());
+ group.animate().alpha(0f).setDuration(250).withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ group.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(final CatHolder holder, int position) {
+ Context context = holder.itemView.getContext();
+ final int size = context.getResources().getDimensionPixelSize(R.dimen.neko_display_size);
+ holder.imageView.setImageIcon(mCats[position].createIcon(context, size, size));
+ holder.textView.setText(mCats[position].getName());
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onCatClick(mCats[holder.getAdapterPosition()]);
+ }
+ });
+ holder.itemView.setOnLongClickListener(new OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ setContextGroupVisible(holder, true);
+ return true;
+ }
+ });
+ holder.delete.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setContextGroupVisible(holder, false);
+ new AlertDialog.Builder(NekoLand.this)
+ .setTitle(getString(R.string.confirm_delete, mCats[position].getName()))
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ onCatRemove(mCats[holder.getAdapterPosition()]);
+ }
+ })
+ .show();
+ }
+ });
+ holder.share.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setContextGroupVisible(holder, false);
+ Cat cat = mCats[holder.getAdapterPosition()];
+ if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+ mPendingShareCat = cat;
+ requestPermissions(
+ new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
+ STORAGE_PERM_REQUEST);
+ return;
+ }
+ shareCat(cat);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return mCats.length;
+ }
+ }
+
+ private void shareCat(Cat cat) {
+ final File dir = new File(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
+ "Cats");
+ if (!dir.exists() && !dir.mkdirs()) {
+ Log.e("NekoLand", "save: error: can't create Pictures directory");
+ return;
+ }
+ final File png = new File(dir, cat.getName().replaceAll("[/ #:]+", "_") + ".png");
+ Bitmap bitmap = cat.createBitmap(EXPORT_BITMAP_SIZE, EXPORT_BITMAP_SIZE);
+ if (bitmap != null) {
+ try {
+ OutputStream os = new FileOutputStream(png);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 0, os);
+ os.close();
+ MediaScannerConnection.scanFile(
+ this,
+ new String[]{png.toString()},
+ new String[]{"image/png"},
+ null);
+ Log.v("Neko", "cat file: " + png);
+ Uri uri = FileProvider.getUriForFile(this, "com.android.egg.fileprovider", png);
+ Log.v("Neko", "cat uri: " + uri);
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.putExtra(Intent.EXTRA_STREAM, uri);
+ intent.putExtra(Intent.EXTRA_SUBJECT, cat.getName());
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setType("image/png");
+ startActivity(Intent.createChooser(intent, null)
+ .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION));
+ cat.logShare(this);
+ } catch (IOException e) {
+ Log.e("NekoLand", "save: error: " + e);
+ }
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ String permissions[], int[] grantResults) {
+ if (requestCode == STORAGE_PERM_REQUEST) {
+ if (mPendingShareCat != null) {
+ shareCat(mPendingShareCat);
+ mPendingShareCat = null;
+ }
+ }
+ }
+
+ private static class CatHolder extends RecyclerView.ViewHolder {
+ private final ImageView imageView;
+ private final TextView textView;
+ private final View contextGroup;
+ private final View delete;
+ private final View share;
+
+ public CatHolder(View itemView) {
+ super(itemView);
+ imageView = (ImageView) itemView.findViewById(android.R.id.icon);
+ textView = (TextView) itemView.findViewById(android.R.id.title);
+ contextGroup = itemView.findViewById(R.id.contextGroup);
+ delete = itemView.findViewById(android.R.id.closeButton);
+ share = itemView.findViewById(android.R.id.shareText);
+ }
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java
new file mode 100644
index 0000000..ca89adc
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoLockedActivity.java
@@ -0,0 +1,48 @@
+/*
+ * 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.egg.neko;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import androidx.annotation.Nullable;
+
+public class NekoLockedActivity extends Activity implements OnDismissListener {
+
+ private NekoDialog mDialog;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+
+ mDialog = new NekoDialog(this);
+ mDialog.setOnDismissListener(this);
+ mDialog.show();
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ finish();
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
new file mode 100644
index 0000000..939e85c
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java
@@ -0,0 +1,193 @@
+/*
+ * 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.egg.neko;
+
+import static com.android.egg.neko.Cat.PURR;
+import static com.android.egg.neko.NekoLand.CHAN_ID;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.egg.R;
+
+import java.util.List;
+import java.util.Random;
+
+public class NekoService extends JobService {
+
+ private static final String TAG = "NekoService";
+
+ public static int JOB_ID = 42;
+
+ public static int CAT_NOTIFICATION = 1;
+ public static int DEBUG_NOTIFICATION = 1234;
+
+ public static float CAT_CAPTURE_PROB = 1.0f; // generous
+
+ public static long SECONDS = 1000;
+ public static long MINUTES = 60 * SECONDS;
+
+ //public static long INTERVAL_FLEX = 15 * SECONDS;
+ public static long INTERVAL_FLEX = 5 * MINUTES;
+
+ public static float INTERVAL_JITTER_FRAC = 0.25f;
+
+ private static void setupNotificationChannels(Context context) {
+ NotificationManager noman = context.getSystemService(NotificationManager.class);
+ NotificationChannel eggChan = new NotificationChannel(CHAN_ID,
+ context.getString(R.string.notification_channel_name),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ eggChan.setSound(Uri.EMPTY, Notification.AUDIO_ATTRIBUTES_DEFAULT); // cats are quiet
+ eggChan.setVibrationPattern(PURR); // not totally quiet though
+ //eggChan.setBlockableSystem(true); // unlike a real cat, you can push this one off your lap
+ eggChan.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); // cats sit in the window
+ noman.createNotificationChannel(eggChan);
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ Log.v(TAG, "Starting job: " + String.valueOf(params));
+
+ if (NekoLand.DEBUG_NOTIFICATIONS) {
+ NotificationManager noman = getSystemService(NotificationManager.class);
+ final Bundle extras = new Bundle();
+ extras.putString("android.substName", getString(R.string.notification_name));
+ final int size = getResources()
+ .getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
+ final Cat cat = Cat.create(this);
+ final Notification.Builder builder
+ = cat.buildNotification(this)
+ .setContentTitle("DEBUG")
+ .setChannelId(NekoLand.CHAN_ID)
+ .setContentText("Ran job: " + params);
+
+ noman.notify(DEBUG_NOTIFICATION, builder.build());
+ }
+
+ triggerFoodResponse(this);
+ cancelJob(this);
+ return false;
+ }
+
+ private static void triggerFoodResponse(Context context) {
+ final PrefState prefs = new PrefState(context);
+ int food = prefs.getFoodState();
+ if (food != 0) {
+ prefs.setFoodState(0); // nom
+ final Random rng = new Random();
+ if (rng.nextFloat() <= CAT_CAPTURE_PROB) {
+ Cat cat;
+ List<Cat> cats = prefs.getCats();
+ final int[] probs = context.getResources().getIntArray(R.array.food_new_cat_prob);
+ final float waterLevel100 = prefs.getWaterState() / 2; // water is 0..200
+ final float new_cat_prob = (float) ((food < probs.length)
+ ? probs[food]
+ : waterLevel100) / 100f;
+ Log.v(TAG, "Food type: " + food);
+ Log.v(TAG, "New cat probability: " + new_cat_prob);
+
+ if (cats.size() == 0 || rng.nextFloat() <= new_cat_prob) {
+ cat = newRandomCat(context, prefs);
+ Log.v(TAG, "A new cat is here: " + cat.getName());
+ } else {
+ cat = getExistingCat(prefs);
+ Log.v(TAG, "A cat has returned: " + cat.getName());
+ }
+
+ notifyCat(context, cat);
+ }
+ }
+ }
+
+ static void notifyCat(Context context, Cat cat) {
+ NotificationManager noman = context.getSystemService(NotificationManager.class);
+ final Notification.Builder builder = cat.buildNotification(context);
+ noman.notify(cat.getShortcutId(), CAT_NOTIFICATION, builder.build());
+ }
+
+ static Cat newRandomCat(Context context, PrefState prefs) {
+ final Cat cat = Cat.create(context);
+ prefs.addCat(cat);
+ cat.logAdd(context);
+ return cat;
+ }
+
+ static Cat getExistingCat(PrefState prefs) {
+ final List<Cat> cats = prefs.getCats();
+ if (cats.size() == 0) return null;
+ return cats.get(new Random().nextInt(cats.size()));
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters jobParameters) {
+ return false;
+ }
+
+ public static void registerJobIfNeeded(Context context, long intervalMinutes) {
+ JobScheduler jss = context.getSystemService(JobScheduler.class);
+ JobInfo info = jss.getPendingJob(JOB_ID);
+ if (info == null) {
+ registerJob(context, intervalMinutes);
+ }
+ }
+
+ public static void registerJob(Context context, long intervalMinutes) {
+ setupNotificationChannels(context);
+
+ JobScheduler jss = context.getSystemService(JobScheduler.class);
+ jss.cancel(JOB_ID);
+ long interval = intervalMinutes * MINUTES;
+ long jitter = (long) (INTERVAL_JITTER_FRAC * interval);
+ interval += (long) (Math.random() * (2 * jitter)) - jitter;
+ final JobInfo jobInfo = new JobInfo.Builder(JOB_ID,
+ new ComponentName(context, NekoService.class))
+ .setPeriodic(interval, INTERVAL_FLEX)
+ .build();
+
+ Log.v(TAG, "A cat will visit in " + interval + "ms: " + String.valueOf(jobInfo));
+ jss.schedule(jobInfo);
+
+ if (NekoLand.DEBUG_NOTIFICATIONS) {
+ NotificationManager noman = context.getSystemService(NotificationManager.class);
+ noman.notify(DEBUG_NOTIFICATION, new Notification.Builder(context)
+ .setSmallIcon(R.drawable.stat_icon)
+ .setContentTitle(String.format("Job scheduled in %d min", (interval / MINUTES)))
+ .setContentText(String.valueOf(jobInfo))
+ .setPriority(Notification.PRIORITY_MIN)
+ .setCategory(Notification.CATEGORY_SERVICE)
+ .setChannelId(NekoLand.CHAN_ID)
+ .setShowWhen(true)
+ .build());
+ }
+ }
+
+ public static void cancelJob(Context context) {
+ JobScheduler jss = context.getSystemService(JobScheduler.class);
+ Log.v(TAG, "Canceling job");
+ jss.cancel(JOB_ID);
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
new file mode 100644
index 0000000..d02433f
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java
@@ -0,0 +1,116 @@
+/*
+ * 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.egg.neko;
+
+import android.content.Intent;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.util.Log;
+
+import com.android.egg.neko.PrefState.PrefsListener;
+import com.android.internal.logging.MetricsLogger;
+
+public class NekoTile extends TileService implements PrefsListener {
+
+ private static final String TAG = "NekoTile";
+
+ private PrefState mPrefs;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mPrefs = new PrefState(this);
+ }
+
+ @Override
+ public void onStartListening() {
+ super.onStartListening();
+ mPrefs.setListener(this);
+ updateState();
+ }
+
+ @Override
+ public void onStopListening() {
+ super.onStopListening();
+ mPrefs.setListener(null);
+ }
+
+ @Override
+ public void onTileAdded() {
+ super.onTileAdded();
+ MetricsLogger.count(this, "egg_neko_tile_added", 1);
+ }
+
+ @Override
+ public void onTileRemoved() {
+ super.onTileRemoved();
+ MetricsLogger.count(this, "egg_neko_tile_removed", 1);
+ }
+
+ @Override
+ public void onPrefsChanged() {
+ updateState();
+ }
+
+ private void updateState() {
+ Tile tile = getQsTile();
+ int foodState = mPrefs.getFoodState();
+ Food food = new Food(foodState);
+ if (foodState != 0) {
+ NekoService.registerJobIfNeeded(this, food.getInterval(this));
+ }
+ tile.setIcon(food.getIcon(this));
+ tile.setLabel(food.getName(this));
+ tile.setState(foodState != 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
+ tile.updateTile();
+ }
+
+ @Override
+ public void onClick() {
+ if (mPrefs.getFoodState() != 0) {
+ // there's already food loaded, let's empty it
+ MetricsLogger.count(this, "egg_neko_empty_food", 1);
+ mPrefs.setFoodState(0);
+ NekoService.cancelJob(this);
+ } else {
+ // time to feed the cats
+ if (isLocked()) {
+ if (isSecure()) {
+ Log.d(TAG, "startActivityAndCollapse");
+ Intent intent = new Intent(this, NekoLockedActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivityAndCollapse(intent);
+ } else {
+ unlockAndRun(new Runnable() {
+ @Override
+ public void run() {
+ showNekoDialog();
+ }
+ });
+ }
+ } else {
+ showNekoDialog();
+ }
+ }
+ }
+
+ private void showNekoDialog() {
+ Log.d(TAG, "showNekoDialog");
+ MetricsLogger.count(this, "egg_neko_select_food", 1);
+ showDialog(new NekoDialog(this));
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
new file mode 100644
index 0000000..49ff315
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java
@@ -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.egg.neko;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class PrefState implements OnSharedPreferenceChangeListener {
+
+ private static final String FILE_NAME = "mPrefs";
+
+ private static final String FOOD_STATE = "food";
+
+ private static final String WATER_STATE = "water";
+
+ private static final String CAT_KEY_PREFIX = "cat:";
+
+ private final Context mContext;
+ private final SharedPreferences mPrefs;
+ private PrefsListener mListener;
+
+ public PrefState(Context context) {
+ mContext = context;
+ mPrefs = mContext.getSharedPreferences(FILE_NAME, 0);
+ }
+
+ // Can also be used for renaming.
+ public void addCat(Cat cat) {
+ mPrefs.edit()
+ .putString(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()), cat.getName())
+ .apply();
+ }
+
+ public void removeCat(Cat cat) {
+ mPrefs.edit().remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())).apply();
+ }
+
+ public List<Cat> getCats() {
+ ArrayList<Cat> cats = new ArrayList<>();
+ Map<String, ?> map = mPrefs.getAll();
+ for (String key : map.keySet()) {
+ if (key.startsWith(CAT_KEY_PREFIX)) {
+ long seed = Long.parseLong(key.substring(CAT_KEY_PREFIX.length()));
+ Cat cat = new Cat(mContext, seed);
+ cat.setName(String.valueOf(map.get(key)));
+ cats.add(cat);
+ }
+ }
+ return cats;
+ }
+
+ public int getFoodState() {
+ return mPrefs.getInt(FOOD_STATE, 0);
+ }
+
+ public void setFoodState(int foodState) {
+ mPrefs.edit().putInt(FOOD_STATE, foodState).apply();
+ }
+
+ public float getWaterState() {
+ return mPrefs.getFloat(WATER_STATE, 0f);
+ }
+
+ public void setWaterState(float waterState) {
+ mPrefs.edit().putFloat(WATER_STATE, waterState).apply();
+ }
+
+ public void setListener(PrefsListener listener) {
+ mListener = listener;
+ if (mListener != null) {
+ mPrefs.registerOnSharedPreferenceChangeListener(this);
+ } else {
+ mPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ mListener.onPrefsChanged();
+ }
+
+ public interface PrefsListener {
+ void onPrefsChanged();
+ }
+}