Merge "Q card." into qt-dev am: 13de667fa6

am: 59fdc5ca76

Change-Id: Ia448d7b73d88f69ab53b0cd888bd25c242aa6d4f
This commit is contained in:
Daniel Sandler
2019-07-10 21:31:55 -07:00
committed by android-build-merger
21 changed files with 1332 additions and 252 deletions

View File

@@ -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();
}
}
}
}

View File

@@ -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"

View 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>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" />

View 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>

View 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>

View 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>

View 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" />

View 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>

View 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>

View 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>

View 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>

View File

@@ -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>

View File

@@ -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>

View 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)
}
}
}

View 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)
}
}
}