MISSION UPDATES -- ANDROID 14 -- PLATLOGO
+ MISSION PATCH NOW AVAILABLE --
UPDATE DRIP ACCORDINGLY.
+ STARFIELD OBSERVED AT CURRENT API LEVEL.
+ THROTTLE MAPPED TO TOUCH OR KEYBOARD --
KEYCODE_SPACE, OBVIOUSLY.
+ A HIGH VELOCITY IS REQUIRED FOR LAUNCH --
CAUTION ADVISED.
FURTHER UPDATES EXPECTED.
Bug: 267678663
Test: adb shell am start -n android/com.android.internal.app.PlatLogoActivity
adb shell input keycombination -t 10000 SPACE SPACE
Change-Id: Ib47f36de76d56acc34c63563acadcb8ab71559b9
This commit is contained in:
@@ -16,42 +16,50 @@
|
||||
|
||||
package com.android.internal.app;
|
||||
|
||||
import static android.graphics.PixelFormat.TRANSLUCENT;
|
||||
import static android.os.VibrationEffect.Composition.PRIMITIVE_SPIN;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.CombinedVibration;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Message;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.VibratorManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.AnalogClock;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -59,30 +67,160 @@ import java.time.ZonedDateTime;
|
||||
public class PlatLogoActivity extends Activity {
|
||||
private static final String TAG = "PlatLogoActivity";
|
||||
|
||||
private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s";
|
||||
private static final long LAUNCH_TIME = 5000L;
|
||||
|
||||
private static final String U_EGG_UNLOCK_SETTING = "egg_mode_u";
|
||||
|
||||
private static final float MIN_WARP = 1f;
|
||||
private static final float MAX_WARP = 10f; // after all these years
|
||||
private static final boolean FINISH_AFTER_NEXT_STAGE_LAUNCH = false;
|
||||
|
||||
private SettableAnalogClock mClock;
|
||||
private ImageView mLogo;
|
||||
private BubblesDrawable mBg;
|
||||
private Starfield mStarfield;
|
||||
|
||||
private FrameLayout mLayout;
|
||||
|
||||
private TimeAnimator mAnim;
|
||||
private ObjectAnimator mWarpAnim;
|
||||
private Random mRandom;
|
||||
private float mDp;
|
||||
|
||||
private RumblePack mRumble;
|
||||
|
||||
private boolean mAnimationsEnabled = true;
|
||||
|
||||
private final View.OnTouchListener mTouchListener = new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
measureTouchPressure(event);
|
||||
startWarp();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
stopWarp();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final Runnable mLaunchNextStage = () -> {
|
||||
stopWarp();
|
||||
launchNextStage(false);
|
||||
};
|
||||
|
||||
private final TimeAnimator.TimeListener mTimeListener = new TimeAnimator.TimeListener() {
|
||||
@Override
|
||||
public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
|
||||
mStarfield.update(deltaTime);
|
||||
final float warpFrac = (mStarfield.getWarp() - MIN_WARP) / (MAX_WARP - MIN_WARP);
|
||||
if (mAnimationsEnabled) {
|
||||
mLogo.setTranslationX(mRandom.nextFloat() * warpFrac * 5 * mDp);
|
||||
mLogo.setTranslationY(mRandom.nextFloat() * warpFrac * 5 * mDp);
|
||||
}
|
||||
if (warpFrac > 0f) {
|
||||
mRumble.rumble(warpFrac);
|
||||
}
|
||||
mLayout.postInvalidate();
|
||||
}
|
||||
};
|
||||
|
||||
private class RumblePack implements Handler.Callback {
|
||||
private static final int MSG = 6464;
|
||||
private static final int INTERVAL = 50;
|
||||
|
||||
private final VibratorManager mVibeMan;
|
||||
private final HandlerThread mVibeThread;
|
||||
private final Handler mVibeHandler;
|
||||
private boolean mSpinPrimitiveSupported;
|
||||
|
||||
private long mLastVibe = 0;
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
final float warpFrac = msg.arg1 / 100f;
|
||||
if (mSpinPrimitiveSupported) {
|
||||
if (msg.getWhen() > mLastVibe + INTERVAL) {
|
||||
mLastVibe = msg.getWhen();
|
||||
mVibeMan.vibrate(CombinedVibration.createParallel(
|
||||
VibrationEffect.startComposition()
|
||||
.addPrimitive(PRIMITIVE_SPIN, (float) Math.pow(warpFrac, 3.0))
|
||||
.compose()
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if (mRandom.nextFloat() < warpFrac) {
|
||||
mLogo.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
RumblePack() {
|
||||
mVibeMan = getSystemService(VibratorManager.class);
|
||||
mSpinPrimitiveSupported = mVibeMan.getDefaultVibrator()
|
||||
.areAllPrimitivesSupported(PRIMITIVE_SPIN);
|
||||
|
||||
mVibeThread = new HandlerThread("VibratorThread");
|
||||
mVibeThread.start();
|
||||
mVibeHandler = Handler.createAsync(mVibeThread.getLooper(), this);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mVibeThread.quit();
|
||||
}
|
||||
|
||||
private void rumble(float warpFrac) {
|
||||
if (!mVibeThread.isAlive()) return;
|
||||
|
||||
final Message msg = Message.obtain();
|
||||
msg.what = MSG;
|
||||
msg.arg1 = (int) (warpFrac * 100);
|
||||
mVibeHandler.removeMessages(MSG);
|
||||
mVibeHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
protected void onDestroy() {
|
||||
mRumble.destroy();
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getWindow().setDecorFitsSystemWindows(false);
|
||||
getWindow().setNavigationBarColor(0);
|
||||
getWindow().setStatusBarColor(0);
|
||||
getWindow().getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
|
||||
|
||||
final ActionBar ab = getActionBar();
|
||||
if (ab != null) ab.hide();
|
||||
|
||||
final FrameLayout layout = new FrameLayout(this);
|
||||
try {
|
||||
mAnimationsEnabled = Settings.Global.getFloat(getContentResolver(),
|
||||
Settings.Global.ANIMATOR_DURATION_SCALE) > 0f;
|
||||
} catch (Settings.SettingNotFoundException e) {
|
||||
mAnimationsEnabled = true;
|
||||
}
|
||||
|
||||
mClock = new SettableAnalogClock(this);
|
||||
mRumble = new RumblePack();
|
||||
|
||||
mLayout = new FrameLayout(this);
|
||||
mRandom = new Random();
|
||||
mDp = getResources().getDisplayMetrics().density;
|
||||
mStarfield = new Starfield(mRandom, mDp * 2f);
|
||||
mStarfield.setVelocity(
|
||||
200f * (mRandom.nextFloat() - 0.5f),
|
||||
200f * (mRandom.nextFloat() - 0.5f));
|
||||
mLayout.setBackground(mStarfield);
|
||||
|
||||
final DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||
final float dp = dm.density;
|
||||
@@ -90,22 +228,79 @@ public class PlatLogoActivity extends Activity {
|
||||
final int widgetSize = (int) (minSide * 0.75);
|
||||
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(widgetSize, widgetSize);
|
||||
lp.gravity = Gravity.CENTER;
|
||||
layout.addView(mClock, lp);
|
||||
|
||||
mLogo = new ImageView(this);
|
||||
mLogo.setVisibility(View.GONE);
|
||||
mLogo.setImageResource(R.drawable.platlogo);
|
||||
layout.addView(mLogo, lp);
|
||||
mLogo.setOnTouchListener(mTouchListener);
|
||||
mLogo.requestFocus();
|
||||
mLayout.addView(mLogo, lp);
|
||||
|
||||
mBg = new BubblesDrawable();
|
||||
mBg.setLevel(0);
|
||||
mBg.avoid = widgetSize / 2;
|
||||
mBg.padding = 0.5f * dp;
|
||||
mBg.minR = 1 * dp;
|
||||
layout.setBackground(mBg);
|
||||
layout.setOnLongClickListener(mBg);
|
||||
Log.v(TAG, "Hello");
|
||||
|
||||
setContentView(layout);
|
||||
setContentView(mLayout);
|
||||
}
|
||||
|
||||
private void startAnimating() {
|
||||
mAnim = new TimeAnimator();
|
||||
mAnim.setTimeListener(mTimeListener);
|
||||
mAnim.start();
|
||||
}
|
||||
|
||||
private void stopAnimating() {
|
||||
mAnim.cancel();
|
||||
mAnim = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_SPACE) {
|
||||
if (event.getRepeatCount() == 0) {
|
||||
startWarp();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_SPACE) {
|
||||
stopWarp();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startWarp() {
|
||||
stopWarp();
|
||||
mWarpAnim = ObjectAnimator.ofFloat(mStarfield, "warp", MIN_WARP, MAX_WARP)
|
||||
.setDuration(LAUNCH_TIME);
|
||||
mWarpAnim.start();
|
||||
|
||||
mLogo.postDelayed(mLaunchNextStage, LAUNCH_TIME + 1000L);
|
||||
}
|
||||
|
||||
private void stopWarp() {
|
||||
if (mWarpAnim != null) {
|
||||
mWarpAnim.cancel();
|
||||
mWarpAnim.removeAllListeners();
|
||||
mWarpAnim = null;
|
||||
}
|
||||
mStarfield.setWarp(1f);
|
||||
mLogo.removeCallbacks(mLaunchNextStage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
startAnimating();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
stopWarp();
|
||||
stopAnimating();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private boolean shouldWriteSettings() {
|
||||
@@ -113,38 +308,14 @@ public class PlatLogoActivity extends Activity {
|
||||
}
|
||||
|
||||
private void launchNextStage(boolean locked) {
|
||||
mClock.animate()
|
||||
.alpha(0f).scaleX(0.5f).scaleY(0.5f)
|
||||
.withEndAction(() -> mClock.setVisibility(View.GONE))
|
||||
.start();
|
||||
|
||||
mLogo.setAlpha(0f);
|
||||
mLogo.setScaleX(0.5f);
|
||||
mLogo.setScaleY(0.5f);
|
||||
mLogo.setVisibility(View.VISIBLE);
|
||||
mLogo.animate()
|
||||
.alpha(1f)
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.setInterpolator(new OvershootInterpolator())
|
||||
.start();
|
||||
|
||||
mLogo.postDelayed(() -> {
|
||||
final ObjectAnimator anim = ObjectAnimator.ofInt(mBg, "level", 0, 10000);
|
||||
anim.setInterpolator(new DecelerateInterpolator(1f));
|
||||
anim.start();
|
||||
},
|
||||
500
|
||||
);
|
||||
|
||||
final ContentResolver cr = getContentResolver();
|
||||
|
||||
try {
|
||||
if (shouldWriteSettings()) {
|
||||
Log.v(TAG, "Saving egg unlock=" + locked);
|
||||
Log.v(TAG, "Saving egg locked=" + locked);
|
||||
syncTouchPressure();
|
||||
Settings.System.putLong(cr,
|
||||
S_EGG_UNLOCK_SETTING,
|
||||
U_EGG_UNLOCK_SETTING,
|
||||
locked ? 0 : System.currentTimeMillis());
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
@@ -152,14 +323,18 @@ public class PlatLogoActivity extends Activity {
|
||||
}
|
||||
|
||||
try {
|
||||
startActivity(new Intent(Intent.ACTION_MAIN)
|
||||
final Intent eggActivity = new Intent(Intent.ACTION_MAIN)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.addCategory("com.android.internal.category.PLATLOGO"));
|
||||
.addCategory("com.android.internal.category.PLATLOGO");
|
||||
Log.v(TAG, "launching: " + eggActivity);
|
||||
startActivity(eggActivity);
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
Log.e("com.android.internal.app.PlatLogoActivity", "No more eggs.");
|
||||
}
|
||||
//finish(); // no longer finish upon unlock; it's fun to frob the dial
|
||||
if (FINISH_AFTER_NEXT_STAGE_LAUNCH) {
|
||||
finish(); // we're done here.
|
||||
}
|
||||
}
|
||||
|
||||
static final String TOUCH_STATS = "touch.stats";
|
||||
@@ -217,266 +392,111 @@ public class PlatLogoActivity extends Activity {
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass of AnalogClock that allows the user to flip up the glass and adjust the hands.
|
||||
*/
|
||||
public class SettableAnalogClock extends AnalogClock {
|
||||
private int mOverrideHour = -1;
|
||||
private int mOverrideMinute = -1;
|
||||
private boolean mOverride = false;
|
||||
private static class Starfield extends Drawable {
|
||||
private static final int NUM_STARS = 34; // Build.VERSION_CODES.UPSIDE_DOWN_CAKE
|
||||
|
||||
public SettableAnalogClock(Context context) {
|
||||
super(context);
|
||||
private static final int NUM_PLANES = 2;
|
||||
private final float[] mStars = new float[NUM_STARS * 4];
|
||||
private float mVx, mVy;
|
||||
private long mDt = 0;
|
||||
private final Paint mStarPaint;
|
||||
|
||||
private final Random mRng;
|
||||
private final float mSize;
|
||||
|
||||
private final Rect mSpace = new Rect();
|
||||
private float mWarp = 1f;
|
||||
|
||||
private float mBuffer;
|
||||
|
||||
public void setWarp(float warp) {
|
||||
mWarp = warp;
|
||||
}
|
||||
|
||||
public float getWarp() {
|
||||
return mWarp;
|
||||
}
|
||||
|
||||
Starfield(Random rng, float size) {
|
||||
mRng = rng;
|
||||
mSize = size;
|
||||
mStarPaint = new Paint();
|
||||
mStarPaint.setStyle(Paint.Style.STROKE);
|
||||
mStarPaint.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Instant now() {
|
||||
final Instant realNow = super.now();
|
||||
final ZoneId tz = Clock.systemDefaultZone().getZone();
|
||||
final ZonedDateTime zdTime = realNow.atZone(tz);
|
||||
if (mOverride) {
|
||||
if (mOverrideHour < 0) {
|
||||
mOverrideHour = zdTime.getHour();
|
||||
}
|
||||
return Clock.fixed(zdTime
|
||||
.withHour(mOverrideHour)
|
||||
.withMinute(mOverrideMinute)
|
||||
.withSecond(0)
|
||||
.toInstant(), tz).instant();
|
||||
} else {
|
||||
return realNow;
|
||||
public void onBoundsChange(Rect bounds) {
|
||||
mSpace.set(bounds);
|
||||
mBuffer = mSize * NUM_PLANES * 2 * MAX_WARP;
|
||||
mSpace.inset(-(int) mBuffer, -(int) mBuffer);
|
||||
final float w = mSpace.width();
|
||||
final float h = mSpace.height();
|
||||
for (int i = 0; i < NUM_STARS; i++) {
|
||||
mStars[4 * i] = mRng.nextFloat() * w;
|
||||
mStars[4 * i + 1] = mRng.nextFloat() * h;
|
||||
mStars[4 * i + 2] = mStars[4 * i];
|
||||
mStars[4 * i + 3] = mStars[4 * i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
double toPositiveDegrees(double rad) {
|
||||
return (Math.toDegrees(rad) + 360 - 90) % 360;
|
||||
public void setVelocity(float x, float y) {
|
||||
mVx = x;
|
||||
mVy = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mOverride = true;
|
||||
// pass through
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
measureTouchPressure(ev);
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
final float dtSec = mDt / 1000f;
|
||||
final float dx = (mVx * dtSec * mWarp);
|
||||
final float dy = (mVy * dtSec * mWarp);
|
||||
|
||||
float x = ev.getX();
|
||||
float y = ev.getY();
|
||||
float cx = getWidth() / 2f;
|
||||
float cy = getHeight() / 2f;
|
||||
float angle = (float) toPositiveDegrees(Math.atan2(x - cx, y - cy));
|
||||
final boolean inWarp = mWarp > 1f;
|
||||
|
||||
int minutes = (75 - (int) (angle / 6)) % 60;
|
||||
int minuteDelta = minutes - mOverrideMinute;
|
||||
if (minuteDelta != 0) {
|
||||
if (Math.abs(minuteDelta) > 45 && mOverrideHour >= 0) {
|
||||
int hourDelta = (minuteDelta < 0) ? 1 : -1;
|
||||
mOverrideHour = (mOverrideHour + 24 + hourDelta) % 24;
|
||||
}
|
||||
mOverrideMinute = minutes;
|
||||
if (mOverrideMinute == 0) {
|
||||
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
if (getScaleX() == 1f) {
|
||||
setScaleX(1.05f);
|
||||
setScaleY(1.05f);
|
||||
animate().scaleX(1f).scaleY(1f).setDuration(150).start();
|
||||
}
|
||||
} else {
|
||||
performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
|
||||
}
|
||||
canvas.drawColor(Color.BLACK); // 0xFF16161D);
|
||||
|
||||
onTimeChanged();
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
return true;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mOverrideMinute == 0 && (mOverrideHour % 12) == 1) {
|
||||
Log.v(TAG, "13:00");
|
||||
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
launchNextStage(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String[][] EMOJI_SETS = {
|
||||
{"🍇", "🍈", "🍉", "🍊", "🍋", "🍌", "🍍", "🥭", "🍎", "🍏", "🍐", "🍑",
|
||||
"🍒", "🍓", "🫐", "🥝"},
|
||||
{"😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾"},
|
||||
{"😀", "😃", "😄", "😁", "😆", "😅", "🤣", "😂", "🙂", "🙃", "🫠", "😉", "😊",
|
||||
"😇", "🥰", "😍", "🤩", "😘", "😗", "☺️", "😚", "😙", "🥲", "😋", "😛", "😜",
|
||||
"🤪", "😝", "🤑", "🤗", "🤭", "🫢", "🫣", "🤫", "🤔", "🫡", "🤐", "🤨", "😐",
|
||||
"😑", "😶", "🫥", "😏", "😒", "🙄", "😬", "🤥", "😌", "😔", "😪", "🤤", "😴",
|
||||
"😷"},
|
||||
{ "🤩", "😍", "🥰", "😘", "🥳", "🥲", "🥹" },
|
||||
{ "🫠" },
|
||||
{"💘", "💝", "💖", "💗", "💓", "💞", "💕", "❣", "💔", "❤", "🧡", "💛",
|
||||
"💚", "💙", "💜", "🤎", "🖤", "🤍"},
|
||||
// {"👁", "️🫦", "👁️"}, // this one is too much
|
||||
{"👽", "🛸", "✨", "🌟", "💫", "🚀", "🪐", "🌙", "⭐", "🌍"},
|
||||
{"🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"},
|
||||
{"🐙", "🪸", "🦑", "🦀", "🦐", "🐡", "🦞", "🐠", "🐟", "🐳", "🐋", "🐬", "🫧", "🌊",
|
||||
"🦈"},
|
||||
{"🙈", "🙉", "🙊", "🐵", "🐒"},
|
||||
{"♈", "♉", "♊", "♋", "♌", "♍", "♎", "♏", "♐", "♑", "♒", "♓"},
|
||||
{"🕛", "🕧", "🕐", "🕜", "🕑", "🕝", "🕒", "🕞", "🕓", "🕟", "🕔", "🕠", "🕕", "🕡",
|
||||
"🕖", "🕢", "🕗", "🕣", "🕘", "🕤", "🕙", "🕥", "🕚", "🕦"},
|
||||
{"🌺", "🌸", "💮", "🏵️", "🌼", "🌿"},
|
||||
{"🐢", "✨", "🌟", "👑"}
|
||||
};
|
||||
|
||||
static class Bubble {
|
||||
public float x, y, r;
|
||||
public int color;
|
||||
public String text = null;
|
||||
}
|
||||
|
||||
class BubblesDrawable extends Drawable implements View.OnLongClickListener {
|
||||
private static final int MAX_BUBBS = 2000;
|
||||
|
||||
private final int[] mColorIds = {
|
||||
android.R.color.system_accent3_400,
|
||||
android.R.color.system_accent3_500,
|
||||
android.R.color.system_accent3_600,
|
||||
|
||||
android.R.color.system_accent2_400,
|
||||
android.R.color.system_accent2_500,
|
||||
android.R.color.system_accent2_600,
|
||||
};
|
||||
|
||||
private int[] mColors = new int[mColorIds.length];
|
||||
|
||||
private int mEmojiSet = -1;
|
||||
|
||||
private final Bubble[] mBubbs = new Bubble[MAX_BUBBS];
|
||||
private int mNumBubbs;
|
||||
|
||||
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
public float avoid = 0f;
|
||||
public float padding = 0f;
|
||||
public float minR = 0f;
|
||||
|
||||
BubblesDrawable() {
|
||||
for (int i = 0; i < mColorIds.length; i++) {
|
||||
mColors[i] = getColor(mColorIds[i]);
|
||||
}
|
||||
for (int j = 0; j < mBubbs.length; j++) {
|
||||
mBubbs[j] = new Bubble();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (getLevel() == 0) return;
|
||||
final float f = getLevel() / 10000f;
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mPaint.setTextAlign(Paint.Align.CENTER);
|
||||
int drawn = 0;
|
||||
for (int j = 0; j < mNumBubbs; j++) {
|
||||
if (mBubbs[j].color == 0 || mBubbs[j].r == 0) continue;
|
||||
if (mBubbs[j].text != null) {
|
||||
mPaint.setTextSize(mBubbs[j].r * 1.75f);
|
||||
canvas.drawText(mBubbs[j].text, mBubbs[j].x,
|
||||
mBubbs[j].y + mBubbs[j].r * f * 0.6f, mPaint);
|
||||
} else {
|
||||
mPaint.setColor(mBubbs[j].color);
|
||||
canvas.drawCircle(mBubbs[j].x, mBubbs[j].y, mBubbs[j].r * f, mPaint);
|
||||
}
|
||||
drawn++;
|
||||
}
|
||||
}
|
||||
|
||||
public void chooseEmojiSet() {
|
||||
mEmojiSet = (int) (Math.random() * EMOJI_SETS.length);
|
||||
final String[] emojiSet = EMOJI_SETS[mEmojiSet];
|
||||
for (int j = 0; j < mBubbs.length; j++) {
|
||||
mBubbs[j].text = emojiSet[(int) (Math.random() * emojiSet.length)];
|
||||
}
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onLevelChange(int level) {
|
||||
invalidateSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
randomize();
|
||||
}
|
||||
|
||||
private void randomize() {
|
||||
final float w = getBounds().width();
|
||||
final float h = getBounds().height();
|
||||
final float maxR = Math.min(w, h) / 3f;
|
||||
mNumBubbs = 0;
|
||||
if (avoid > 0f) {
|
||||
mBubbs[mNumBubbs].x = w / 2f;
|
||||
mBubbs[mNumBubbs].y = h / 2f;
|
||||
mBubbs[mNumBubbs].r = avoid;
|
||||
mBubbs[mNumBubbs].color = 0;
|
||||
mNumBubbs++;
|
||||
}
|
||||
for (int j = 0; j < MAX_BUBBS; j++) {
|
||||
// a simple but time-tested bubble-packing algorithm:
|
||||
// 1. pick a spot
|
||||
// 2. shrink the bubble until it is no longer overlapping any other bubble
|
||||
// 3. if the bubble hasn't popped, keep it
|
||||
int tries = 5;
|
||||
while (tries-- > 0) {
|
||||
float x = (float) Math.random() * w;
|
||||
float y = (float) Math.random() * h;
|
||||
float r = Math.min(Math.min(x, w - x), Math.min(y, h - y));
|
||||
|
||||
// shrink radius to fit other bubbs
|
||||
for (int i = 0; i < mNumBubbs; i++) {
|
||||
r = (float) Math.min(r,
|
||||
Math.hypot(x - mBubbs[i].x, y - mBubbs[i].y) - mBubbs[i].r
|
||||
- padding);
|
||||
if (r < minR) break;
|
||||
}
|
||||
|
||||
if (r >= minR) {
|
||||
// we have found a spot for this bubble to live, let's save it and move on
|
||||
r = Math.min(maxR, r);
|
||||
|
||||
mBubbs[mNumBubbs].x = x;
|
||||
mBubbs[mNumBubbs].y = y;
|
||||
mBubbs[mNumBubbs].r = r;
|
||||
mBubbs[mNumBubbs].color = mColors[(int) (Math.random() * mColors.length)];
|
||||
mNumBubbs++;
|
||||
break;
|
||||
}
|
||||
if (mDt > 0 && mDt < 1000) {
|
||||
canvas.translate(
|
||||
-(mBuffer) + mRng.nextFloat() * (mWarp - 1f),
|
||||
-(mBuffer) + mRng.nextFloat() * (mWarp - 1f)
|
||||
);
|
||||
final float w = mSpace.width();
|
||||
final float h = mSpace.height();
|
||||
for (int i = 0; i < NUM_STARS; i++) {
|
||||
final int plane = (int) ((((float) i) / NUM_STARS) * NUM_PLANES) + 1;
|
||||
mStars[4 * i + 2] = (mStars[4 * i + 2] + dx * plane + w) % w;
|
||||
mStars[4 * i + 3] = (mStars[4 * i + 3] + dy * plane + h) % h;
|
||||
mStars[4 * i + 0] = inWarp ? mStars[4 * i + 2] - dx * mWarp * 2 * plane : -100;
|
||||
mStars[4 * i + 1] = inWarp ? mStars[4 * i + 3] - dy * mWarp * 2 * plane : -100;
|
||||
}
|
||||
}
|
||||
Log.v(TAG, String.format("successfully placed %d bubbles (%d%%)",
|
||||
mNumBubbs, (int) (100f * mNumBubbs / MAX_BUBBS)));
|
||||
final int slice = (mStars.length / NUM_PLANES / 4) * 4;
|
||||
for (int p = 0; p < NUM_PLANES; p++) {
|
||||
mStarPaint.setStrokeWidth(mSize * (p + 1));
|
||||
if (inWarp) {
|
||||
canvas.drawLines(mStars, p * slice, slice, mStarPaint);
|
||||
}
|
||||
canvas.drawPoints(mStars, p * slice, slice, mStarPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) { }
|
||||
public void setAlpha(int alpha) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) { }
|
||||
public void setColorFilter(@Nullable ColorFilter colorFilter) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return TRANSLUCENT;
|
||||
return PixelFormat.OPAQUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (getLevel() == 0) return false;
|
||||
chooseEmojiSet();
|
||||
return true;
|
||||
public void update(long dt) {
|
||||
mDt = dt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -13,33 +13,186 @@ Copyright (C) 2021 The Android Open Source Project
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector android:height="128dp"
|
||||
android:width="128dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="256"
|
||||
android:startY="21.81"
|
||||
android:endX="256"
|
||||
android:endY="350.42"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FF073042"/>
|
||||
<item android:offset="1" android:color="#FF073042"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:fillColor="@android:color/system_accent1_400"
|
||||
android:pathData="M11,0.3c0.6,-0.3 1.4,-0.3 2,0l0.6,0.4c0.7,0.4 1.4,0.6 2.2,0.6l0.7,-0.1c0.7,0 1.4,0.3 1.8,0.9l0.3,0.6c0.4,0.7 1,1.2 1.7,1.5L21,4.5c0.7,0.3 1.1,0.9 1.2,1.7v0.7C22.2,7.7 22.5,8.4 23,9l0.4,0.5c0.4,0.6 0.5,1.3 0.2,2l-0.3,0.6c-0.3,0.7 -0.4,1.5 -0.3,2.3l0.1,0.7c0.1,0.7 -0.2,1.4 -0.7,1.9L22,17.5c-0.6,0.5 -1.1,1.1 -1.3,1.9L20.5,20c-0.2,0.7 -0.8,1.2 -1.5,1.4l-0.7,0.1c-0.8,0.2 -1.4,0.5 -2,1.1l-0.5,0.5c-0.5,0.5 -1.3,0.7 -2,0.5l-0.6,-0.2c-0.8,-0.2 -1.5,-0.2 -2.3,0l-0.6,0.2c-0.7,0.2 -1.5,0 -2,-0.5l-0.5,-0.5c-0.5,-0.5 -1.2,-0.9 -2,-1.1L5,21.4c-0.7,-0.2 -1.3,-0.7 -1.5,-1.4l-0.2,-0.7C3.1,18.6 2.6,18 2,17.5l-0.6,-0.4c-0.6,-0.5 -0.8,-1.2 -0.7,-1.9l0.1,-0.7c0.1,-0.8 0,-1.6 -0.3,-2.3l-0.3,-0.6c-0.3,-0.7 -0.2,-1.4 0.2,-2L1,9c0.5,-0.6 0.7,-1.4 0.8,-2.2V6.2C1.9,5.5 2.3,4.8 3,4.5l0.6,-0.3c0.7,-0.3 1.3,-0.9 1.7,-1.5l0.3,-0.6c0.4,-0.6 1.1,-1 1.8,-0.9l0.7,0.1c0.8,0 1.6,-0.2 2.2,-0.6L11,0.3z"
|
||||
/>
|
||||
android:pathData="m195.27,187.64l2.25,-6.69c13.91,78.13 50.84,284.39 50.84,50.33 0,-0.97 0.72,-1.81 1.62,-1.81h12.69c0.9,0 1.62,0.83 1.62,1.8 -0.2,409.91 -69.03,-43.64 -69.03,-43.64Z"
|
||||
android:fillColor="#3ddc84"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M6.3,6.5l3,0l0,12.2"
|
||||
android:strokeWidth="2.22"
|
||||
android:strokeColor="@android:color/system_accent3_800"
|
||||
/>
|
||||
android:pathData="m158.77,180.68l-33.17,57.45c-1.9,3.3 -0.77,7.52 2.53,9.42 3.3,1.9 7.52,0.77 9.42,-2.53l33.59,-58.17c54.27,24.33 116.34,24.33 170.61,0l33.59,58.17c1.97,3.26 6.21,4.3 9.47,2.33 3.17,-1.91 4.26,-5.99 2.47,-9.23l-33.16,-57.45c56.95,-30.97 95.91,-88.64 101.61,-156.76H57.17c5.7,68.12 44.65,125.79 101.61,156.76Z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M12.3,6.5h4l-2,4c2.2,0.3 3.6,2.4 3.3,4.5c-0.3,1.9 -1.9,3.3 -3.8,3.3c-0.5,0 -1,-0.1 -1.4,-0.3"
|
||||
android:strokeWidth="2.22"
|
||||
android:strokeColor="@android:color/system_accent3_800"
|
||||
/>
|
||||
android:pathData="M250.26,187.66L262.17,187.66A2.13,2.13 0,0 1,264.3 189.78L264.3,217.85A2.13,2.13 0,0 1,262.17 219.98L250.26,219.98A2.13,2.13 0,0 1,248.14 217.85L248.14,189.78A2.13,2.13 0,0 1,250.26 187.66z"
|
||||
android:fillColor="#3ddc84"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M6.3,6.5l3,0l0,12.2"
|
||||
android:strokeWidth="0.56"
|
||||
android:strokeColor="@android:color/system_neutral1_100"
|
||||
/>
|
||||
android:pathData="M250.12,170.29L262.32,170.29A1.98,1.98 0,0 1,264.3 172.26L264.3,176.39A1.98,1.98 0,0 1,262.32 178.37L250.12,178.37A1.98,1.98 0,0 1,248.14 176.39L248.14,172.26A1.98,1.98 0,0 1,250.12 170.29z"
|
||||
android:fillColor="#3ddc84"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M12.3,6.5h4l-2,4c2.2,0.3 3.6,2.4 3.3,4.5c-0.3,1.9 -1.9,3.3 -3.8,3.3c-0.5,0 -1,-0.1 -1.4,-0.3"
|
||||
android:strokeWidth="0.56"
|
||||
android:strokeColor="@android:color/system_neutral1_100"
|
||||
/>
|
||||
android:pathData="M171.92,216.82h4.04v4.04h-4.04z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M188.8,275.73h4.04v4.04h-4.04z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M369.04,337.63h4.04v4.04h-4.04z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M285.93,252.22h4.04v4.04h-4.04z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M318.96,218.84h4.04v4.04h-4.04z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M294.05,288.55h4.04v4.04h-4.04z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M330.82,273.31h8.08v8.08h-8.08z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M188.8,298.95h4.04v4.04h-4.04z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M220.14,238.94h8.08v8.08h-8.08z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M272.1,318.9h8.08v8.08h-8.08z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M293.34,349.25h8.08v8.08h-8.08z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M161.05,254.24h8.08v8.08h-8.08z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M378.92,192h8.08v8.08h-8.08z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"/>
|
||||
<path
|
||||
android:pathData="M137.87,323.7h8.08v8.08h-8.08z"
|
||||
android:fillColor="#fff"/>
|
||||
</group>
|
||||
<path
|
||||
android:pathData="M256,256m-200,0a200,200 0,1 1,400 0a200,200 0,1 1,-400 0"
|
||||
android:strokeWidth="56.561"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#f86734"/>
|
||||
<path
|
||||
android:pathData="m256.22,126.57c-6.69,0 -12.12,5.27 -12.12,11.77v14.52c0,1.25 1.02,2.27 2.27,2.27h0c1.25,0 2.27,-1.02 2.27,-2.27v-3.91c0,-2.51 2.04,-4.55 4.55,-4.55h6.06c2.51,0 4.55,2.04 4.55,4.55v3.91c0,1.25 1.02,2.27 2.27,2.27s2.27,-1.02 2.27,-2.27v-14.52c0,-6.5 -5.43,-11.77 -12.12,-11.77Z"
|
||||
android:fillColor="#3ddc84"/>
|
||||
<path
|
||||
android:pathData="m93.34,116.36l3.85,-4.36 29.64,9.76 -4.44,5.03 -6.23,-2.1 -7.86,8.91 2.86,5.92 -4.43,5.03 -13.39,-28.18ZM110.43,122.76l-8.86,-3.02 4.11,8.41 4.76,-5.39Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m153.62,100.85l-21.71,-6.2 10.38,14.38 -5.21,3.76 -16.78,-23.26 4.49,-3.24 21.65,6.19 -10.35,-14.35 5.24,-3.78 16.78,23.26 -4.49,3.24Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m161.46,63.15l8.99,-3.84c7.43,-3.18 15.96,0.12 19.09,7.44 3.13,7.32 -0.38,15.76 -7.81,18.94l-8.99,3.84 -11.28,-26.38ZM179.41,80.26c4.46,-1.91 5.96,-6.72 4.15,-10.96 -1.81,-4.24 -6.33,-6.48 -10.79,-4.57l-3.08,1.32 6.64,15.53 3.08,-1.32Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m204.23,47.57l11.1,-2.2c5.31,-1.05 9.47,2.08 10.4,6.76 0.72,3.65 -0.76,6.37 -4.07,8.34l12.4,10.44 -7.57,1.5 -11.65,-9.76 -1.03,0.2 2.3,11.61 -6.3,1.25 -5.57,-28.14ZM216.78,56.7c1.86,-0.37 3,-1.71 2.68,-3.33 -0.34,-1.7 -1.88,-2.43 -3.74,-2.06l-4.04,0.8 1.07,5.39 4.04,-0.8Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m244.29,55.6c0.13,-8.16 6.86,-14.72 15.06,-14.58 8.16,0.13 14.72,6.9 14.58,15.06s-6.91,14.72 -15.06,14.58c-8.2,-0.13 -14.71,-6.9 -14.58,-15.06ZM267.44,55.98c0.08,-4.64 -3.54,-8.66 -8.18,-8.74 -4.68,-0.08 -8.42,3.82 -8.5,8.47 -0.08,4.65 3.54,8.66 8.22,8.74 4.64,0.08 8.39,-3.82 8.46,-8.47Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m294.39,44.84l6.31,1.23 -5.49,28.16 -6.31,-1.23 5.49,-28.16Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m321.94,51.41l9.14,3.48c7.55,2.88 11.39,11.17 8.56,18.61 -2.83,7.44 -11.22,11.07 -18.77,8.19l-9.14,-3.48 10.22,-26.8ZM322.96,76.19c4.53,1.73 8.95,-0.69 10.6,-5 1.64,-4.3 -0.05,-9.06 -4.58,-10.78l-3.13,-1.19 -6.01,15.78 3.13,1.19Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m381.41,89.24l-4.21,-3.21 3.65,-4.78 9.06,6.91 -17.4,22.81 -4.85,-3.7 13.75,-18.02Z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m397.96,126.37l-9.56,-10.26 3.61,-3.36 22.8,-1.25 3.74,4.02 -12.35,11.51 2.51,2.69 -4.08,3.8 -2.51,-2.69 -4.55,4.24 -4.16,-4.46 4.55,-4.24ZM407.83,117.17l-10.28,0.58 4.49,4.82 5.79,-5.4Z"
|
||||
android:fillColor="#fff"/>
|
||||
</vector>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user