diff options
author | Dan Sandler <dsandler@android.com> | 2019-06-26 01:01:26 -0400 |
---|---|---|
committer | Dan Sandler <dsandler@android.com> | 2019-07-10 15:51:12 -0400 |
commit | a7613376379947f463a34543358e535fc28e30eb (patch) | |
tree | 16cc14ce417c3d242ae94d52bc8d1b6321f8493c | |
parent | 99367a7ba08aac635fd69ce50d8505cde7e04e44 (diff) |
Q card.
(Goodbye, hypno-P and your '90s tech magazine color palette.)
Bug: 123903304
Test: adb shell am start -n android/com.android.internal.app.PlatLogoActivity
Test: adb shell am start -c com.android.internal.category.PLATLOGO -a android.intent.action.MAIN
Test: adb shell am start -n com.android.egg/.paint.PaintActivity # still works
Change-Id: I4865024a14b6a78e7a043c56d2330b5f9dd214c6
21 files changed, 1332 insertions, 252 deletions
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index 57785443919e..157e0a74712b 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -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; - - private class PBackground extends Drawable { - private float maxRadius, radius, x, y, dp; - private int[] palette; - private int darkest; - private float offset; - - 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) { - - } + ImageView mZeroView, mOneView; + BackslashDrawable mBackslash; + int mClicks; + + static final Paint sPaint = new Paint(); + static { + sPaint.setStyle(Paint.Style.STROKE); + sPaint.setStrokeWidth(4f); + sPaint.setStrokeCap(Paint.Cap.SQUARE); + } - @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(); + syncTouchPressure(); + } - bg.randomizePalette(); + @Override + public void onStop() { + syncTouchPressure(); + super.onStop(); + } - 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(); - } - }); + 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(); + } - anim.start(); + @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; + } } - @Override - public void onStop() { - if (anim != null) { - anim.cancel(); - anim = null; + 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(); + } } - super.onStop(); } } + diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f25f93fddb15..119d5ea33dc3 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4656,8 +4656,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" diff --git a/core/res/res/drawable-nodpi/android_logotype.xml b/core/res/res/drawable-nodpi/android_logotype.xml new file mode 100644 index 000000000000..bd298e48ef34 --- /dev/null +++ b/core/res/res/drawable-nodpi/android_logotype.xml @@ -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> diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml index f5bbadcce06b..19a296a0e46b 100644 --- a/core/res/res/drawable-nodpi/platlogo.xml +++ b/core/res/res/drawable-nodpi/platlogo.xml @@ -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> diff --git a/core/res/res/layout/platlogo_layout.xml b/core/res/res/layout/platlogo_layout.xml new file mode 100644 index 000000000000..4a4ad751e421 --- /dev/null +++ b/core/res/res/layout/platlogo_layout.xml @@ -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> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 622e043eaa67..498e60e0405b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3824,9 +3824,13 @@ <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" /> + <java-symbol type="integer" name="config_notificationWarnRemoteViewSizeBytes" /> <java-symbol type="integer" name="config_notificationStripRemoteViewSizeBytes" /> <java-symbol type="string" name="config_factoryResetPackage" /> <java-symbol type="array" name="config_highRefreshRateBlacklist" /> + </resources> diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml index c7dd40d7afdb..7f76a4529963 100644 --- a/packages/EasterEgg/AndroidManifest.xml +++ b/packages/EasterEgg/AndroidManifest.xml @@ -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> diff --git a/packages/EasterEgg/res/drawable/icon_bg.xml b/packages/EasterEgg/res/drawable/icon_bg.xml index c1553ce50946..659f98be4f43 100644 --- a/packages/EasterEgg/res/drawable/icon_bg.xml +++ b/packages/EasterEgg/res/drawable/icon_bg.xml @@ -15,4 +15,4 @@ limitations under the License. --> <color xmlns:android="http://schemas.android.com/apk/res/android" - android:color="#C5E1A5" />
\ No newline at end of file + android:color="@color/q_clue_text" /> diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/p_icon.xml index 2306b7b554c5..2306b7b554c5 100644 --- a/packages/EasterEgg/res/drawable/icon.xml +++ b/packages/EasterEgg/res/drawable/p_icon.xml diff --git a/packages/EasterEgg/res/drawable/pixel_bg.xml b/packages/EasterEgg/res/drawable/pixel_bg.xml new file mode 100644 index 000000000000..4d4a113cce53 --- /dev/null +++ b/packages/EasterEgg/res/drawable/pixel_bg.xml @@ -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>
\ No newline at end of file diff --git a/packages/EasterEgg/res/drawable/q.xml b/packages/EasterEgg/res/drawable/q.xml new file mode 100644 index 000000000000..75baa47e3aa6 --- /dev/null +++ b/packages/EasterEgg/res/drawable/q.xml @@ -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> diff --git a/packages/EasterEgg/res/drawable/q_icon.xml b/packages/EasterEgg/res/drawable/q_icon.xml new file mode 100644 index 000000000000..ef4b0a362043 --- /dev/null +++ b/packages/EasterEgg/res/drawable/q_icon.xml @@ -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> diff --git a/packages/EasterEgg/res/drawable/q_smaller.xml b/packages/EasterEgg/res/drawable/q_smaller.xml new file mode 100644 index 000000000000..c71dff094235 --- /dev/null +++ b/packages/EasterEgg/res/drawable/q_smaller.xml @@ -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" /> diff --git a/packages/EasterEgg/res/layout/activity_quares.xml b/packages/EasterEgg/res/layout/activity_quares.xml new file mode 100644 index 000000000000..dcc90f6f77ae --- /dev/null +++ b/packages/EasterEgg/res/layout/activity_quares.xml @@ -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> diff --git a/packages/EasterEgg/res/values-night/q_colors.xml b/packages/EasterEgg/res/values-night/q_colors.xml new file mode 100644 index 000000000000..191bd944b7dc --- /dev/null +++ b/packages/EasterEgg/res/values-night/q_colors.xml @@ -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>
\ No newline at end of file diff --git a/packages/EasterEgg/res/values/q_colors.xml b/packages/EasterEgg/res/values/q_colors.xml new file mode 100644 index 000000000000..5e92c84fd97d --- /dev/null +++ b/packages/EasterEgg/res/values/q_colors.xml @@ -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> diff --git a/packages/EasterEgg/res/values/q_puzzles.xml b/packages/EasterEgg/res/values/q_puzzles.xml new file mode 100644 index 000000000000..7c2eff152ffe --- /dev/null +++ b/packages/EasterEgg/res/values/q_puzzles.xml @@ -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> diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml index 32dbc97a00fb..b95ec6be4c84 100644 --- a/packages/EasterEgg/res/values/strings.xml +++ b/packages/EasterEgg/res/values/strings.xml @@ -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> diff --git a/packages/EasterEgg/res/values/styles.xml b/packages/EasterEgg/res/values/styles.xml index 44e2ce52aab8..e576526f49b7 100644 --- a/packages/EasterEgg/res/values/styles.xml +++ b/packages/EasterEgg/res/values/styles.xml @@ -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> diff --git a/packages/EasterEgg/src/com/android/egg/quares/Quare.kt b/packages/EasterEgg/src/com/android/egg/quares/Quare.kt new file mode 100644 index 000000000000..eb77362a0be2 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/quares/Quare.kt @@ -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) + } + } +} diff --git a/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt b/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt new file mode 100644 index 000000000000..ce439a9a663c --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt @@ -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) + } + } +} |