Merge "Q card." into qt-dev am: 13de667fa6
am: 59fdc5ca76
Change-Id: Ia448d7b73d88f69ab53b0cd888bd25c242aa6d4f
This commit is contained in:
@@ -16,252 +16,167 @@
|
||||
|
||||
package com.android.internal.app;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeAnimator;
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.MotionEvent.PointerCoords;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class PlatLogoActivity extends Activity {
|
||||
FrameLayout layout;
|
||||
TimeAnimator anim;
|
||||
PBackground bg;
|
||||
ImageView mZeroView, mOneView;
|
||||
BackslashDrawable mBackslash;
|
||||
int mClicks;
|
||||
|
||||
private class PBackground extends Drawable {
|
||||
private float maxRadius, radius, x, y, dp;
|
||||
private int[] palette;
|
||||
private int darkest;
|
||||
private float offset;
|
||||
static final Paint sPaint = new Paint();
|
||||
static {
|
||||
sPaint.setStyle(Paint.Style.STROKE);
|
||||
sPaint.setStrokeWidth(4f);
|
||||
sPaint.setStrokeCap(Paint.Cap.SQUARE);
|
||||
}
|
||||
|
||||
public PBackground() {
|
||||
randomizePalette();
|
||||
}
|
||||
|
||||
/**
|
||||
* set inner radius of "p" logo
|
||||
*/
|
||||
public void setRadius(float r) {
|
||||
this.radius = Math.max(48*dp, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* move the "p"
|
||||
*/
|
||||
public void setPosition(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* for animating the "p"
|
||||
*/
|
||||
public void setOffset(float o) {
|
||||
this.offset = o;
|
||||
}
|
||||
|
||||
/**
|
||||
* rough luminance calculation
|
||||
* https://www.w3.org/TR/AERT/#color-contrast
|
||||
*/
|
||||
public float lum(int rgb) {
|
||||
return ((Color.red(rgb) * 299f) + (Color.green(rgb) * 587f) + (Color.blue(rgb) * 114f)) / 1000f;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a random evenly-spaced color palette
|
||||
* guaranteed to contrast!
|
||||
*/
|
||||
public void randomizePalette() {
|
||||
final int slots = 2 + (int)(Math.random() * 2);
|
||||
float[] color = new float[] { (float) Math.random() * 360f, 1f, 1f };
|
||||
palette = new int[slots];
|
||||
darkest = 0;
|
||||
for (int i=0; i<slots; i++) {
|
||||
palette[i] = Color.HSVToColor(color);
|
||||
color[0] = (color[0] + 360f/slots) % 360f;
|
||||
if (lum(palette[i]) < lum(palette[darkest])) darkest = i;
|
||||
}
|
||||
|
||||
final StringBuilder str = new StringBuilder();
|
||||
for (int c : palette) {
|
||||
str.append(String.format("#%08x ", c));
|
||||
}
|
||||
Log.v("PlatLogoActivity", "color palette: " + str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (dp == 0) dp = getResources().getDisplayMetrics().density;
|
||||
final float width = canvas.getWidth();
|
||||
final float height = canvas.getHeight();
|
||||
if (radius == 0) {
|
||||
setPosition(width / 2, height / 2);
|
||||
setRadius(width / 6);
|
||||
}
|
||||
final float inner_w = radius * 0.667f;
|
||||
|
||||
final Paint paint = new Paint();
|
||||
paint.setStrokeCap(Paint.Cap.BUTT);
|
||||
canvas.translate(x, y);
|
||||
|
||||
Path p = new Path();
|
||||
p.moveTo(-radius, height);
|
||||
p.lineTo(-radius, 0);
|
||||
p.arcTo(-radius, -radius, radius, radius, -180, 270, false);
|
||||
p.lineTo(-radius, radius);
|
||||
|
||||
float w = Math.max(canvas.getWidth(), canvas.getHeight()) * 1.414f;
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
|
||||
int i=0;
|
||||
while (w > radius*2 + inner_w*2) {
|
||||
paint.setColor(0xFF000000 | palette[i % palette.length]);
|
||||
// for a slower but more complete version:
|
||||
// paint.setStrokeWidth(w);
|
||||
// canvas.drawPath(p, paint);
|
||||
canvas.drawOval(-w/2, -w/2, w/2, w/2, paint);
|
||||
w -= inner_w * (1.1f + Math.sin((i/20f + offset) * 3.14159f));
|
||||
i++;
|
||||
}
|
||||
|
||||
// the innermost circle needs to be a constant color to avoid rapid flashing
|
||||
paint.setColor(0xFF000000 | palette[(darkest+1) % palette.length]);
|
||||
canvas.drawOval(-radius, -radius, radius, radius, paint);
|
||||
|
||||
p.reset();
|
||||
p.moveTo(-radius, height);
|
||||
p.lineTo(-radius, 0);
|
||||
p.arcTo(-radius, -radius, radius, radius, -180, 270, false);
|
||||
p.lineTo(-radius + inner_w, radius);
|
||||
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(inner_w*2);
|
||||
paint.setColor(palette[darkest]);
|
||||
canvas.drawPath(p, paint);
|
||||
paint.setStrokeWidth(inner_w);
|
||||
paint.setColor(0xFFFFFFFF);
|
||||
canvas.drawPath(p, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return 0;
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (mBackslash != null) {
|
||||
mBackslash.stopAnimating();
|
||||
}
|
||||
mClicks = 0;
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final float dp = getResources().getDisplayMetrics().density;
|
||||
|
||||
layout = new FrameLayout(this);
|
||||
setContentView(layout);
|
||||
getWindow().getDecorView().setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
getWindow().setNavigationBarColor(0);
|
||||
getWindow().setStatusBarColor(0);
|
||||
|
||||
bg = new PBackground();
|
||||
layout.setBackground(bg);
|
||||
getActionBar().hide();
|
||||
|
||||
final ContentResolver cr = getContentResolver();
|
||||
setContentView(R.layout.platlogo_layout);
|
||||
|
||||
layout.setOnTouchListener(new View.OnTouchListener() {
|
||||
final String TOUCH_STATS = "touch.stats";
|
||||
mBackslash = new BackslashDrawable((int) (50 * dp));
|
||||
|
||||
final PointerCoords pc0 = new PointerCoords();
|
||||
final PointerCoords pc1 = new PointerCoords();
|
||||
mOneView = findViewById(R.id.one);
|
||||
mOneView.setImageDrawable(new OneDrawable());
|
||||
mZeroView = findViewById(R.id.zero);
|
||||
mZeroView.setImageDrawable(new ZeroDrawable());
|
||||
|
||||
double pressure_min, pressure_max;
|
||||
int maxPointers;
|
||||
int tapCount;
|
||||
final ViewGroup root = (ViewGroup) mOneView.getParent();
|
||||
root.setClipChildren(false);
|
||||
root.setBackground(mBackslash);
|
||||
root.getBackground().setAlpha(0x20);
|
||||
|
||||
View.OnTouchListener tl = new View.OnTouchListener() {
|
||||
float mOffsetX, mOffsetY;
|
||||
long mClickTime;
|
||||
ObjectAnimator mRotAnim;
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
final float pressure = event.getPressure();
|
||||
measureTouchPressure(event);
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
pressure_min = pressure_max = pressure;
|
||||
// fall through
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (pressure < pressure_min) pressure_min = pressure;
|
||||
if (pressure > pressure_max) pressure_max = pressure;
|
||||
final int pc = event.getPointerCount();
|
||||
if (pc > maxPointers) maxPointers = pc;
|
||||
if (pc > 1) {
|
||||
event.getPointerCoords(0, pc0);
|
||||
event.getPointerCoords(1, pc1);
|
||||
bg.setRadius((float) Math.hypot(pc0.x - pc1.x, pc0.y - pc1.y) / 2f);
|
||||
v.animate().scaleX(1.1f).scaleY(1.1f);
|
||||
v.getParent().bringChildToFront(v);
|
||||
mOffsetX = event.getRawX() - v.getX();
|
||||
mOffsetY = event.getRawY() - v.getY();
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - mClickTime < 350) {
|
||||
mRotAnim = ObjectAnimator.ofFloat(v, View.ROTATION,
|
||||
v.getRotation(), v.getRotation() + 3600);
|
||||
mRotAnim.setDuration(10000);
|
||||
mRotAnim.start();
|
||||
mClickTime = 0;
|
||||
} else {
|
||||
mClickTime = now;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
v.setX(event.getRawX() - mOffsetX);
|
||||
v.setY(event.getRawY() - mOffsetY);
|
||||
v.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
try {
|
||||
final String touchDataJson = Settings.System.getString(cr, TOUCH_STATS);
|
||||
final JSONObject touchData = new JSONObject(
|
||||
touchDataJson != null ? touchDataJson : "{}");
|
||||
if (touchData.has("min")) {
|
||||
pressure_min = Math.min(pressure_min, touchData.getDouble("min"));
|
||||
}
|
||||
if (touchData.has("max")) {
|
||||
pressure_max = Math.max(pressure_max, touchData.getDouble("max"));
|
||||
}
|
||||
touchData.put("min", pressure_min);
|
||||
touchData.put("max", pressure_max);
|
||||
Settings.System.putString(cr, TOUCH_STATS, touchData.toString());
|
||||
} catch (Exception e) {
|
||||
Log.e("PlatLogoActivity", "Can't write touch settings", e);
|
||||
}
|
||||
|
||||
if (maxPointers == 1) {
|
||||
tapCount ++;
|
||||
if (tapCount < 7) {
|
||||
bg.randomizePalette();
|
||||
} else {
|
||||
launchNextStage();
|
||||
}
|
||||
} else {
|
||||
tapCount = 0;
|
||||
}
|
||||
maxPointers = 0;
|
||||
v.performClick();
|
||||
// fall through
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
v.animate().scaleX(1f).scaleY(1f);
|
||||
if (mRotAnim != null) mRotAnim.cancel();
|
||||
testOverlap();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
findViewById(R.id.one).setOnTouchListener(tl);
|
||||
findViewById(R.id.zero).setOnTouchListener(tl);
|
||||
findViewById(R.id.text).setOnTouchListener(tl);
|
||||
}
|
||||
|
||||
private void testOverlap() {
|
||||
final float width = mZeroView.getWidth();
|
||||
final float targetX = mZeroView.getX() + width * .2f;
|
||||
final float targetY = mZeroView.getY() + width * .3f;
|
||||
if (Math.hypot(targetX - mOneView.getX(), targetY - mOneView.getY()) < width * .2f
|
||||
&& Math.abs(mOneView.getRotation() % 360 - 315) < 15) {
|
||||
mOneView.animate().x(mZeroView.getX() + width * .2f);
|
||||
mOneView.animate().y(mZeroView.getY() + width * .3f);
|
||||
mOneView.setRotation(mOneView.getRotation() % 360);
|
||||
mOneView.animate().rotation(315);
|
||||
mOneView.performHapticFeedback(HapticFeedbackConstants.CONFIRM);
|
||||
|
||||
mBackslash.startAnimating();
|
||||
|
||||
mClicks++;
|
||||
if (mClicks >= 7) {
|
||||
launchNextStage();
|
||||
}
|
||||
} else {
|
||||
mBackslash.stopAnimating();
|
||||
}
|
||||
}
|
||||
|
||||
private void launchNextStage() {
|
||||
final ContentResolver cr = getContentResolver();
|
||||
|
||||
if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0) == 0) {
|
||||
if (Settings.System.getLong(cr, "egg_mode" /* Settings.System.EGG_MODE */, 0) == 0) {
|
||||
// For posterity: the moment this user unlocked the easter egg
|
||||
try {
|
||||
Settings.System.putLong(cr,
|
||||
Settings.System.EGG_MODE,
|
||||
"egg_mode", // Settings.System.EGG_MODE,
|
||||
System.currentTimeMillis());
|
||||
} catch (RuntimeException e) {
|
||||
Log.e("PlatLogoActivity", "Can't write settings", e);
|
||||
Log.e("com.android.internal.app.PlatLogoActivity", "Can't write settings", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
@@ -270,36 +185,206 @@ public class PlatLogoActivity extends Activity {
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.addCategory("com.android.internal.category.PLATLOGO"));
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
Log.e("PlatLogoActivity", "No more eggs.");
|
||||
Log.e("com.android.internal.app.PlatLogoActivity", "No more eggs.");
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
static final String TOUCH_STATS = "touch.stats";
|
||||
double mPressureMin = 0, mPressureMax = -1;
|
||||
|
||||
private void measureTouchPressure(MotionEvent event) {
|
||||
final float pressure = event.getPressure();
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (mPressureMax < 0) {
|
||||
mPressureMin = mPressureMax = pressure;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (pressure < mPressureMin) mPressureMin = pressure;
|
||||
if (pressure > mPressureMax) mPressureMax = pressure;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void syncTouchPressure() {
|
||||
try {
|
||||
final String touchDataJson = Settings.System.getString(
|
||||
getContentResolver(), TOUCH_STATS);
|
||||
final JSONObject touchData = new JSONObject(
|
||||
touchDataJson != null ? touchDataJson : "{}");
|
||||
if (touchData.has("min")) {
|
||||
mPressureMin = Math.min(mPressureMin, touchData.getDouble("min"));
|
||||
}
|
||||
if (touchData.has("max")) {
|
||||
mPressureMax = Math.max(mPressureMax, touchData.getDouble("max"));
|
||||
}
|
||||
if (mPressureMax >= 0) {
|
||||
touchData.put("min", mPressureMin);
|
||||
touchData.put("max", mPressureMax);
|
||||
Settings.System.putString(getContentResolver(), TOUCH_STATS, touchData.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("com.android.internal.app.PlatLogoActivity", "Can't write touch settings", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
bg.randomizePalette();
|
||||
|
||||
anim = new TimeAnimator();
|
||||
anim.setTimeListener(
|
||||
new TimeAnimator.TimeListener() {
|
||||
@Override
|
||||
public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
|
||||
bg.setOffset((float) totalTime / 60000f);
|
||||
bg.invalidateSelf();
|
||||
}
|
||||
});
|
||||
|
||||
anim.start();
|
||||
syncTouchPressure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (anim != null) {
|
||||
anim.cancel();
|
||||
anim = null;
|
||||
}
|
||||
syncTouchPressure();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
static class ZeroDrawable extends Drawable {
|
||||
int mTintColor;
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
sPaint.setColor(mTintColor | 0xFF000000);
|
||||
|
||||
canvas.save();
|
||||
canvas.scale(canvas.getWidth() / 24f, canvas.getHeight() / 24f);
|
||||
|
||||
canvas.drawCircle(12f, 12f, 10f, sPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) { }
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) { }
|
||||
|
||||
@Override
|
||||
public void setTintList(ColorStateList tint) {
|
||||
mTintColor = tint.getDefaultColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
}
|
||||
|
||||
static class OneDrawable extends Drawable {
|
||||
int mTintColor;
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
sPaint.setColor(mTintColor | 0xFF000000);
|
||||
|
||||
canvas.save();
|
||||
canvas.scale(canvas.getWidth() / 24f, canvas.getHeight() / 24f);
|
||||
|
||||
final Path p = new Path();
|
||||
p.moveTo(12f, 21.83f);
|
||||
p.rLineTo(0f, -19.67f);
|
||||
p.rLineTo(-5f, 0f);
|
||||
canvas.drawPath(p, sPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) { }
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) { }
|
||||
|
||||
@Override
|
||||
public void setTintList(ColorStateList tint) {
|
||||
mTintColor = tint.getDefaultColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
}
|
||||
|
||||
private static class BackslashDrawable extends Drawable implements TimeAnimator.TimeListener {
|
||||
Bitmap mTile;
|
||||
Paint mPaint = new Paint();
|
||||
BitmapShader mShader;
|
||||
TimeAnimator mAnimator = new TimeAnimator();
|
||||
Matrix mMatrix = new Matrix();
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
canvas.drawPaint(mPaint);
|
||||
}
|
||||
|
||||
BackslashDrawable(int width) {
|
||||
mTile = Bitmap.createBitmap(width, width, Bitmap.Config.ALPHA_8);
|
||||
mAnimator.setTimeListener(this);
|
||||
|
||||
final Canvas tileCanvas = new Canvas(mTile);
|
||||
final float w = tileCanvas.getWidth();
|
||||
final float h = tileCanvas.getHeight();
|
||||
|
||||
final Path path = new Path();
|
||||
path.moveTo(0, 0);
|
||||
path.lineTo(w / 2, 0);
|
||||
path.lineTo(w, h / 2);
|
||||
path.lineTo(w, h);
|
||||
path.close();
|
||||
|
||||
path.moveTo(0, h / 2);
|
||||
path.lineTo(w / 2, h);
|
||||
path.lineTo(0, h);
|
||||
path.close();
|
||||
|
||||
final Paint slashPaint = new Paint();
|
||||
slashPaint.setAntiAlias(true);
|
||||
slashPaint.setStyle(Paint.Style.FILL);
|
||||
slashPaint.setColor(0xFF000000);
|
||||
tileCanvas.drawPath(path, slashPaint);
|
||||
|
||||
//mPaint.setColor(0xFF0000FF);
|
||||
mShader = new BitmapShader(mTile, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
|
||||
mPaint.setShader(mShader);
|
||||
}
|
||||
|
||||
public void startAnimating() {
|
||||
if (!mAnimator.isStarted()) {
|
||||
mAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void stopAnimating() {
|
||||
if (mAnimator.isStarted()) {
|
||||
mAnimator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
mPaint.setAlpha(alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) {
|
||||
mPaint.setColorFilter(colorFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
|
||||
if (mShader != null) {
|
||||
mMatrix.postTranslate(deltaTime / 4f, 0);
|
||||
mShader.setLocalMatrix(mMatrix);
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4662,8 +4662,9 @@
|
||||
android:process=":ui">
|
||||
</activity>
|
||||
<activity android:name="com.android.internal.app.PlatLogoActivity"
|
||||
android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
|
||||
android:theme="@style/Theme.DeviceDefault.DayNight"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:icon="@drawable/platlogo"
|
||||
android:process=":ui">
|
||||
</activity>
|
||||
<activity android:name="com.android.internal.app.DisableCarModeActivity"
|
||||
|
||||
42
core/res/res/drawable-nodpi/android_logotype.xml
Normal file
42
core/res/res/drawable-nodpi/android_logotype.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<!--
|
||||
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="290dp"
|
||||
android:height="64dp"
|
||||
android:viewportWidth="290.0"
|
||||
android:viewportHeight="64.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M21.81,28.91c-7.44,0,-12.45,5.85,-12.45,13.37c0,7.52,5.01,13.37,12.45,13.37s12.45,-5.85,12.45,-13.37 C34.26,34.76,29.24,28.91,21.81,28.91 M20.13,20.55c6.02,0,11.03,3.09,13.37,6.43v-5.6l9.19,0l0,41.78l-6.24,0 c-1.63,0,-2.95,-1.32,-2.95,-2.95v-2.65C31.17,60.91,26.15,64,20.14,64C8.69,64,0,54.23,0,42.28C0,30.33,8.69,20.55,20.13,20.55"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M53.13,21.39l9.19,0l0,5.68c2.5,-4.18,7.27,-6.52,12.7,-6.52c9.69,0,15.96,6.85,15.96,17.46l0,25.15l-6.24,0 c-1.63,0,-2.95,-1.32,-2.95,-2.95l0,-20.7c0,-6.6,-3.34,-10.61,-8.69,-10.61c-6.1,0,-10.78,4.76,-10.78,13.7l0,20.55l-6.25,0 c-1.63,0,-2.95,-1.32,-2.95,-2.95L53.13,21.39z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M120.06,28.91c-7.43,0,-12.45,5.85,-12.45,13.37c0,7.52,5.01,13.37,12.45,13.37c7.43,0,12.45,-5.85,12.45,-13.37 C132.51,34.76,127.5,28.91,120.06,28.91 M118.39,20.55c6.02,0,11.03,3.09,13.37,6.43l0,-26.49l9.19,0l0,62.66h-6.24 c-1.63,0,-2.95,-1.32,-2.95,-2.95v-2.65c-2.34,3.34,-7.35,6.43,-13.37,6.43c-11.45,0,-20.14,-9.77,-20.14,-21.72 C98.25,30.33,106.94,20.55,118.39,20.55"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M151.39,21.39l9.19,0v7.44c1.59,-4.76,6.27,-7.86,11.03,-7.86c1.17,0,2.34,0.08,3.59,0.34v9.44c-1.59,-0.5,-2.92,-0.75,-4.59,-0.75 c-5.26,0,-10.03,4.43,-10.03,12.78l0,20.39l-6.24,0c-1.63,0,-2.95,-1.32,-2.95,-2.95L151.39,21.39z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M199.98,55.48c7.35,0,12.53,-5.77,12.53,-13.2c0,-7.44,-5.18,-13.2,-12.53,-13.2c-7.44,0,-12.62,5.77,-12.62,13.2 C187.37,49.71,192.55,55.48,199.98,55.48 M199.98,64c-12.37,0,-21.89,-9.61,-21.89,-21.72c0,-12.12,9.52,-21.73,21.89,-21.73 c12.37,0,21.89,9.61,21.89,21.73C221.87,54.39,212.35,64,199.98,64"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M229.32,21.39l9.19,0l0,41.78l-6.24,0c-1.63,0,-2.95,-1.32,-2.95,-2.95L229.32,21.39z M233.92,12.28 c-3.34,0,-6.18,-2.76,-6.18,-6.18c0,-3.34,2.84,-6.1,6.18,-6.1c3.43,0,6.1,2.76,6.1,6.1C240.02,9.53,237.34,12.28,233.92,12.28"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M267.87,28.91c-7.43,0,-12.45,5.85,-12.45,13.37c0,7.52,5.01,13.37,12.45,13.37c7.44,0,12.45,-5.85,12.45,-13.37 C280.32,34.76,275.31,28.91,267.87,28.91 M266.2,20.55c6.02,0,11.03,3.09,13.37,6.43l0,-26.49l9.19,0l0,62.66l-6.24,0 c-1.63,0,-2.95,-1.32,-2.95,-2.95v-2.65c-2.34,3.34,-7.35,6.43,-13.37,6.43c-11.44,0,-20.14,-9.77,-20.14,-21.72S254.76,20.55,266.2,20.55"/>
|
||||
</vector>
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
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.
|
||||
@@ -13,21 +13,15 @@ Copyright (C) 2018 The Android Open Source Project
|
||||
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:name="vector"
|
||||
android:width="640dp"
|
||||
android:height="640dp"
|
||||
android:viewportWidth="64"
|
||||
android:viewportHeight="64">
|
||||
<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:name="bg"
|
||||
android:pathData="M 27 43 L 32 43 C 38.075 43 43 38.075 43 32 C 43 25.925 38.075 21 32 21 C 25.925 21 21 25.925 21 32 L 21 64"
|
||||
android:strokeColor="#6823a1"
|
||||
android:strokeWidth="16"/>
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19.45,22.89l-10.250001,-10.249999l-2.6599998,2.6599998l-1.77,-1.7600002l4.43,-4.4300003l12.0199995,12.0199995l-1.7699986,1.7600002z"/>
|
||||
<path
|
||||
android:name="fg"
|
||||
android:pathData="M 29 43 L 32 43 C 38.075 43 43 38.075 43 32 C 43 25.925 38.075 21 32 21 C 25.925 21 21 25.925 21 32 L 21 64"
|
||||
android:strokeColor="#ff0000"
|
||||
android:strokeWidth="8"/>
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,6a6,6 0,1 1,-6 6,6 6,0 0,1 6,-6m0,-2.5A8.5,8.5 0,1 0,20.5 12,8.51 8.51,0 0,0 12,3.5Z"/>
|
||||
</vector>
|
||||
|
||||
50
core/res/res/layout/platlogo_layout.xml
Normal file
50
core/res/res/layout/platlogo_layout.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:background="@android:color/transparent">
|
||||
<ImageView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="400dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:translationY="-100dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_marginBottom="-80dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/android_logotype"
|
||||
android:tint="?android:attr/textColorPrimary"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/one"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:layout_below="@id/text"
|
||||
android:layout_alignLeft="@id/text"
|
||||
android:tint="?android:attr/textColorPrimary"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/zero"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_marginRight="34dp"
|
||||
android:layout_below="@id/text"
|
||||
android:layout_alignRight="@id/text"
|
||||
android:tint="?android:attr/textColorPrimary"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
@@ -3823,4 +3823,8 @@
|
||||
|
||||
<java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" />
|
||||
<java-symbol type="bool" name="config_inflateSignalStrength" />
|
||||
|
||||
<java-symbol type="drawable" name="android_logotype" />
|
||||
<java-symbol type="layout" name="platlogo_layout" />
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,40 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.egg"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<uses-sdk android:minSdkVersion="28" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/icon"
|
||||
android:icon="@drawable/q_icon"
|
||||
android:label="@string/app_name">
|
||||
<activity android:name=".quares.QuaresActivity"
|
||||
android:icon="@drawable/q_icon"
|
||||
android:label="@string/q_egg_name"
|
||||
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
|
||||
android:name=".paint.PaintActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@drawable/p_icon"
|
||||
android:label="@string/p_egg_name"
|
||||
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" />
|
||||
|
||||
<!-- <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>
|
||||
</application>
|
||||
|
||||
@@ -15,4 +15,4 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<color xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="#C5E1A5" />
|
||||
android:color="@color/q_clue_text" />
|
||||
|
||||
27
packages/EasterEgg/res/drawable/pixel_bg.xml
Normal file
27
packages/EasterEgg/res/drawable/pixel_bg.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2019 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.
|
||||
-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:exitFadeDuration="100">
|
||||
<item android:state_pressed="true">
|
||||
<shape><solid android:color="@color/red"/></shape>
|
||||
</item>
|
||||
<item android:state_checked="true">
|
||||
<shape><solid android:color="@color/pixel_on"/></shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape><solid android:color="@color/pixel_off"/></shape>
|
||||
</item>
|
||||
</selector>
|
||||
27
packages/EasterEgg/res/drawable/q.xml
Normal file
27
packages/EasterEgg/res/drawable/q.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<!--
|
||||
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="@color/q_icon_fg"
|
||||
android:pathData="M19.45,22.89l-10.250001,-10.249999l-2.6599998,2.6599998l-1.77,-1.7600002l4.43,-4.4300003l12.0199995,12.0199995l-1.7699986,1.7600002z"/>
|
||||
<path
|
||||
android:fillColor="@color/q_icon_fg"
|
||||
android:pathData="M12,6a6,6 0,1 1,-6 6,6 6,0 0,1 6,-6m0,-2.5A8.5,8.5 0,1 0,20.5 12,8.51 8.51,0 0,0 12,3.5Z"/>
|
||||
</vector>
|
||||
19
packages/EasterEgg/res/drawable/q_icon.xml
Normal file
19
packages/EasterEgg/res/drawable/q_icon.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Copyright (C) 2019 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/q_smaller"/>
|
||||
</adaptive-icon>
|
||||
23
packages/EasterEgg/res/drawable/q_smaller.xml
Normal file
23
packages/EasterEgg/res/drawable/q_smaller.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<!--
|
||||
Copyright (C) 2019 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.
|
||||
-->
|
||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:insetBottom="5dp"
|
||||
android:insetLeft="5dp"
|
||||
android:insetRight="5dp"
|
||||
android:insetTop="5dp"
|
||||
android:drawable="@drawable/q" />
|
||||
46
packages/EasterEgg/res/layout/activity_quares.xml
Normal file
46
packages/EasterEgg/res/layout/activity_quares.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2019 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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
tools:context="com.android.egg.quares.QuaresActivity">
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:alignmentMode="alignBounds"
|
||||
android:id="@+id/grid"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/label"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:gravity="center"
|
||||
android:textSize="18dp"
|
||||
android:visibility="gone"
|
||||
android:drawablePadding="8dp"
|
||||
android:padding="12dp"
|
||||
android:backgroundTint="@color/q_clue_bg_correct"
|
||||
android:textColor="@color/q_clue_text"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:elevation="30dp"
|
||||
/>
|
||||
</FrameLayout>
|
||||
22
packages/EasterEgg/res/values-night/q_colors.xml
Normal file
22
packages/EasterEgg/res/values-night/q_colors.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2019 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>
|
||||
<color name="pixel_off">#000000</color>
|
||||
<color name="pixel_on">#FFFFFF</color>
|
||||
|
||||
<color name="q_clue_bg">@color/navy</color>
|
||||
<color name="q_clue_text">@color/tan</color>
|
||||
</resources>
|
||||
31
packages/EasterEgg/res/values/q_colors.xml
Normal file
31
packages/EasterEgg/res/values/q_colors.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2019 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>
|
||||
<color name="emerald">#3ddc84</color>
|
||||
<color name="red">#f8c734</color>
|
||||
<color name="navy">#073042</color>
|
||||
<color name="vapor">#d7effe</color>
|
||||
<color name="tan">#eff7cf</color>
|
||||
|
||||
<color name="pixel_off">#FFFFFF</color>
|
||||
<color name="pixel_on">#000000</color>
|
||||
|
||||
<color name="q_clue_bg">@color/tan</color>
|
||||
<color name="q_clue_text">@color/navy</color>
|
||||
<color name="q_clue_bg_correct">@color/emerald</color>
|
||||
|
||||
<color name="q_icon_fg">@color/emerald</color>
|
||||
</resources>
|
||||
214
packages/EasterEgg/res/values/q_puzzles.xml
Normal file
214
packages/EasterEgg/res/values/q_puzzles.xml
Normal file
@@ -0,0 +1,214 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="puzzles">
|
||||
|
||||
<item>q</item>
|
||||
<item>q</item>
|
||||
<item>q</item>
|
||||
<item>q</item>
|
||||
<item>q</item>
|
||||
|
||||
<item>android:drawable/ic_info</item>
|
||||
|
||||
<item>android:drawable/stat_sys_adb</item>
|
||||
<item>android:drawable/stat_sys_battery</item>
|
||||
<item>android:drawable/stat_sys_phone_call</item>
|
||||
<item>android:drawable/stat_sys_certificate_info</item>
|
||||
<item>android:drawable/stat_sys_data_bluetooth</item>
|
||||
<item>android:drawable/stat_sys_data_usb</item>
|
||||
<item>android:drawable/stat_sys_download</item>
|
||||
<item>android:drawable/stat_sys_gps_on</item>
|
||||
<item>android:drawable/stat_sys_phone_call</item>
|
||||
<item>android:drawable/stat_sys_tether_wifi</item>
|
||||
<item>android:drawable/stat_sys_throttled</item>
|
||||
<item>android:drawable/stat_sys_upload</item>
|
||||
|
||||
<item>android:drawable/stat_notify_car_mode</item>
|
||||
<item>android:drawable/stat_notify_chat</item>
|
||||
<item>android:drawable/stat_notify_disk_full</item>
|
||||
<item>android:drawable/stat_notify_email_generic</item>
|
||||
<item>android:drawable/stat_notify_error</item>
|
||||
<item>android:drawable/stat_notify_gmail</item>
|
||||
<item>android:drawable/stat_notify_missed_call</item>
|
||||
<item>android:drawable/stat_notify_mmcc_indication_icn</item>
|
||||
<item>android:drawable/stat_notify_more</item>
|
||||
<item>android:drawable/stat_notify_rssi_in_range</item>
|
||||
<item>android:drawable/stat_notify_sdcard</item>
|
||||
<item>android:drawable/stat_notify_sdcard_prepare</item>
|
||||
<item>android:drawable/stat_notify_sdcard_usb</item>
|
||||
<item>android:drawable/stat_notify_sim_toolkit</item>
|
||||
<item>android:drawable/stat_notify_sync</item>
|
||||
<item>android:drawable/stat_notify_sync_anim0</item>
|
||||
<item>android:drawable/stat_notify_sync_error</item>
|
||||
<item>android:drawable/stat_notify_voicemail</item>
|
||||
|
||||
<item>android:drawable/ic_audio_alarm</item>
|
||||
<item>android:drawable/ic_audio_alarm_mute</item>
|
||||
<item>android:drawable/ic_bluetooth_share_icon</item>
|
||||
<item>android:drawable/ic_bt_headphones_a2dp</item>
|
||||
<item>android:drawable/ic_bt_headset_hfp</item>
|
||||
<item>android:drawable/ic_bt_hearing_aid</item>
|
||||
<item>android:drawable/ic_bt_laptop</item>
|
||||
<item>android:drawable/ic_bt_misc_hid</item>
|
||||
<item>android:drawable/ic_bt_network_pan</item>
|
||||
<item>android:drawable/ic_bt_pointing_hid</item>
|
||||
<item>android:drawable/ic_corp_badge</item>
|
||||
<item>android:drawable/ic_expand_more</item>
|
||||
<item>android:drawable/ic_faster_emergency</item>
|
||||
<item>android:drawable/ic_file_copy</item>
|
||||
<item>android:drawable/ic_info_outline_24</item>
|
||||
<item>android:drawable/ic_lock</item>
|
||||
<item>android:drawable/ic_lock_bugreport</item>
|
||||
<item>android:drawable/ic_lock_open</item>
|
||||
<item>android:drawable/ic_lock_power_off</item>
|
||||
<item>android:drawable/ic_lockscreen_ime</item>
|
||||
<item>android:drawable/ic_mode_edit</item>
|
||||
<item>android:drawable/ic_phone</item>
|
||||
<item>android:drawable/ic_qs_airplane</item>
|
||||
<item>android:drawable/ic_qs_auto_rotate</item>
|
||||
<item>android:drawable/ic_qs_battery_saver</item>
|
||||
<item>android:drawable/ic_qs_bluetooth</item>
|
||||
<item>android:drawable/ic_qs_dnd</item>
|
||||
<item>android:drawable/ic_qs_flashlight</item>
|
||||
<item>android:drawable/ic_qs_night_display_on</item>
|
||||
<item>android:drawable/ic_restart</item>
|
||||
<item>android:drawable/ic_screenshot</item>
|
||||
<item>android:drawable/ic_settings_bluetooth</item>
|
||||
<item>android:drawable/ic_signal_cellular_0_4_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_0_5_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_1_4_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_1_5_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_2_4_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_2_5_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_3_4_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_3_5_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_4_4_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_4_5_bar</item>
|
||||
<item>android:drawable/ic_signal_cellular_5_5_bar</item>
|
||||
<item>android:drawable/ic_signal_location</item>
|
||||
<item>android:drawable/ic_wifi_signal_0</item>
|
||||
<item>android:drawable/ic_wifi_signal_1</item>
|
||||
<item>android:drawable/ic_wifi_signal_2</item>
|
||||
<item>android:drawable/ic_wifi_signal_3</item>
|
||||
<item>android:drawable/ic_wifi_signal_4</item>
|
||||
<item>android:drawable/perm_group_activity_recognition</item>
|
||||
<item>android:drawable/perm_group_calendar</item>
|
||||
<item>android:drawable/perm_group_call_log</item>
|
||||
<item>android:drawable/perm_group_camera</item>
|
||||
<item>android:drawable/perm_group_contacts</item>
|
||||
<item>android:drawable/perm_group_location</item>
|
||||
<item>android:drawable/perm_group_microphone</item>
|
||||
<item>android:drawable/perm_group_phone_calls</item>
|
||||
<item>android:drawable/perm_group_sensors</item>
|
||||
<item>android:drawable/perm_group_sms</item>
|
||||
<item>android:drawable/perm_group_storage</item>
|
||||
<item>android:drawable/perm_group_visual</item>
|
||||
|
||||
<item>com.android.settings:drawable/ic_add_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_airplanemode_active</item>
|
||||
<item>com.android.settings:drawable/ic_android</item>
|
||||
<item>com.android.settings:drawable/ic_apps</item>
|
||||
<item>com.android.settings:drawable/ic_arrow_back</item>
|
||||
<item>com.android.settings:drawable/ic_arrow_down_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_battery_charging_full</item>
|
||||
<item>com.android.settings:drawable/ic_battery_status_bad_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_battery_status_good_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_battery_status_maybe_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_call_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_cancel</item>
|
||||
<item>com.android.settings:drawable/ic_cast_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_chevron_right_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_data_saver</item>
|
||||
<item>com.android.settings:drawable/ic_delete</item>
|
||||
<item>com.android.settings:drawable/ic_devices_other</item>
|
||||
<item>com.android.settings:drawable/ic_devices_other_opaque_black</item>
|
||||
<item>com.android.settings:drawable/ic_do_not_disturb_on_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_eject_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_expand_less</item>
|
||||
<item>com.android.settings:drawable/ic_expand_more_inverse</item>
|
||||
<item>com.android.settings:drawable/ic_folder_vd_theme_24</item>
|
||||
<item>com.android.settings:drawable/ic_friction_lock_closed</item>
|
||||
<item>com.android.settings:drawable/ic_gray_scale_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_headset_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_help</item>
|
||||
<item>com.android.settings:drawable/ic_local_movies</item>
|
||||
<item>com.android.settings:drawable/ic_lock</item>
|
||||
<item>com.android.settings:drawable/ic_media_stream</item>
|
||||
<item>com.android.settings:drawable/ic_network_cell</item>
|
||||
<item>com.android.settings:drawable/ic_notifications</item>
|
||||
<item>com.android.settings:drawable/ic_notifications_off_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_phone_info</item>
|
||||
<item>com.android.settings:drawable/ic_photo_library</item>
|
||||
<item>com.android.settings:drawable/ic_settings_accessibility</item>
|
||||
<item>com.android.settings:drawable/ic_settings_accounts</item>
|
||||
<item>com.android.settings:drawable/ic_settings_backup</item>
|
||||
<item>com.android.settings:drawable/ic_settings_battery_white</item>
|
||||
<item>com.android.settings:drawable/ic_settings_data_usage</item>
|
||||
<item>com.android.settings:drawable/ic_settings_date_time</item>
|
||||
<item>com.android.settings:drawable/ic_settings_delete</item>
|
||||
<item>com.android.settings:drawable/ic_settings_display_white</item>
|
||||
<item>com.android.settings:drawable/ic_settings_home</item>
|
||||
<item>com.android.settings:drawable/ic_settings_location</item>
|
||||
<item>com.android.settings:drawable/ic_settings_night_display</item>
|
||||
<item>com.android.settings:drawable/ic_settings_open</item>
|
||||
<item>com.android.settings:drawable/ic_settings_print</item>
|
||||
<item>com.android.settings:drawable/ic_settings_privacy</item>
|
||||
<item>com.android.settings:drawable/ic_settings_security_white</item>
|
||||
<item>com.android.settings:drawable/ic_settings_sim</item>
|
||||
<item>com.android.settings:drawable/ic_settings_wireless</item>
|
||||
<item>com.android.settings:drawable/ic_storage</item>
|
||||
<item>com.android.settings:drawable/ic_storage_white</item>
|
||||
<item>com.android.settings:drawable/ic_suggestion_night_display</item>
|
||||
<item>com.android.settings:drawable/ic_sync</item>
|
||||
<item>com.android.settings:drawable/ic_system_update</item>
|
||||
<item>com.android.settings:drawable/ic_videogame_vd_theme_24</item>
|
||||
<item>com.android.settings:drawable/ic_volume_ringer_vibrate</item>
|
||||
<item>com.android.settings:drawable/ic_volume_up_24dp</item>
|
||||
<item>com.android.settings:drawable/ic_vpn_key</item>
|
||||
<item>com.android.settings:drawable/ic_wifi_tethering</item>
|
||||
|
||||
<item>com.android.systemui:drawable/ic_alarm</item>
|
||||
<item>com.android.systemui:drawable/ic_alarm_dim</item>
|
||||
<item>com.android.systemui:drawable/ic_arrow_back</item>
|
||||
<item>com.android.systemui:drawable/ic_bluetooth_connected</item>
|
||||
<item>com.android.systemui:drawable/ic_brightness_thumb</item>
|
||||
<item>com.android.systemui:drawable/ic_camera</item>
|
||||
<item>com.android.systemui:drawable/ic_cast</item>
|
||||
<item>com.android.systemui:drawable/ic_cast_connected</item>
|
||||
<item>com.android.systemui:drawable/ic_cast_connected_fill</item>
|
||||
<item>com.android.systemui:drawable/ic_close_white</item>
|
||||
<item>com.android.systemui:drawable/ic_data_saver</item>
|
||||
<item>com.android.systemui:drawable/ic_data_saver_off</item>
|
||||
<item>com.android.systemui:drawable/ic_drag_handle</item>
|
||||
<item>com.android.systemui:drawable/ic_headset</item>
|
||||
<item>com.android.systemui:drawable/ic_headset_mic</item>
|
||||
<item>com.android.systemui:drawable/ic_hotspot</item>
|
||||
<item>com.android.systemui:drawable/ic_invert_colors</item>
|
||||
<item>com.android.systemui:drawable/ic_location</item>
|
||||
<item>com.android.systemui:drawable/ic_lockscreen_ime</item>
|
||||
<item>com.android.systemui:drawable/ic_notifications_alert</item>
|
||||
<item>com.android.systemui:drawable/ic_notifications_silence</item>
|
||||
<item>com.android.systemui:drawable/ic_power_low</item>
|
||||
<item>com.android.systemui:drawable/ic_power_saver</item>
|
||||
<item>com.android.systemui:drawable/ic_qs_bluetooth_connecting</item>
|
||||
<item>com.android.systemui:drawable/ic_qs_bluetooth_on</item>
|
||||
<item>com.android.systemui:drawable/ic_qs_cancel</item>
|
||||
<item>com.android.systemui:drawable/ic_qs_no_sim</item>
|
||||
<item>com.android.systemui:drawable/ic_screenshot_delete</item>
|
||||
<item>com.android.systemui:drawable/ic_settings</item>
|
||||
<item>com.android.systemui:drawable/ic_swap_vert</item>
|
||||
<item>com.android.systemui:drawable/ic_volume_alarm</item>
|
||||
<item>com.android.systemui:drawable/ic_volume_alarm_mute</item>
|
||||
<item>com.android.systemui:drawable/ic_volume_media</item>
|
||||
<item>com.android.systemui:drawable/ic_volume_media_mute</item>
|
||||
<item>com.android.systemui:drawable/ic_volume_ringer</item>
|
||||
<item>com.android.systemui:drawable/ic_volume_ringer_mute</item>
|
||||
<item>com.android.systemui:drawable/ic_volume_ringer_vibrate</item>
|
||||
<item>com.android.systemui:drawable/ic_volume_voice</item>
|
||||
<item>com.android.systemui:drawable/stat_sys_camera</item>
|
||||
<item>com.android.systemui:drawable/stat_sys_managed_profile_status</item>
|
||||
<item>com.android.systemui:drawable/stat_sys_mic_none</item>
|
||||
<item>com.android.systemui:drawable/stat_sys_vpn_ic</item>
|
||||
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -15,5 +14,11 @@ Copyright (C) 2018 The Android Open Source Project
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<string name="app_name" translatable="false">PAINT.APK</string>
|
||||
<string name="app_name" translatable="false">Android Q 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>
|
||||
</resources>
|
||||
|
||||
@@ -20,4 +20,16 @@
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
</style>
|
||||
|
||||
<style name="QuaresTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||
<item name="android:windowShowWallpaper">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
168
packages/EasterEgg/src/com/android/egg/quares/Quare.kt
Normal file
168
packages/EasterEgg/src/com/android/egg/quares/Quare.kt
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2019 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.quares
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import java.util.ArrayList
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.round
|
||||
|
||||
class Quare(val width: Int, val height: Int, val depth: Int) : Parcelable {
|
||||
private val data: IntArray = IntArray(width * height)
|
||||
private val user: IntArray = data.copyOf()
|
||||
|
||||
private fun loadAndQuantize(bitmap8bpp: Bitmap) {
|
||||
bitmap8bpp.getPixels(data, 0, width, 0, 0, width, height)
|
||||
if (depth == 8) return
|
||||
val s = (255f / depth)
|
||||
for (i in 0 until data.size) {
|
||||
var f = (data[i] ushr 24).toFloat() / s
|
||||
// f = f.pow(0.75f) // gamma adjust for bolder lines
|
||||
f *= 1.25f // brightness adjust for bolder lines
|
||||
f.coerceAtMost(1f)
|
||||
data[i] = (round(f) * s).toInt() shl 24
|
||||
}
|
||||
}
|
||||
|
||||
fun isBlank(): Boolean {
|
||||
return data.sum() == 0
|
||||
}
|
||||
|
||||
fun load(drawable: Drawable) {
|
||||
val resized = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
|
||||
val canvas = Canvas(resized)
|
||||
drawable.setBounds(0, 0, width, height)
|
||||
drawable.setTint(0xFF000000.toInt())
|
||||
drawable.draw(canvas)
|
||||
loadAndQuantize(resized)
|
||||
resized.recycle()
|
||||
}
|
||||
|
||||
fun load(context: Context, icon: Icon) {
|
||||
icon.loadDrawable(context)?.let {
|
||||
load(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun bitmap(): Bitmap {
|
||||
return Bitmap.createBitmap(data, width, height, Bitmap.Config.ALPHA_8)
|
||||
}
|
||||
|
||||
fun getUserMark(x: Int, y: Int): Int {
|
||||
return user[y * width + x] ushr 24
|
||||
}
|
||||
|
||||
fun setUserMark(x: Int, y: Int, v: Int) {
|
||||
user[y * width + x] = v shl 24
|
||||
}
|
||||
|
||||
fun getDataAt(x: Int, y: Int): Int {
|
||||
return data[y * width + x] ushr 24
|
||||
}
|
||||
|
||||
fun check(): Boolean {
|
||||
return data.contentEquals(user)
|
||||
}
|
||||
|
||||
fun check(xSel: Int, ySel: Int): Boolean {
|
||||
val xStart = if (xSel < 0) 0 else xSel
|
||||
val xEnd = if (xSel < 0) width - 1 else xSel
|
||||
val yStart = if (ySel < 0) 0 else ySel
|
||||
val yEnd = if (ySel < 0) height - 1 else ySel
|
||||
for (y in yStart..yEnd)
|
||||
for (x in xStart..xEnd)
|
||||
if (getDataAt(x, y) != getUserMark(x, y)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun errors(): IntArray {
|
||||
return IntArray(width * height) {
|
||||
abs(data[it] - user[it])
|
||||
}
|
||||
}
|
||||
|
||||
fun getRowClue(y: Int): IntArray {
|
||||
return getClue(-1, y)
|
||||
}
|
||||
fun getColumnClue(x: Int): IntArray {
|
||||
return getClue(x, -1)
|
||||
}
|
||||
fun getClue(xSel: Int, ySel: Int): IntArray {
|
||||
val arr = ArrayList<Int>()
|
||||
var len = 0
|
||||
val xStart = if (xSel < 0) 0 else xSel
|
||||
val xEnd = if (xSel < 0) width - 1 else xSel
|
||||
val yStart = if (ySel < 0) 0 else ySel
|
||||
val yEnd = if (ySel < 0) height - 1 else ySel
|
||||
for (y in yStart..yEnd)
|
||||
for (x in xStart..xEnd)
|
||||
if (getDataAt(x, y) != 0) {
|
||||
len++
|
||||
} else if (len > 0) {
|
||||
arr.add(len)
|
||||
len = 0
|
||||
}
|
||||
if (len > 0) arr.add(len)
|
||||
else if (arr.size == 0) arr.add(0)
|
||||
return arr.toIntArray()
|
||||
}
|
||||
|
||||
fun resetUserMarks() {
|
||||
user.forEachIndexed { index, _ -> user[index] = 0 }
|
||||
}
|
||||
|
||||
// Parcelable interface
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(p: Parcel?, flags: Int) {
|
||||
p?.let {
|
||||
p.writeInt(width)
|
||||
p.writeInt(height)
|
||||
p.writeInt(depth)
|
||||
p.writeIntArray(data)
|
||||
p.writeIntArray(user)
|
||||
}
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<Quare> {
|
||||
override fun createFromParcel(p: Parcel?): Quare {
|
||||
return p!!.let {
|
||||
Quare(
|
||||
p.readInt(), // width
|
||||
p.readInt(), // height
|
||||
p.readInt() // depth
|
||||
).also {
|
||||
p.readIntArray(it.data)
|
||||
p.readIntArray(it.user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<Quare?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
312
packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
Normal file
312
packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright 2019 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.quares
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Bundle
|
||||
import android.text.StaticLayout
|
||||
import android.text.TextPaint
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.widget.Button
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.GridLayout
|
||||
|
||||
import java.util.Random
|
||||
|
||||
import com.android.egg.R
|
||||
|
||||
const val TAG = "Quares"
|
||||
|
||||
class QuaresActivity : Activity() {
|
||||
private var q: Quare = Quare(16, 16, 1)
|
||||
private var resId = 0
|
||||
private var resName = ""
|
||||
private var icon: Icon? = null
|
||||
|
||||
private lateinit var label: Button
|
||||
private lateinit var grid: GridLayout
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
|
||||
actionBar?.hide()
|
||||
|
||||
setContentView(R.layout.activity_quares)
|
||||
|
||||
grid = findViewById(R.id.grid)
|
||||
label = findViewById(R.id.label)
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
Log.v(TAG, "restoring puzzle from state")
|
||||
q = savedInstanceState.getParcelable("q") ?: q
|
||||
resId = savedInstanceState.getInt("resId")
|
||||
resName = savedInstanceState.getString("resName", "")
|
||||
loadPuzzle()
|
||||
}
|
||||
|
||||
label.setOnClickListener { newPuzzle() }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (resId == 0) {
|
||||
// lazy init from onCreate
|
||||
newPuzzle()
|
||||
}
|
||||
checkVictory()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
|
||||
outState.putParcelable("q", q)
|
||||
outState.putInt("resId", resId)
|
||||
outState.putString("resName", resName)
|
||||
}
|
||||
|
||||
fun newPuzzle() {
|
||||
Log.v(TAG, "new puzzle...")
|
||||
|
||||
q.resetUserMarks()
|
||||
val oldResId = resId
|
||||
resId = android.R.drawable.stat_sys_warning
|
||||
try {
|
||||
for (tries in 0..3) {
|
||||
val ar = resources.obtainTypedArray(R.array.puzzles)
|
||||
val newName = ar.getString(Random().nextInt(ar.length()))
|
||||
if (newName == null) continue
|
||||
|
||||
Log.v(TAG, "Looking for icon " + newName)
|
||||
|
||||
val pkg = getPackageNameForResourceName(newName)
|
||||
val newId = packageManager.getResourcesForApplication(pkg)
|
||||
.getIdentifier(newName, "drawable", pkg)
|
||||
if (newId == 0) {
|
||||
Log.v(TAG, "oops, " + newName + " doesn't resolve from pkg " + pkg)
|
||||
} else if (newId != oldResId) {
|
||||
// got a good one
|
||||
resId = newId
|
||||
resName = newName
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
Log.v(TAG, "problem loading puzzle, using fallback", e)
|
||||
}
|
||||
loadPuzzle()
|
||||
}
|
||||
|
||||
fun getPackageNameForResourceName(name: String): String {
|
||||
return if (name.contains(":") && !name.startsWith("android:")) {
|
||||
name.substring(0, name.indexOf(":"))
|
||||
} else {
|
||||
packageName
|
||||
}
|
||||
}
|
||||
|
||||
fun checkVictory() {
|
||||
if (q.check()) {
|
||||
val dp = resources.displayMetrics.density
|
||||
|
||||
val label: Button = findViewById(R.id.label)
|
||||
label.text = resName.replace(Regex("^.*/"), "")
|
||||
val drawable = icon?.loadDrawable(this)?.also {
|
||||
it.setBounds(0, 0, (32 * dp).toInt(), (32 * dp).toInt())
|
||||
it.setTint(label.currentTextColor)
|
||||
}
|
||||
label.setCompoundDrawables(drawable, null, null, null)
|
||||
|
||||
label.visibility = VISIBLE
|
||||
} else {
|
||||
label.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
fun loadPuzzle() {
|
||||
Log.v(TAG, "loading " + resName + " at " + q.width + "x" + q.height)
|
||||
|
||||
val dp = resources.displayMetrics.density
|
||||
|
||||
icon = Icon.createWithResource(getPackageNameForResourceName(resName), resId)
|
||||
q.load(this, icon!!)
|
||||
|
||||
if (q.isBlank()) {
|
||||
// this is a really boring puzzle, let's try again
|
||||
resId = 0
|
||||
resName = ""
|
||||
recreate()
|
||||
return
|
||||
}
|
||||
|
||||
grid.removeAllViews()
|
||||
grid.columnCount = q.width + 1
|
||||
grid.rowCount = q.height + 1
|
||||
|
||||
label.visibility = GONE
|
||||
|
||||
val orientation = resources.configuration.orientation
|
||||
|
||||
// clean this up a bit
|
||||
val minSide = resources.configuration.smallestScreenWidthDp - 25 // ish
|
||||
val size = (minSide / (q.height + 0.5) * dp).toInt()
|
||||
|
||||
val sb = StringBuffer()
|
||||
|
||||
for (j in 0 until grid.rowCount) {
|
||||
for (i in 0 until grid.columnCount) {
|
||||
val tv: View
|
||||
val params = GridLayout.LayoutParams().also {
|
||||
it.width = size
|
||||
it.height = size
|
||||
it.setMargins(1, 1, 1, 1)
|
||||
it.rowSpec = GridLayout.spec(GridLayout.UNDEFINED, GridLayout.TOP) // UGH
|
||||
}
|
||||
val x = i - 1
|
||||
val y = j - 1
|
||||
if (i > 0 && j > 0) {
|
||||
if (i == 1 && j > 1) sb.append("\n")
|
||||
sb.append(if (q.getDataAt(x, y) == 0) " " else "X")
|
||||
tv = PixelButton(this)
|
||||
tv.isChecked = q.getUserMark(x, y) != 0
|
||||
tv.setOnClickListener {
|
||||
q.setUserMark(x, y, if (tv.isChecked) 0xFF else 0)
|
||||
val columnCorrect = (grid.getChildAt(i) as? ClueView)?.check(q) ?: false
|
||||
val rowCorrect = (grid.getChildAt(j*(grid.columnCount)) as? ClueView)
|
||||
?.check(q) ?: false
|
||||
if (columnCorrect && rowCorrect) {
|
||||
checkVictory()
|
||||
} else {
|
||||
label.visibility = GONE
|
||||
}
|
||||
}
|
||||
} else if (i == j) { // 0,0
|
||||
tv = View(this)
|
||||
tv.visibility = GONE
|
||||
} else {
|
||||
tv = ClueView(this)
|
||||
if (j == 0) {
|
||||
tv.textRotation = 90f
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
params.height /= 2
|
||||
tv.showText = false
|
||||
} else {
|
||||
params.height = (96 * dp).toInt()
|
||||
}
|
||||
if (x >= 0) {
|
||||
tv.setColumn(q, x)
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
params.width /= 2
|
||||
tv.showText = false
|
||||
} else {
|
||||
params.width = (96 * dp).toInt()
|
||||
}
|
||||
if (y >= 0) {
|
||||
tv.setRow(q, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
grid.addView(tv, params)
|
||||
}
|
||||
}
|
||||
|
||||
Log.v(TAG, "icon: \n" + sb)
|
||||
}
|
||||
}
|
||||
|
||||
class PixelButton(context: Context) : CompoundButton(context) {
|
||||
init {
|
||||
setBackgroundResource(R.drawable.pixel_bg)
|
||||
isClickable = true
|
||||
isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
class ClueView(context: Context) : View(context) {
|
||||
var row: Int = -1
|
||||
var column: Int = -1
|
||||
var textRotation: Float = 0f
|
||||
var text: CharSequence = ""
|
||||
var showText = true
|
||||
val paint: TextPaint
|
||||
val incorrectColor: Int
|
||||
val correctColor: Int
|
||||
|
||||
init {
|
||||
setBackgroundColor(0)
|
||||
paint = TextPaint().also {
|
||||
it.textSize = 14f * context.resources.displayMetrics.density
|
||||
it.color = context.getColor(R.color.q_clue_text)
|
||||
it.typeface = Typeface.DEFAULT_BOLD
|
||||
it.textAlign = Paint.Align.CENTER
|
||||
}
|
||||
incorrectColor = context.getColor(R.color.q_clue_bg)
|
||||
correctColor = context.getColor(R.color.q_clue_bg_correct)
|
||||
}
|
||||
|
||||
fun setRow(q: Quare, row: Int): Boolean {
|
||||
this.row = row
|
||||
this.column = -1
|
||||
this.textRotation = 0f
|
||||
text = q.getRowClue(row).joinToString("-")
|
||||
return check(q)
|
||||
}
|
||||
fun setColumn(q: Quare, column: Int): Boolean {
|
||||
this.column = column
|
||||
this.row = -1
|
||||
this.textRotation = 90f
|
||||
text = q.getColumnClue(column).joinToString("-")
|
||||
return check(q)
|
||||
}
|
||||
fun check(q: Quare): Boolean {
|
||||
val correct = q.check(column, row)
|
||||
setBackgroundColor(if (correct) correctColor else incorrectColor)
|
||||
return correct
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
super.onDraw(canvas)
|
||||
if (!showText) return
|
||||
canvas?.let {
|
||||
val x = canvas.width / 2f
|
||||
val y = canvas.height / 2f
|
||||
var textWidth = canvas.width
|
||||
if (textRotation != 0f) {
|
||||
canvas.rotate(textRotation, x, y)
|
||||
textWidth = canvas.height
|
||||
}
|
||||
val textLayout = StaticLayout.Builder.obtain(
|
||||
text, 0, text.length, paint, textWidth).build()
|
||||
canvas.translate(x, y - textLayout.height / 2)
|
||||
textLayout.draw(canvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user