LineageParts: Add unique easter egg
Android Oreo is an octopus, lets be a squid instead!
https://i.imgur.com/od1DSRL.png
https://i.imgur.com/PmmrdV1.png
https://i.imgur.com/6mpdSuq.png
https://www.youtube.com/watch?v=O6Gi7ClQZ6U
Change-Id: I5c69190ac931cc287c9b98ca11fac1a92ecc013d
diff --git a/Android.mk b/Android.mk
index aab511d..d73478c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -7,6 +7,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v4 \
android-support-v13 \
+ android-support-dynamic-animation \
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 63f60a6..ce857d9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -248,5 +248,15 @@
</intent-filter>
</activity>
+ <activity android:name=".egg.octo.Ocquarium"
+ android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"
+ android:label="@string/egg_title">
+ <intent-filter>
+ <action android:name="org.lineageos.lineageparts.EASTER_EGG"/>
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.android.internal.category.PLATLOGO" />
+ </intent-filter>
+ </activity>
+
</application>
</manifest>
diff --git a/res/drawable-nodpi/octo_bg_lineage.xml b/res/drawable-nodpi/octo_bg_lineage.xml
new file mode 100644
index 0000000..74a8d5a
--- /dev/null
+++ b/res/drawable-nodpi/octo_bg_lineage.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+ Copyright (C) 2017 The LineageOS 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient android:angle="-90"
+ android:startColor="#FF167c80"
+ android:endColor="#FF084A4C"
+ android:type="linear"
+ />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/logo_lineage.xml b/res/drawable/logo_lineage.xml
new file mode 100644
index 0000000..cac1b33
--- /dev/null
+++ b/res/drawable/logo_lineage.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The LineageOS 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="512dp"
+ android:height="256dp"
+ android:viewportWidth="512"
+ android:viewportHeight="256">
+
+ <path
+ android:fillColor="#167c80"
+ android:pathData="M416,128a39.92,39.92,0,0,0-31.11,14.87l-1.5-.6A294.78,294.78,0,0,0,336,128.14s0-.09,0-.14a80,80,0,0,0-160,0s0,.09,0,.13l-1.71
+.37 a293.48,293.48,0,0,0-45.67,13.76l-1.5 .6
+a40,40,0,1,0,7.39,14.28h0a277.34,277.34,0,0,1,43.1-13,80,80,0,0,0,156.73,0,277.3,277.3,0,0,1,43.11,13h0A40,40,0,1,0,416,128ZM96,192a24,24,0,1,1,24-24A24,24,0,0,1,96,192Zm160,0a64,64,0,1,1,64-64A64.07,64.07,0,0,1,256,192Zm160,0a24,24,0,1,1,24-24A24,24,0,0,1,416,192ZM288,128a32,32,0,1,1-32-32A32,32,0,0,1,288,128Z" />
+</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 31f3757..7d181d8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -672,4 +672,7 @@
<string name="touchscreen_gesture_action_next_track">Skip to the next music track</string>
<string name="touchscreen_gesture_action_volume_down">Lower media volume</string>
<string name="touchscreen_gesture_action_volume_up">Raise media volume</string>
+
+ <!-- Egg: Title for the easter egg activity -->
+ <string name="egg_title">Easter Egg</string>
</resources>
diff --git a/src/org/lineageos/lineageparts/egg/octo/Ocquarium.java b/src/org/lineageos/lineageparts/egg/octo/Ocquarium.java
new file mode 100644
index 0000000..d4a31d4
--- /dev/null
+++ b/src/org/lineageos/lineageparts/egg/octo/Ocquarium.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2017 The LineageOS 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 org.lineageos.lineageparts.egg.octo;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import org.lineageos.lineageparts.R;
+
+public class Ocquarium extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+ final float dp = getResources().getDisplayMetrics().density;
+
+ getWindow().setBackgroundDrawableResource(R.drawable.octo_bg_lineage);
+
+ FrameLayout bg = new FrameLayout(this);
+ setContentView(bg);
+ bg.setAlpha(0f);
+ bg.animate().setStartDelay(500).setDuration(5000).alpha(1f).start();
+
+ ImageView imageView = new ImageView(this);
+ bg.addView(imageView, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+
+ final OctopusDrawable octo = new OctopusDrawable(getApplicationContext());
+ octo.setSizePx((int) (OctopusDrawable.randfrange(40f, 180f) * dp));
+ imageView.setImageDrawable(octo);
+ octo.startDrift();
+
+ imageView.setOnTouchListener(new View.OnTouchListener() {
+ boolean touching;
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ switch (motionEvent.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ if (octo.hitTest(motionEvent.getX(), motionEvent.getY())) {
+ touching = true;
+ octo.stopDrift();
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (touching) {
+ octo.moveTo(motionEvent.getX(), motionEvent.getY());
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ touching = false;
+ octo.startDrift();
+ break;
+ }
+ return true;
+ }
+ });
+ }
+}
diff --git a/src/org/lineageos/lineageparts/egg/octo/OctopusDrawable.java b/src/org/lineageos/lineageparts/egg/octo/OctopusDrawable.java
new file mode 100644
index 0000000..fb7089c
--- /dev/null
+++ b/src/org/lineageos/lineageparts/egg/octo/OctopusDrawable.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2017 The LineageOS 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 org.lineageos.lineageparts.egg.octo;
+
+import android.animation.TimeAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.DashPathEffect;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.animation.DynamicAnimation;
+import android.support.animation.SpringForce;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.animation.SpringAnimation;
+import android.support.animation.FloatValueHolder;
+
+import org.lineageos.lineageparts.R;
+
+public class OctopusDrawable extends Drawable {
+ private static final float BASE_SCALE = 100f;
+
+ private static final int BODY_COLOR = 0xFFE0F2F1;
+ private static final int ARM_COLOR = 0xFF212121;
+ private static final int LINE_COLOR = 0xFF212121;
+
+ private static final int[] FRONT_ARMS = {0, 1, 2, 3};
+ // use a bunch of presets for X to get the arms looking just right
+ private static final float[][] ARM_XPOS_FRONT = {
+ {0, -5f, -10f},
+ {1f, -1f, -4f},
+ {-1f, 1f, 4f},
+ {0, 5f, 10f}};
+
+ private Paint mPaint = new Paint();
+ private Arm[] mArms = new Arm[4]; // 8
+ final PointF mCenter = new PointF();
+ private int mSizePx = 100;
+ final Matrix M = new Matrix();
+ final Matrix M_inv = new Matrix();
+ private TimeAnimator mDriftAnimation;
+ private float[] mPtmp = new float[2];
+ private float[] mScaledBounds = new float[2];
+
+ private Drawable mEyeLogo;
+
+ public static float randfrange(float a, float b) {
+ return (float) (Math.random() * (b - a) + a);
+ }
+ public static float clamp(float v, float a, float b) {
+ return v < a ? a : v > b ? b : v;
+ }
+
+ public OctopusDrawable(Context context) {
+ float dp = context.getResources().getDisplayMetrics().density;
+ setSizePx((int)(100 * dp));
+ mPaint.setAntiAlias(true);
+ for (int i = 0; i < mArms.length; i++) {
+ mArms[i] = new Arm(
+ 0, 0, // arm will be repositioned on moveTo
+ ARM_XPOS_FRONT[i][0], 15f,
+ ARM_XPOS_FRONT[i][1], 30f,
+ ARM_XPOS_FRONT[i][2], -5f,
+ 14f, 2f);
+ }
+
+ mEyeLogo = context.getResources().getDrawable(R.drawable.logo_lineage);
+ }
+
+ public void setSizePx(int size) {
+ mSizePx = size;
+ M.setScale(mSizePx / BASE_SCALE, mSizePx / BASE_SCALE);
+ // TaperedPathStroke.setMinStep(20f*BASE_SCALE/mSizePx); // nice little floaty circles
+ TaperedPathStroke.setMinStep(8f * BASE_SCALE / mSizePx); // classic tentacles
+ M.invert(M_inv);
+ }
+
+ public void startDrift() {
+ if (mDriftAnimation == null) {
+ mDriftAnimation = new TimeAnimator();
+ mDriftAnimation.setTimeListener(new TimeAnimator.TimeListener() {
+ static final float MAX_VY = 35f;
+ static final float JUMP_VY = -100f;
+ static final float MAX_VX = 15f;
+ private float ax = 0f, ay = 30f;
+ private float vx, vy;
+ long nextjump = 0;
+
+ @Override
+ public void onTimeUpdate(TimeAnimator timeAnimator, long t, long dt) {
+ float t_sec = 0.001f * t;
+ float dt_sec = 0.001f * dt;
+ if (t > nextjump) {
+ vy = JUMP_VY;
+ nextjump = t + (long) randfrange(5000, 10000);
+ }
+
+ ax = (float) (MAX_VX * Math.sin(t_sec * .25f));
+
+ vx = clamp(vx + dt_sec * ax, -MAX_VX, MAX_VX);
+ vy = clamp(vy + dt_sec * ay, -100 * MAX_VY, MAX_VY);
+
+ // oob check
+ if (mCenter.y - BASE_SCALE / 2 > mScaledBounds[1]) {
+ vy = JUMP_VY;
+ } else if (mCenter.y + BASE_SCALE < 0) {
+ vy = MAX_VY;
+ }
+
+ mCenter.x = clamp(mCenter.x + dt_sec * vx, 0, mScaledBounds[0]);
+ mCenter.y = mCenter.y + dt_sec * vy;
+
+ repositionArms();
+ }
+ });
+ }
+ mDriftAnimation.start();
+ }
+
+ public void stopDrift() {
+ mDriftAnimation.cancel();
+ }
+
+ @Override
+ public void onBoundsChange(Rect bounds) {
+ final float w = bounds.width();
+ final float h = bounds.height();
+
+ lockArms(true);
+ moveTo(w/2, h / 2);
+ lockArms(false);
+
+ mScaledBounds[0] = w;
+ mScaledBounds[1] = h;
+ M_inv.mapPoints(mScaledBounds);
+ }
+
+ // real pixel coordinates
+ public void moveTo(float x, float y) {
+ mCenter.x = x;
+ mCenter.y = y;
+ mapPointF(M_inv, mCenter);
+ repositionArms();
+ }
+
+ public boolean hitTest(float x, float y) {
+ mPtmp[0] = x;
+ mPtmp[1] = y;
+ M_inv.mapPoints(mPtmp);
+ return Math.hypot(mPtmp[0] - mCenter.x, mPtmp[1] - mCenter.y) < BASE_SCALE/2;
+ }
+
+ private void lockArms(boolean l) {
+ for (Arm arm : mArms) {
+ arm.setLocked(l);
+ }
+ }
+
+ private void repositionArms() {
+ for (int i = 0; i < mArms.length; i++) {
+ final float bias = (float)i / (mArms.length - 1) - 0.5f;
+ mArms[i].setAnchor(mCenter.x + bias * 30f, mCenter.y + 26f);
+ }
+ invalidateSelf();
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ canvas.save();
+ {
+ canvas.concat(M);
+
+ // draw the bottom part of the squid, really only the corner rounding is different.
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setColor(BODY_COLOR);
+ canvas.drawRoundRect(mCenter.x - 23f, mCenter.y - 10f, mCenter.x + 23f, mCenter.y + 25f,
+ 10f, 10f, mPaint);
+ // draw the body outline
+ mPaint.setColor(LINE_COLOR);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setStrokeWidth(4f);
+ canvas.drawRoundRect(mCenter.x - 23f, mCenter.y - 10f, mCenter.x + 23f, mCenter.y + 25f,
+ 10f, 10f, mPaint);
+
+ // draw the top part of our squid then clip out the bottom part.
+ canvas.save();
+ {
+ canvas.clipOutRect(mCenter.x - 28f, mCenter.y + 5f,
+ mCenter.x + 28f, mCenter.y + 30f);
+
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setColor(BODY_COLOR);
+ canvas.drawRoundRect(mCenter.x - 23f, mCenter.y - 21f,
+ mCenter.x + 23f, mCenter.y + 25f, 16f, 15f, mPaint);
+
+ mPaint.setColor(LINE_COLOR);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setStrokeWidth(4f);
+ canvas.drawRoundRect(mCenter.x - 23f, mCenter.y - 21f,
+ mCenter.x + 23f, mCenter.y + 25f, 16f, 15f, mPaint);
+ }
+ canvas.restore();
+
+ // draw our logo drawable and translate it to the squid's position. Aspect 2:1
+ canvas.save();
+ {
+ canvas.translate(mCenter.x - 23f, mCenter.y - 2f);
+ mEyeLogo.setBounds(0, 0, 46, 23);
+ mEyeLogo.draw(canvas);
+ }
+ canvas.restore();
+
+ // arms in front
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setColor(ARM_COLOR);
+ for (int i : FRONT_ARMS) {
+ mArms[i].draw(canvas, mPaint);
+ }
+
+ }
+ canvas.restore();
+ }
+
+ // Unused. We must implement because inherited drawable class expects it
+ @Override
+ public void setAlpha(int i) {
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ static Path pathMoveTo(Path p, PointF pt) {
+ p.moveTo(pt.x, pt.y);
+ return p;
+ }
+
+ static Path pathQuadTo(Path p, PointF p1, PointF p2) {
+ p.quadTo(p1.x, p1.y, p2.x, p2.y);
+ return p;
+ }
+
+ static void mapPointF(Matrix m, PointF point) {
+ float[] p = new float[2];
+ p[0] = point.x;
+ p[1] = point.y;
+ m.mapPoints(p);
+ point.x = p[0];
+ point.y = p[1];
+ }
+
+ // he come to town
+ private class Link implements DynamicAnimation.OnAnimationUpdateListener {
+ final FloatValueHolder[] coords = new FloatValueHolder[2];
+ final SpringAnimation[] anims = new SpringAnimation[coords.length];
+ private float dx, dy;
+ private boolean locked = false;
+ Link next;
+
+ Link(int index, float x1, float y1, float dx, float dy) {
+ coords[0] = new FloatValueHolder(x1);
+ coords[1] = new FloatValueHolder(y1);
+ this.dx = dx;
+ this.dy = dy;
+ for (int i = 0; i < coords.length; i++) {
+ anims[i] = new SpringAnimation(coords[i]);
+ anims[i].setSpring(new SpringForce()
+ .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ .setStiffness(
+ index == 0 ? SpringForce.STIFFNESS_LOW
+ : index == 1 ? SpringForce.STIFFNESS_VERY_LOW
+ : SpringForce.STIFFNESS_VERY_LOW / 2)
+ .setFinalPosition(0f));
+ anims[i].addUpdateListener(this);
+ }
+ }
+
+ public void setLocked(boolean locked) {
+ this.locked = locked;
+ }
+
+ public PointF start() {
+ return new PointF(coords[0].getValue(), coords[1].getValue());
+ }
+
+ public PointF end() {
+ return new PointF(coords[0].getValue() + dx, coords[1].getValue() + dy);
+ }
+
+ public PointF mid() {
+ return new PointF(
+ 0.5f * dx + (coords[0].getValue()),
+ 0.5f * dy + (coords[1].getValue()));
+ }
+
+ public void animateTo(PointF target) {
+ if (locked) {
+ setStart(target.x, target.y);
+ } else {
+ anims[0].animateToFinalPosition(target.x);
+ anims[1].animateToFinalPosition(target.y);
+ }
+ }
+
+ @Override
+ public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float v, float v1) {
+ if (next != null) {
+ next.animateTo(end());
+ }
+ OctopusDrawable.this.invalidateSelf();
+ }
+
+ public void setStart(float x, float y) {
+ coords[0].setValue(x);
+ coords[1].setValue(y);
+ onAnimationUpdate(null, 0, 0);
+ }
+ }
+
+ private class Arm {
+ final Link link1, link2, link3;
+ float max, min;
+
+ public Arm(float x, float y, float dx1, float dy1, float dx2, float dy2,
+ float dx3, float dy3, float max, float min) {
+ link1 = new Link(0, x, y, dx1, dy1);
+ link2 = new Link(1, x + dx1, y + dy1, dx2, dy2);
+ link3 = new Link(2, x + dx1 + dx2, y + dy1 + dy2, dx3, dy3);
+ link1.next = link2;
+ link2.next = link3;
+
+ link1.setLocked(true);
+ link2.setLocked(false);
+ link3.setLocked(false);
+
+ this.max = max;
+ this.min = min;
+ }
+
+ // when the arm is locked, it moves rigidly, without physics
+ public void setLocked(boolean locked) {
+ link2.setLocked(locked);
+ link3.setLocked(locked);
+ }
+
+ private void setAnchor(float x, float y) {
+ link1.setStart(x, y);
+ }
+
+ public Path getPath() {
+ Path p = new Path();
+ pathMoveTo(p, link1.start());
+ pathQuadTo(p, link2.start(), link2.mid());
+ pathQuadTo(p, link2.end(), link3.end());
+ return p;
+ }
+
+ public void draw(@NonNull Canvas canvas, Paint pt) {
+ final Path p = getPath();
+ TaperedPathStroke.drawPath(canvas, p, max, min, pt);
+ }
+
+ }
+}
diff --git a/src/org/lineageos/lineageparts/egg/octo/TaperedPathStroke.java b/src/org/lineageos/lineageparts/egg/octo/TaperedPathStroke.java
new file mode 100644
index 0000000..68bd233
--- /dev/null
+++ b/src/org/lineageos/lineageparts/egg/octo/TaperedPathStroke.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2017 The LineageOS 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 org.lineageos.lineageparts.egg.octo;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.os.Debug;
+
+import java.util.Arrays;
+
+public class TaperedPathStroke {
+ static float sMinStepPx = 4f;
+ static PathMeasure pm = new PathMeasure();
+ static float[] pos = {0, 0};
+ static float[] tan = {0, 0};
+ static float lerp(float t, float a, float b) {
+ return a + t * (b - a);
+ }
+ public static void setMinStep(float px) {
+ sMinStepPx = px;
+ }
+
+ // it's the variable-width brush algorithm from the Markers app, basically
+ public static void drawPath(Canvas c, Path p, float r1, float r2, Paint pt) {
+ pm.setPath(p, false);
+ final float len = pm.getLength();
+ float t = 0;
+ boolean last = false;
+ while (!last) {
+ if (t >= len) {
+ t = len;
+ last = true;
+ }
+ pm.getPosTan(t, pos, tan);
+ // float r = len > 0 ? lerp(t/len, r1, r2) : r1;
+ float r = 3f;
+ c.drawCircle(pos[0], pos[1], r, pt);
+ // walk forward 1/4 radius, not too small though
+ t += Math.max(r * 0.25f, sMinStepPx);
+ }
+ }
+}
diff --git a/src/org/lineageos/lineageparts/logo/PlatLogoActivity.java b/src/org/lineageos/lineageparts/logo/PlatLogoActivity.java
index 5ccb828..819059a 100644
--- a/src/org/lineageos/lineageparts/logo/PlatLogoActivity.java
+++ b/src/org/lineageos/lineageparts/logo/PlatLogoActivity.java
@@ -69,8 +69,7 @@
mImageView.setClickable(true);
mImageView.setOnClickListener(this);
- // Disable until we have an egg we want to launch
- //mImageView.setOnLongClickListener(this);
+ mImageView.setOnLongClickListener(this);
// Enable hardware keyboard input for TV compatibility.
mImageView.setFocusable(true);
@@ -100,7 +99,7 @@
@Override
public void run() {
try {
- startActivity(new Intent(Intent.ACTION_MAIN)
+ startActivity(new Intent("org.lineageos.lineageparts.EASTER_EGG")
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)