diff options
82 files changed, 2306 insertions, 478 deletions
diff --git a/core/java/android/os/RedactingFileDescriptor.java b/core/java/android/os/RedactingFileDescriptor.java index 4e5eaac3442f..a1ed2146b38e 100644 --- a/core/java/android/os/RedactingFileDescriptor.java +++ b/core/java/android/os/RedactingFileDescriptor.java @@ -35,7 +35,7 @@ import java.util.Arrays; /** * Variant of {@link FileDescriptor} that allows its creator to specify regions - * that should be redacted (appearing as zeros to the reader). + * that should be redacted. * * @hide */ @@ -44,13 +44,16 @@ public class RedactingFileDescriptor { private static final boolean DEBUG = true; private volatile long[] mRedactRanges; + private volatile long[] mFreeOffsets; private FileDescriptor mInner = null; private ParcelFileDescriptor mOuter = null; - private RedactingFileDescriptor(Context context, File file, int mode, long[] redactRanges) + private RedactingFileDescriptor( + Context context, File file, int mode, long[] redactRanges, long[] freeOffsets) throws IOException { mRedactRanges = checkRangesArgument(redactRanges); + mFreeOffsets = freeOffsets; try { try { @@ -88,13 +91,17 @@ public class RedactingFileDescriptor { * * @param file The underlying file to open. * @param mode The {@link ParcelFileDescriptor} mode to open with. - * @param redactRanges List of file offsets that should be redacted, stored + * @param redactRanges List of file ranges that should be redacted, stored * as {@code [start1, end1, start2, end2, ...]}. Start values are * inclusive and end values are exclusive. + * @param freePositions List of file offsets at which the four byte value 'free' should be + * written instead of zeros within parts of the file covered by {@code redactRanges}. + * Non-redacted bytes will not be modified even if covered by a 'free'. This is + * useful for overwriting boxes in ISOBMFF files with padding data. */ public static ParcelFileDescriptor open(Context context, File file, int mode, - long[] redactRanges) throws IOException { - return new RedactingFileDescriptor(context, file, mode, redactRanges).mOuter; + long[] redactRanges, long[] freePositions) throws IOException { + return new RedactingFileDescriptor(context, file, mode, redactRanges, freePositions).mOuter; } /** @@ -169,6 +176,15 @@ public class RedactingFileDescriptor { for (long j = start; j < end; j++) { data[(int) (j - offset)] = 0; } + // Overwrite data at 'free' offsets within the redaction ranges. + for (long freeOffset : mFreeOffsets) { + final long freeEnd = freeOffset + 4; + final long redactFreeStart = Math.max(freeOffset, start); + final long redactFreeEnd = Math.min(freeEnd, end); + for (long j = redactFreeStart; j < redactFreeEnd; j++) { + data[(int) (j - offset)] = (byte) "free".charAt((int) (j - freeOffset)); + } + } } return n; } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index caab00c3863e..775ec9920575 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -300,5 +300,5 @@ interface IWindowSession { /** * Called when the system gesture exclusion has changed. */ - void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects); + oneway void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bf6191ec61eb..1275e46ed421 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -967,6 +967,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ static boolean sBrokenInsetsDispatch; + /** + * Prior to Q, calling + * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} + * did not call update the window format so the opacity of the background was not correctly + * applied to the window. Some applications rely on this misbehavior to work properly. + * <p> + * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is + * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} + * which updates the window format. + * @hide + */ + protected static boolean sBrokenWindowBackground; + /** @hide */ @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @Retention(RetentionPolicy.SOURCE) @@ -5104,6 +5117,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sBrokenInsetsDispatch = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL || targetSdkVersion < Build.VERSION_CODES.Q; + sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; + sCompatibilityDone = true; } } 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/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 4daddfbfb204..8dc47a401580 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -186,6 +186,89 @@ public final class SystemUiDeviceConfigFlags { */ public static final String BRIGHTLINE_FALSING_MANAGER_ENABLED = "brightline_falsing_manager_enabled"; + /** + * (float) Maximum fraction of the screen required to qualify as a real swipe. + */ + public static final String BRIGHTLINE_FALSING_DISTANCE_SCREEN_FRACTION_MAX_DISTANCE = + "brightline_falsing_distance_screen_fraction_max_distance"; + + /** + * (float) Multiplier for swipe velocity to convert it to pixels for a fling. + */ + public static final String BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE = + "brightline_falsing_distance_velcoity_to_distance"; + + /** + * (float) How far, in inches, must a fling travel horizontally to qualify as intentional. + */ + public static final String BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN = + "brightline_falsing_distance_horizontal_fling_threshold_in"; + + /** + * (float) Maximum fraction of the screen required to qualify as a real swipe. + */ + public static final String BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN = + "brightline_falsing_distance_vertical_fling_threshold_in"; + + /** + * (float) How far, in inches, must a continuous swipe travel horizontally to be intentional. + */ + public static final String BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN = + "brightline_falsing_distance_horizontal_swipe_threshold_in"; + + /** + * (float) How far, in inches, must a continuous swipe travel vertically to be intentional. + */ + public static final String BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN = + "brightline_falsing_distance_horizontal_swipe_threshold_in"; + + /** + * (float) Percentage of swipe with the proximity sensor covered that triggers a higher + * swipe distance requirement. + */ + public static final String BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD = + "brightline_falsing_proximity_percent_covered_threshold"; + + /** + * (float) Angle, in radians, that a swipe can vary from horizontal and sill be intentional. + */ + public static final String BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE = + "brightline_falsing_diagonal_horizontal_angle_range"; + + /** + * (float) Angle, in radians, that a swipe can vary from vertical and sill be intentional. + */ + public static final String BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE = + "brightline_falsing_diagonal_horizontal_angle_range"; + + /** + * (float) Distance, in inches, that a swipe is allowed to vary in the horizontal direction for + * horizontal swipes. + */ + public static final String BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE = + "brightline_falsing_zigzag_x_primary_deviance"; + + /** + * (float) Distance, in inches, that a swipe is allowed to vary in the vertical direction for + * vertical swipes. + */ + public static final String BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE = + "brightline_falsing_zigzag_y_primary_deviance"; + + /** + * (float) Distance, in inches, that a swipe is allowed to vary in the horizontal direction for + * horizontal swipes. + */ + public static final String BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE = + "brightline_falsing_zigzag_x_secondary_deviance"; + + /** + * (float) Distance, in inches, that a swipe is allowed to vary in the vertical direction for + * vertical swipes. + */ + public static final String BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE = + "brightline_falsing_zigzag_y_secondary_deviance"; + private SystemUiDeviceConfigFlags() { } } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index fe66cf9aab7d..7c52a40d4494 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -983,13 +983,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind @Override public void setBackgroundDrawable(Drawable background) { - // TODO: This should route through setWindowBackground, but late in the release to make this // change. if (mOriginalBackgroundDrawable != background) { mOriginalBackgroundDrawable = background; updateBackgroundDrawable(); - drawableChanged(); + if (!View.sBrokenWindowBackground) { + drawableChanged(); + } } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index fef4dcd3b9f1..02eed9a7bcf7 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4616,8 +4616,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" @@ -4939,6 +4940,7 @@ <service android:name="com.android.server.autofill.AutofillCompatAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" + android:visibleToInstantApps="true" android:exported="true"> <meta-data android:name="android.accessibilityservice" 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/config.xml b/core/res/res/values/config.xml index f92a58ad471e..eb09d3fa4356 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4162,6 +4162,10 @@ one bar higher than they actually are --> <bool name="config_inflateSignalStrength">false</bool> + <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission + grants, even if the UICC claims that the app should be privileged. See b/138150105 --> + <string-array name="config_restrictedPreinstalledCarrierApps" translatable="false"/> + <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q --> <integer name="config_maxShortcutTargetsPerApp">3</integer> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c10d32cf6807..646c4ce434d3 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3819,4 +3819,9 @@ <java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" /> <java-symbol type="bool" name="config_inflateSignalStrength" /> + <java-symbol type="array" name="config_restrictedPreinstalledCarrierApps" /> + + <java-symbol type="drawable" name="android_logotype" /> + <java-symbol type="layout" name="platlogo_layout" /> + </resources> diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java index d5163e193510..eff4826040f4 100644 --- a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java +++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java @@ -64,7 +64,7 @@ public class RedactingFileDescriptorTest { @Test public void testSingleByte() throws Exception { final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY, - new long[] { 10, 11 }).getFileDescriptor(); + new long[] { 10, 11 }, new long[] {}).getFileDescriptor(); final byte[] buf = new byte[1_000]; assertEquals(buf.length, Os.read(fd, buf, 0, buf.length)); @@ -80,7 +80,7 @@ public class RedactingFileDescriptorTest { @Test public void testRanges() throws Exception { final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY, - new long[] { 100, 200, 300, 400 }).getFileDescriptor(); + new long[] { 100, 200, 300, 400 }, new long[] {}).getFileDescriptor(); final byte[] buf = new byte[10]; assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 90)); @@ -102,7 +102,7 @@ public class RedactingFileDescriptorTest { @Test public void testEntireFile() throws Exception { final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY, - new long[] { 0, 5_000_000 }).getFileDescriptor(); + new long[] { 0, 5_000_000 }, new long[] {}).getFileDescriptor(); try (FileInputStream in = new FileInputStream(fd)) { int val; @@ -115,7 +115,7 @@ public class RedactingFileDescriptorTest { @Test public void testReadWrite() throws Exception { final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, - new long[] { 100, 200, 300, 400 }).getFileDescriptor(); + new long[] { 100, 200, 300, 400 }, new long[] {}).getFileDescriptor(); // Redacted at first final byte[] buf = new byte[10]; @@ -168,4 +168,76 @@ public class RedactingFileDescriptorTest { assertArrayEquals(new long[] { 100, 200 }, removeRange(new long[] { 100, 200 }, 150, 150)); } + + @Test + public void testFreeAtStart() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 10 }, new long[] {1}).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, (byte) 'f', (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0, 0, 0 }, + buf); + } + + @Test + public void testFreeAtOffset() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 10 }, new long[] {3}).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, 0, 0, (byte) 'f', (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0 }, + buf); + } + + @Test + public void testFreeAcrossRedactionStart() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 10 }, new long[] {0}).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0, 0, 0, 0 }, + buf); + } + + @Test + public void testFreeAcrossRedactionEnd() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 3 }, new long[] {2}).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, 0, (byte) 'f', 64, 64, 64, 64, 64, 64, 64 }, + buf); + } + + @Test + public void testFreeOutsideRedaction() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 8 }, new long[] { 8 }).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, 0, 0, 0, 0, 0, 0, 0, 64, 64 }, + buf); + } + + @Test + public void testFreeMultipleRedactions() throws Exception { + final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE, + new long[] { 1, 2, 3, 4 }, new long[] { 0 }).getFileDescriptor(); + + final byte[] buf = new byte[10]; + assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0)); + assertArrayEquals( + new byte[] { 64, (byte) 'r', 64, (byte) 'e', 64, 64, 64, 64, 64, 64 }, + buf); + } } 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) + } + } +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java index 28d5402bf707..52ec1f0bb330 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java @@ -30,7 +30,7 @@ import java.io.PrintWriter; */ @ProvidesInterface(version = FalsingManager.VERSION) public interface FalsingManager { - int VERSION = 1; + int VERSION = 2; void onSucccessfulUnlock(); @@ -103,4 +103,6 @@ public interface FalsingManager { void onTouchEvent(MotionEvent ev, int width, int height); void dump(PrintWriter pw); + + void cleanup(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index b1cba53c4bca..fee2c9b2505a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -540,6 +540,9 @@ public class KeyguardClockSwitch extends RelativeLayout { @Override public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { + if (!sceneRoot.isShown()) { + return null; + } final float cutoff = mCutoff; final int startVisibility = View.INVISIBLE; final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY); @@ -552,6 +555,9 @@ public class KeyguardClockSwitch extends RelativeLayout { @Override public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) { + if (!sceneRoot.isShown()) { + return null; + } final float cutoff = 1f - mCutoff; final int startVisibility = View.VISIBLE; final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index e219e24a8944..af4e61b3f6bc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -89,6 +89,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe private final HashMap<View, PendingIntent> mClickActions; private final ActivityStarter mActivityStarter; private final ConfigurationController mConfigurationController; + private final LayoutTransition mLayoutTransition; private Uri mKeyguardSliceUri; @VisibleForTesting TextView mTitle; @@ -126,16 +127,16 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mActivityStarter = activityStarter; mConfigurationController = configurationController; - LayoutTransition transition = new LayoutTransition(); - transition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2); - transition.setDuration(LayoutTransition.APPEARING, DEFAULT_ANIM_DURATION); - transition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 2); - transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING); - transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); - transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.FAST_OUT_SLOW_IN); - transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT); - transition.setAnimateParentHierarchy(false); - setLayoutTransition(transition); + mLayoutTransition = new LayoutTransition(); + mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2); + mLayoutTransition.setDuration(LayoutTransition.APPEARING, DEFAULT_ANIM_DURATION); + mLayoutTransition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 2); + mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING); + mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); + mLayoutTransition.setInterpolator(LayoutTransition.APPEARING, + Interpolators.FAST_OUT_SLOW_IN); + mLayoutTransition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT); + mLayoutTransition.setAnimateParentHierarchy(false); } @Override @@ -174,6 +175,12 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mConfigurationController.removeCallback(this); } + @Override + public void onVisibilityAggregated(boolean isVisible) { + super.onVisibilityAggregated(isVisible); + setLayoutTransition(isVisible ? mLayoutTransition : null); + } + /** * Returns whether the current visible slice has a title/header. */ @@ -419,6 +426,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe * their desired positions. */ private final Animation.AnimationListener mKeepAwakeListener; + private LayoutTransition mLayoutTransition; private float mDarkAmount; public Row(Context context) { @@ -440,33 +448,41 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe @Override protected void onFinishInflate() { - LayoutTransition transition = new LayoutTransition(); - transition.setDuration(DEFAULT_ANIM_DURATION); + mLayoutTransition = new LayoutTransition(); + mLayoutTransition.setDuration(DEFAULT_ANIM_DURATION); PropertyValuesHolder left = PropertyValuesHolder.ofInt("left", 0, 1); PropertyValuesHolder right = PropertyValuesHolder.ofInt("right", 0, 1); ObjectAnimator changeAnimator = ObjectAnimator.ofPropertyValuesHolder((Object) null, left, right); - transition.setAnimator(LayoutTransition.CHANGE_APPEARING, changeAnimator); - transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeAnimator); - transition.setInterpolator(LayoutTransition.CHANGE_APPEARING, + mLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, changeAnimator); + mLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeAnimator); + mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_APPEARING, Interpolators.ACCELERATE_DECELERATE); - transition.setInterpolator(LayoutTransition.CHANGE_DISAPPEARING, + mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_DISAPPEARING, Interpolators.ACCELERATE_DECELERATE); - transition.setStartDelay(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION); - transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, DEFAULT_ANIM_DURATION); + mLayoutTransition.setStartDelay(LayoutTransition.CHANGE_APPEARING, + DEFAULT_ANIM_DURATION); + mLayoutTransition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, + DEFAULT_ANIM_DURATION); ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f); - transition.setAnimator(LayoutTransition.APPEARING, appearAnimator); - transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN); + mLayoutTransition.setAnimator(LayoutTransition.APPEARING, appearAnimator); + mLayoutTransition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN); ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f); - transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT); - transition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 4); - transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator); + mLayoutTransition.setInterpolator(LayoutTransition.DISAPPEARING, + Interpolators.ALPHA_OUT); + mLayoutTransition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 4); + mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator); - transition.setAnimateParentHierarchy(false); - setLayoutTransition(transition); + mLayoutTransition.setAnimateParentHierarchy(false); + } + + @Override + public void onVisibilityAggregated(boolean isVisible) { + super.onVisibilityAggregated(isVisible); + setLayoutTransition(isVisible ? mLayoutTransition : null); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 9a0e9fc92af6..bd91333100bd 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -46,6 +46,8 @@ public class ImageWallpaper extends WallpaperService { // We delayed destroy render context that subsequent render requests have chance to cancel it. // This is to avoid destroying then recreating render context in a very short time. private static final int DELAY_FINISH_RENDERING = 1000; + private static final int INTERVAL_WAIT_FOR_RENDERING = 100; + private static final int PATIENCE_WAIT_FOR_RENDERING = 10; private HandlerThread mWorker; @Override @@ -80,7 +82,10 @@ public class ImageWallpaper extends WallpaperService { private StatusBarStateController mController; private final Runnable mFinishRenderingTask = this::finishRendering; private final boolean mNeedTransition; + private final Object mMonitor = new Object(); private boolean mNeedRedraw; + // This variable can only be accessed in synchronized block. + private boolean mWaitingForRendering; GLEngine(Context context) { mNeedTransition = ActivityManager.isHighEndGfx() @@ -119,9 +124,30 @@ public class ImageWallpaper extends WallpaperService { @Override public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { - long duration = mNeedTransition || animationDuration != 0 ? animationDuration : 0; + if (!mNeedTransition) return; mWorker.getThreadHandler().post( - () -> mRenderer.updateAmbientMode(inAmbientMode, duration)); + () -> mRenderer.updateAmbientMode(inAmbientMode, animationDuration)); + if (inAmbientMode && animationDuration == 0) { + // This means that we are transiting from home to aod, to avoid + // race condition between window visibility and transition, + // we don't return until the transition is finished. See b/136643341. + waitForBackgroundRendering(); + } + } + + private void waitForBackgroundRendering() { + synchronized (mMonitor) { + try { + mWaitingForRendering = true; + for (int patience = 1; mWaitingForRendering; patience++) { + mMonitor.wait(INTERVAL_WAIT_FOR_RENDERING); + mWaitingForRendering &= patience < PATIENCE_WAIT_FOR_RENDERING; + } + } catch (InterruptedException ex) { + } finally { + mWaitingForRendering = false; + } + } } @Override @@ -178,7 +204,8 @@ public class ImageWallpaper extends WallpaperService { @Override public void preRender() { - mWorker.getThreadHandler().post(this::preRenderInternal); + // This method should only be invoked from worker thread. + preRenderInternal(); } private void preRenderInternal() { @@ -212,7 +239,8 @@ public class ImageWallpaper extends WallpaperService { @Override public void requestRender() { - mWorker.getThreadHandler().post(this::requestRenderInternal); + // This method should only be invoked from worker thread. + requestRenderInternal(); } private void requestRenderInternal() { @@ -234,7 +262,21 @@ public class ImageWallpaper extends WallpaperService { @Override public void postRender() { - mWorker.getThreadHandler().post(this::scheduleFinishRendering); + // This method should only be invoked from worker thread. + notifyWaitingThread(); + scheduleFinishRendering(); + } + + private void notifyWaitingThread() { + synchronized (mMonitor) { + if (mWaitingForRendering) { + try { + mWaitingForRendering = false; + mMonitor.notify(); + } catch (IllegalMonitorStateException ex) { + } + } + } } private void cancelFinishRenderingTask() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java index 6fb6467d07b2..382c5d5c5954 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java @@ -168,6 +168,7 @@ public class FalsingManagerImpl implements FalsingManager { .append("enabled=").append(isEnabled() ? 1 : 0) .append(" mScreenOn=").append(mScreenOn ? 1 : 0) .append(" mState=").append(StatusBarState.toShortString(mState)) + .append(" mShowingAod=").append(mShowingAod ? 1 : 0) .toString() ); } @@ -550,6 +551,14 @@ public class FalsingManagerImpl implements FalsingManager { pw.println(); } + @Override + public void cleanup() { + mSensorManager.unregisterListener(mSensorEventListener); + mContext.getContentResolver().unregisterContentObserver(mSettingsObserver); + Dependency.get(StatusBarStateController.class).removeCallback(mStatusBarStateListener); + KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mKeyguardUpdateCallback); + } + public Uri reportRejectedTouch() { if (mDataCollector.isEnabled()) { return mDataCollector.reportRejectedTouch(); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 3cc8ec9afbb2..eb4edcc45c80 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -65,6 +65,7 @@ public class FalsingManagerProxy implements FalsingManager { public void onPluginConnected(FalsingPlugin plugin, Context context) { FalsingManager pluginFalsingManager = plugin.getFalsingManager(context); if (pluginFalsingManager != null) { + mInternalFalsingManager.cleanup(); mInternalFalsingManager = pluginFalsingManager; } } @@ -91,7 +92,10 @@ public class FalsingManagerProxy implements FalsingManager { @VisibleForTesting public void setupFalsingManager(Context context) { boolean brightlineEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, false); + DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, true); + if (mInternalFalsingManager != null) { + mInternalFalsingManager.cleanup(); + } if (!brightlineEnabled) { mInternalFalsingManager = new FalsingManagerImpl(context); } else { @@ -290,4 +294,9 @@ public class FalsingManagerProxy implements FalsingManager { public void dump(PrintWriter pw) { mInternalFalsingManager.dump(pw); } + + @Override + public void cleanup() { + mInternalFalsingManager.cleanup(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java index 19c46e40f604..fbbba57381c6 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java @@ -44,6 +44,8 @@ public class BrightLineFalsingManager implements FalsingManager { private final SensorManager mSensorManager; private final FalsingDataProvider mDataProvider; private boolean mSessionStarted; + private boolean mShowingAod; + private boolean mScreenOn; private final ExecutorService mBackgroundExecutor = Executors.newSingleThreadExecutor(); @@ -98,10 +100,12 @@ public class BrightLineFalsingManager implements FalsingManager { } private void sessionStart() { - logDebug("Starting Session"); - mSessionStarted = true; - registerSensors(); - mClassifiers.forEach(FalsingClassifier::onSessionStarted); + if (!mSessionStarted && !mShowingAod && mScreenOn) { + logDebug("Starting Session"); + mSessionStarted = true; + registerSensors(); + mClassifiers.forEach(FalsingClassifier::onSessionStarted); + } } private void sessionEnd() { @@ -157,6 +161,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void onSucccessfulUnlock() { + sessionEnd(); } @Override @@ -165,6 +170,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void setShowingAod(boolean showingAod) { + mShowingAod = showingAod; if (showingAod) { sessionEnd(); } else { @@ -249,7 +255,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void onScreenOnFromTouch() { - sessionStart(); + onScreenTurningOn(); } @Override @@ -271,11 +277,13 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void onScreenTurningOn() { + mScreenOn = true; sessionStart(); } @Override public void onScreenOff() { + mScreenOn = false; sessionEnd(); } @@ -309,6 +317,11 @@ public class BrightLineFalsingManager implements FalsingManager { public void dump(PrintWriter printWriter) { } + @Override + public void cleanup() { + unregisterSensors(); + } + static void logDebug(String msg) { logDebug(msg, null); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java index 730907e1fa9c..cc6645415fd8 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java @@ -16,9 +16,13 @@ package com.android.systemui.classifier.brightline; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE; import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE; import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE; +import android.provider.DeviceConfig; + /** * False on swipes that are too close to 45 degrees. * @@ -35,8 +39,20 @@ class DiagonalClassifier extends FalsingClassifier { private static final float ONE_HUNDRED_EIGHTY_DEG = (float) (Math.PI); private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI); + private final float mHorizontalAngleRange; + private final float mVerticalAngleRange; + DiagonalClassifier(FalsingDataProvider dataProvider) { super(dataProvider); + + mHorizontalAngleRange = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE, + HORIZONTAL_ANGLE_RANGE); + mVerticalAngleRange = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE, + VERTICAL_ANGLE_RANGE); } @Override @@ -52,11 +68,11 @@ class DiagonalClassifier extends FalsingClassifier { return false; } - float minAngle = DIAGONAL - HORIZONTAL_ANGLE_RANGE; - float maxAngle = DIAGONAL + HORIZONTAL_ANGLE_RANGE; + float minAngle = DIAGONAL - mHorizontalAngleRange; + float maxAngle = DIAGONAL + mHorizontalAngleRange; if (isVertical()) { - minAngle = DIAGONAL - VERTICAL_ANGLE_RANGE; - maxAngle = DIAGONAL + VERTICAL_ANGLE_RANGE; + minAngle = DIAGONAL - mVerticalAngleRange; + maxAngle = DIAGONAL + mVerticalAngleRange; } return angleBetween(angle, minAngle, maxAngle) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java index 005ee12c4f61..a6a617dc51de 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java @@ -16,6 +16,14 @@ package com.android.systemui.classifier.brightline; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_SCREEN_FRACTION_MAX_DISTANCE; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN; + +import android.provider.DeviceConfig; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -31,12 +39,13 @@ class DistanceClassifier extends FalsingClassifier { private static final float HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN = 3; private static final float VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN = 3; private static final float VELOCITY_TO_DISTANCE = 80f; - private static final float SCREEN_FRACTION_MIN_DISTANCE = 0.8f; + private static final float SCREEN_FRACTION_MAX_DISTANCE = 0.8f; private final float mVerticalFlingThresholdPx; private final float mHorizontalFlingThresholdPx; private final float mVerticalSwipeThresholdPx; private final float mHorizontalSwipeThresholdPx; + private final float mVelocityToDistanceMultiplier; private boolean mDistanceDirty; private DistanceVectors mCachedDistance; @@ -44,18 +53,48 @@ class DistanceClassifier extends FalsingClassifier { DistanceClassifier(FalsingDataProvider dataProvider) { super(dataProvider); + mVelocityToDistanceMultiplier = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE, + VELOCITY_TO_DISTANCE); + + float horizontalFlingThresholdIn = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN, + HORIZONTAL_FLING_THRESHOLD_DISTANCE_IN); + + float verticalFlingThresholdIn = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN, + VERTICAL_FLING_THRESHOLD_DISTANCE_IN); + + float horizontalSwipeThresholdIn = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN, + HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN); + + float verticalSwipeThresholdIn = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN, + VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN); + + float screenFractionMaxDistance = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_DISTANCE_SCREEN_FRACTION_MAX_DISTANCE, + SCREEN_FRACTION_MAX_DISTANCE); + mHorizontalFlingThresholdPx = Math - .min(getWidthPixels() * SCREEN_FRACTION_MIN_DISTANCE, - HORIZONTAL_FLING_THRESHOLD_DISTANCE_IN * getXdpi()); + .min(getWidthPixels() * screenFractionMaxDistance, + horizontalFlingThresholdIn * getXdpi()); mVerticalFlingThresholdPx = Math - .min(getHeightPixels() * SCREEN_FRACTION_MIN_DISTANCE, - VERTICAL_FLING_THRESHOLD_DISTANCE_IN * getYdpi()); + .min(getHeightPixels() * screenFractionMaxDistance, + verticalFlingThresholdIn * getYdpi()); mHorizontalSwipeThresholdPx = Math - .min(getWidthPixels() * SCREEN_FRACTION_MIN_DISTANCE, - HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN * getXdpi()); + .min(getWidthPixels() * screenFractionMaxDistance, + horizontalSwipeThresholdIn * getXdpi()); mVerticalSwipeThresholdPx = Math - .min(getHeightPixels() * SCREEN_FRACTION_MIN_DISTANCE, - VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN * getYdpi()); + .min(getHeightPixels() * screenFractionMaxDistance, + verticalSwipeThresholdIn * getYdpi()); mDistanceDirty = true; } @@ -139,18 +178,18 @@ class DistanceClassifier extends FalsingClassifier { } boolean getPassedFlingThreshold() { - float dX = this.mDx + this.mVx * VELOCITY_TO_DISTANCE; - float dY = this.mDy + this.mVy * VELOCITY_TO_DISTANCE; + float dX = this.mDx + this.mVx * mVelocityToDistanceMultiplier; + float dY = this.mDy + this.mVy * mVelocityToDistanceMultiplier; if (isHorizontal()) { logDebug("Horizontal swipe and fling distance: " + this.mDx + ", " - + this.mVx * VELOCITY_TO_DISTANCE); + + this.mVx * mVelocityToDistanceMultiplier); logDebug("Threshold: " + mHorizontalFlingThresholdPx); return Math.abs(dX) >= mHorizontalFlingThresholdPx; } logDebug("Vertical swipe and fling distance: " + this.mDy + ", " - + this.mVy * VELOCITY_TO_DISTANCE); + + this.mVy * mVelocityToDistanceMultiplier); logDebug("Threshold: " + mVerticalFlingThresholdPx); return Math.abs(dY) >= mVerticalFlingThresholdPx; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java index 94a8ac85b724..2644bf9f26ce 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java @@ -16,10 +16,12 @@ package com.android.systemui.classifier.brightline; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD; import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; import android.hardware.Sensor; import android.hardware.SensorEvent; +import android.provider.DeviceConfig; import android.view.MotionEvent; @@ -31,8 +33,9 @@ import android.view.MotionEvent; */ class ProximityClassifier extends FalsingClassifier { - private static final double PERCENT_COVERED_THRESHOLD = 0.1; + private static final float PERCENT_COVERED_THRESHOLD = 0.1f; private final DistanceClassifier mDistanceClassifier; + private final float mPercentCoveredThreshold; private boolean mNear; private long mGestureStartTimeNs; @@ -44,6 +47,11 @@ class ProximityClassifier extends FalsingClassifier { FalsingDataProvider dataProvider) { super(dataProvider); this.mDistanceClassifier = distanceClassifier; + + mPercentCoveredThreshold = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD, + PERCENT_COVERED_THRESHOLD); } @Override @@ -107,7 +115,7 @@ class ProximityClassifier extends FalsingClassifier { logInfo("Percent of gesture in proximity: " + mPercentNear); - if (mPercentNear > PERCENT_COVERED_THRESHOLD) { + if (mPercentNear > mPercentCoveredThreshold) { return !mDistanceClassifier.isLongSwipe(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java index a62574f26399..c58b7db451b0 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java @@ -16,7 +16,13 @@ package com.android.systemui.classifier.brightline; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE; + import android.graphics.Point; +import android.provider.DeviceConfig; import android.view.MotionEvent; import java.util.ArrayList; @@ -37,8 +43,34 @@ class ZigZagClassifier extends FalsingClassifier { private static final float MAX_X_SECONDARY_DEVIANCE = .3f; private static final float MAX_Y_SECONDARY_DEVIANCE = .3f; + private final float mMaxXPrimaryDeviance; + private final float mMaxYPrimaryDeviance; + private final float mMaxXSecondaryDeviance; + private final float mMaxYSecondaryDeviance; + ZigZagClassifier(FalsingDataProvider dataProvider) { super(dataProvider); + + mMaxXPrimaryDeviance = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE, + MAX_X_PRIMARY_DEVIANCE); + + mMaxYPrimaryDeviance = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE, + MAX_Y_PRIMARY_DEVIANCE); + + mMaxXSecondaryDeviance = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE, + MAX_X_SECONDARY_DEVIANCE); + + mMaxYSecondaryDeviance = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE, + MAX_Y_SECONDARY_DEVIANCE); + } @Override @@ -98,11 +130,11 @@ class ZigZagClassifier extends FalsingClassifier { float maxXDeviance; float maxYDeviance; if (actualDx > actualDy) { - maxXDeviance = MAX_X_PRIMARY_DEVIANCE * totalDistanceIn * getXdpi(); - maxYDeviance = MAX_Y_SECONDARY_DEVIANCE * totalDistanceIn * getYdpi(); + maxXDeviance = mMaxXPrimaryDeviance * totalDistanceIn * getXdpi(); + maxYDeviance = mMaxYSecondaryDeviance * totalDistanceIn * getYdpi(); } else { - maxXDeviance = MAX_X_SECONDARY_DEVIANCE * totalDistanceIn * getXdpi(); - maxYDeviance = MAX_Y_PRIMARY_DEVIANCE * totalDistanceIn * getYdpi(); + maxXDeviance = mMaxXSecondaryDeviance * totalDistanceIn * getXdpi(); + maxYDeviance = mMaxYPrimaryDeviance * totalDistanceIn * getYdpi(); } logDebug("Straightness Deviance: (" + devianceX + "," + devianceY + ") vs " diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 8694d2ad607c..9c2adb36e1ae 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -30,6 +30,7 @@ import com.android.systemui.R; import com.android.systemui.SystemUIApplication; import com.android.systemui.classifier.FalsingManagerFactory; import com.android.systemui.dock.DockManager; +import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.AsyncSensorManager; import com.android.systemui.util.wakelock.DelayedWakeLock; @@ -70,7 +71,7 @@ public class DozeFactory { new DozeScreenState(wrappedService, handler, params, wakeLock), createDozeScreenBrightness(context, wrappedService, sensorManager, host, params, handler), - new DozeWallpaperState(context), + new DozeWallpaperState(context, getBiometricUnlockController(dozeService)), new DozeDockHandler(context, machine, host, config, handler, dockManager) }); @@ -107,4 +108,10 @@ public class DozeFactory { final SystemUIApplication app = (SystemUIApplication) appCandidate; return app.getComponent(DozeHost.class); } + + public static BiometricUnlockController getBiometricUnlockController(DozeService service) { + Application appCandidate = service.getApplication(); + final SystemUIApplication app = (SystemUIApplication) appCandidate; + return app.getComponent(BiometricUnlockController.class); + } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 5f52486b2bc6..a882309c06d4 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -43,6 +43,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; +import com.android.systemui.R; import com.android.systemui.plugins.SensorManagerPlugin; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.AlarmTimeout; @@ -255,12 +256,21 @@ public class DozeSensors { long mLastNear; final AlarmTimeout mCooldownTimer; final AlwaysOnDisplayPolicy mPolicy; - + final Sensor mSensor; public ProxSensor(AlwaysOnDisplayPolicy policy) { mPolicy = policy; mCooldownTimer = new AlarmTimeout(mAlarmManager, this::updateRegistered, "prox_cooldown", mHandler); + + // The default prox sensor can be noisy, so let's use a prox gated brightness sensor + // if available. + Sensor sensor = DozeSensors.findSensorWithType(mSensorManager, + mContext.getString(R.string.doze_brightness_sensor_type)); + if (sensor == null) { + sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + } + mSensor = sensor; } void setRequested(boolean requested) { @@ -324,8 +334,9 @@ public class DozeSensors { @Override public String toString() { - return String.format("{registered=%s, requested=%s, coolingDown=%s, currentlyFar=%s}", - mRegistered, mRequested, mCooldownTimer.isScheduled(), mCurrentlyFar); + return String.format("{registered=%s, requested=%s, coolingDown=%s, currentlyFar=%s," + + " sensor=%s}", mRegistered, mRequested, mCooldownTimer.isScheduled(), + mCurrentlyFar, mSensor); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java index 1b3cd881b949..35c8b741381c 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java @@ -24,6 +24,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.DozeParameters; import java.io.PrintWriter; @@ -38,18 +39,22 @@ public class DozeWallpaperState implements DozeMachine.Part { private final IWallpaperManager mWallpaperManagerService; private final DozeParameters mDozeParameters; + private final BiometricUnlockController mBiometricUnlockController; private boolean mIsAmbientMode; - public DozeWallpaperState(Context context) { + public DozeWallpaperState(Context context, + BiometricUnlockController biometricUnlockController) { this(IWallpaperManager.Stub.asInterface( ServiceManager.getService(Context.WALLPAPER_SERVICE)), + biometricUnlockController, DozeParameters.getInstance(context)); } @VisibleForTesting DozeWallpaperState(IWallpaperManager wallpaperManagerService, - DozeParameters parameters) { + BiometricUnlockController biometricUnlockController, DozeParameters parameters) { mWallpaperManagerService = wallpaperManagerService; + mBiometricUnlockController = biometricUnlockController; mDozeParameters = parameters; } @@ -76,7 +81,9 @@ public class DozeWallpaperState implements DozeMachine.Part { } else { boolean wakingUpFromPulse = oldState == DozeMachine.State.DOZE_PULSING && newState == DozeMachine.State.FINISH; - animated = !mDozeParameters.getDisplayNeedsBlanking() || wakingUpFromPulse; + boolean fastDisplay = !mDozeParameters.getDisplayNeedsBlanking(); + animated = (fastDisplay && !mBiometricUnlockController.unlockedByWakeAndUnlock()) + || wakingUpFromPulse; } if (isAmbientMode != mIsAmbientMode) { diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java index 6a1f24afe620..b154e66a846e 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java @@ -65,7 +65,7 @@ class ImageRevealHelper { @Override public void onAnimationStart(Animator animation) { if (mRevealListener != null) { - mRevealListener.onRevealStart(); + mRevealListener.onRevealStart(true /* animate */); } } }); @@ -73,7 +73,7 @@ class ImageRevealHelper { private void animate() { mAnimator.cancel(); - mAnimator.setFloatValues(mReveal, !mAwake ? MIN_REVEAL : MAX_REVEAL); + mAnimator.setFloatValues(mReveal, mAwake ? MAX_REVEAL : MIN_REVEAL); mAnimator.start(); } @@ -84,7 +84,16 @@ class ImageRevealHelper { void updateAwake(boolean awake, long duration) { mAwake = awake; mAnimator.setDuration(duration); - animate(); + if (duration == 0) { + // We are transiting from home to aod or aod to home directly, + // we don't need to do transition in these cases. + mReveal = mAwake ? MAX_REVEAL : MIN_REVEAL; + mRevealListener.onRevealStart(false /* animate */); + mRevealListener.onRevealStateChanged(); + mRevealListener.onRevealEnd(); + } else { + animate(); + } } /** @@ -100,7 +109,7 @@ class ImageRevealHelper { /** * Called back while reveal starts. */ - void onRevealStart(); + void onRevealStart(boolean animate); /** * Called back while reveal ends. diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java index 93d8dd6146a6..7b22a49fc88a 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java @@ -24,6 +24,7 @@ import static android.opengl.GLES20.glViewport; import android.app.WallpaperManager; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Rect; import android.util.Log; @@ -70,7 +71,14 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, DisplayInfo displayInfo = new DisplayInfo(); WindowManager wm = context.getSystemService(WindowManager.class); wm.getDefaultDisplay().getDisplayInfo(displayInfo); - mScissor = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); + + // We only do transition in portrait currently, b/137962047. + int orientation = context.getResources().getConfiguration().orientation; + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + mScissor = new Rect(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); + } else { + mScissor = new Rect(0, 0, displayInfo.logicalHeight, displayInfo.logicalWidth); + } mProxy = proxy; mProgram = new ImageGLProgram(context); @@ -179,20 +187,24 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer, } @Override - public void onRevealStart() { - mScissorMode = true; - // Use current display area of texture. - mWallpaper.adjustTextureCoordinates(mSurfaceSize, mScissor, mXOffset, mYOffset); + public void onRevealStart(boolean animate) { + if (animate) { + mScissorMode = true; + // Use current display area of texture. + mWallpaper.adjustTextureCoordinates(mSurfaceSize, mScissor, mXOffset, mYOffset); + } mProxy.preRender(); } @Override public void onRevealEnd() { - mScissorMode = false; - // reset texture coordinates to use full texture. - mWallpaper.adjustTextureCoordinates(null, null, 0, 0); - // We need draw full texture back before finishing render. - mProxy.requestRender(); + if (mScissorMode) { + mScissorMode = false; + // reset texture coordinates to use full texture. + mWallpaper.adjustTextureCoordinates(null, null, 0, 0); + // We need draw full texture back before finishing render. + mProxy.requestRender(); + } mProxy.postRender(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index 20477975a6dd..0687b7d8efce 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -52,6 +52,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.R; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.NextAlarmControllerImpl; import com.android.systemui.statusbar.policy.ZenModeController; @@ -125,6 +126,7 @@ public class KeyguardSliceProvider extends SliceProvider implements private CharSequence mMediaTitle; private CharSequence mMediaArtist; protected boolean mDozing; + private int mStatusBarState; private boolean mMediaIsVisible; /** @@ -227,7 +229,10 @@ public class KeyguardSliceProvider extends SliceProvider implements } protected boolean needsMediaLocked() { - return !TextUtils.isEmpty(mMediaTitle) && mMediaIsVisible && mDozing; + // Show header if music is playing and the status bar is in the shade state. This way, an + // animation isn't necessary when pressing power and transitioning to AOD. + boolean keepWhenShade = mStatusBarState == StatusBarState.SHADE && mMediaIsVisible; + return !TextUtils.isEmpty(mMediaTitle) && mMediaIsVisible && (mDozing || keepWhenShade); } protected void addMediaLocked(ListBuilder listBuilder) { @@ -454,7 +459,7 @@ public class KeyguardSliceProvider extends SliceProvider implements synchronized (this) { boolean nextVisible = !mMediaInvisibleStates.contains(state); mHandler.removeCallbacksAndMessages(mMediaToken); - if (mMediaIsVisible && !nextVisible) { + if (mMediaIsVisible && !nextVisible && mStatusBarState != StatusBarState.SHADE) { // We need to delay this event for a few millis when stopping to avoid jank in the // animation. The media app might not send its update when buffering, and the slice // would end up without a header for 0.5 second. @@ -511,5 +516,14 @@ public class KeyguardSliceProvider extends SliceProvider implements @Override public void onStateChanged(int newState) { + final boolean notify; + synchronized (this) { + boolean needsMedia = needsMediaLocked(); + mStatusBarState = newState; + notify = needsMedia != needsMediaLocked(); + } + if (notify) { + notifyChange(); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index 0fe5f8a6af5a..4cc5b2144adc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -15,7 +15,6 @@ package com.android.systemui.statusbar; import android.content.pm.UserInfo; -import android.service.notification.StatusBarNotification; import android.util.SparseArray; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -58,7 +57,7 @@ public interface NotificationLockscreenUserManager { boolean shouldHideNotifications(int userId); boolean shouldHideNotifications(String key); - boolean shouldShowOnKeyguard(StatusBarNotification sbn); + boolean shouldShowOnKeyguard(NotificationEntry entry); boolean isAnyProfilePublicMode(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 4ea1ed5b9451..e08a5ae07bd8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -33,7 +33,6 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; -import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -302,7 +301,7 @@ public class NotificationLockscreenUserManagerImpl implements Notification.VISIBILITY_SECRET; } - public boolean shouldShowOnKeyguard(StatusBarNotification sbn) { + public boolean shouldShowOnKeyguard(NotificationEntry entry) { if (getEntryManager() == null) { Log.wtf(TAG, "mEntryManager was null!", new Throwable()); return false; @@ -310,10 +309,10 @@ public class NotificationLockscreenUserManagerImpl implements boolean exceedsPriorityThreshold; if (NotificationUtils.useNewInterruptionModel(mContext) && hideSilentNotificationsOnLockscreen()) { - exceedsPriorityThreshold = getEntryManager().getNotificationData().isHighPriority(sbn); + exceedsPriorityThreshold = entry.isTopBucket(); } else { exceedsPriorityThreshold = - !getEntryManager().getNotificationData().isAmbient(sbn.getKey()); + !getEntryManager().getNotificationData().isAmbient(entry.key); } return mShowLockscreenNotifications && exceedsPriorityThreshold; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 312ea473d9e6..165c64e7a6a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -512,7 +512,7 @@ public class NotificationShelf extends ActivatableNotificationView implements float viewEnd = row.getTranslationY() + row.getActualHeight(); boolean isPinned = (row.isPinned() || row.isHeadsUpAnimatingAway()) && !mAmbientState.isDozingAndNotPulsing(row); - boolean shouldClipOwnTop = row.showingAmbientPulsing() + boolean shouldClipOwnTop = row.showingAmbientPulsing() && !mAmbientState.isFullyDark() || (mAmbientState.isPulseExpanding() && childIndex == 0); if (viewEnd > notificationClipEnd && !shouldClipOwnTop && (mAmbientState.isShadeExpanded() || !isPinned)) { @@ -752,8 +752,9 @@ public class NotificationShelf extends ActivatableNotificationView implements iconState.scaleY = 1.0f; iconState.hidden = false; } - if (row.isAboveShelf() || (!row.isInShelf() && (isLastChild && row.areGutsExposed() - || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) { + if ((row.isAboveShelf() || (!row.isInShelf() && (isLastChild && row.areGutsExposed() + || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) + && !mAmbientState.isFullyDark()) { iconState.hidden = true; } int backgroundColor = getBackgroundColorWithoutTint(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 404920187351..9c3ee96fe25b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -394,15 +394,13 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle int userId = entry.notification.getUserId(); boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup( entry.notification) && !entry.isRowRemoved(); - boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry - .notification); + boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry); if (!showOnKeyguard) { // min priority notifications should show if their summary is showing if (mGroupManager.isChildInGroupWithSummary(entry.notification)) { NotificationEntry summary = mGroupManager.getLogicalGroupSummary( entry.notification); - if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard( - summary.notification)) { + if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(summary)) { showOnKeyguard = true; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java index 0d9f4e7b909d..91d47077fc31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java @@ -153,6 +153,7 @@ public class ActivityLaunchAnimator { if (primary == null) { setAnimationPending(false); invokeCallback(iRemoteAnimationFinishedCallback); + mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */); return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java index 64b2f048ce2e..13f8f1a6a548 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java @@ -25,7 +25,6 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; -import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; @@ -108,10 +107,19 @@ public class NotificationData { boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH && isSystemNotification(nb); - boolean isHeadsUp = a.getRow().isHeadsUp(); - if (isHeadsUp != b.getRow().isHeadsUp()) { - return isHeadsUp ? -1 : 1; - } else if (isHeadsUp) { + + boolean aHeadsUp = a.getRow().isHeadsUp(); + boolean bHeadsUp = b.getRow().isHeadsUp(); + + // HACK: This should really go elsewhere, but it's currently not straightforward to + // extract the comparison code and we're guaranteed to touch every element, so this is + // the best place to set the buckets for the moment. + a.setIsTopBucket(aHeadsUp || aMedia || aSystemMax || a.isHighPriority()); + b.setIsTopBucket(bHeadsUp || bMedia || bSystemMax || b.isHighPriority()); + + if (aHeadsUp != bHeadsUp) { + return aHeadsUp ? -1 : 1; + } else if (aHeadsUp) { // Provide consistent ranking with headsUpManager return mHeadsUpManager.compare(a, b); } else if (a.getRow().showingAmbientPulsing() != b.getRow().showingAmbientPulsing()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 92c261c4cad7..d157f06c03e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -173,6 +173,8 @@ public final class NotificationEntry { */ private boolean mHighPriority; + private boolean mIsTopBucket; + public NotificationEntry(StatusBarNotification n) { this(n, null); } @@ -220,6 +222,18 @@ public final class NotificationEntry { this.mHighPriority = highPriority; } + /** + * @return True if the notif should appear in the "top" or "important" section of notifications + * (as opposed to the "bottom" or "silent" section). This is usually the same as + * {@link #isHighPriority()}, but there are certain exceptions, such as media notifs. + */ + public boolean isTopBucket() { + return mIsTopBucket; + } + public void setIsTopBucket(boolean isTopBucket) { + mIsTopBucket = isTopBucket; + } + public boolean isBubble() { return (notification.getNotification().flags & FLAG_BUBBLE) != 0; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java index 170a4d570688..d119fb79e4c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java @@ -133,7 +133,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide if (child instanceof ExpandableNotificationRow && child.getVisibility() != View.GONE) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; - if (!row.getEntry().isHighPriority()) { + if (!row.getEntry().isTopBucket()) { firstGentleNotifIndex = i; mFirstGentleNotif = row; break; @@ -248,7 +248,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide View child = mParent.getChildAt(i); if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; - if (!row.getEntry().isHighPriority()) { + if (!row.getEntry().isTopBucket()) { break; } else { lastChildBeforeGap = row; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 8fe34180203f..237825e44b97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -1355,7 +1355,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mIsClipped = clipped; } - if (!mAmbientPulseManager.hasNotifications() && mAmbientState.isFullyDark()) { + if (!mPulsing && mAmbientState.isFullyDark()) { setClipBounds(null); } else if (mAmbientState.isDarkAtAll()) { clipToOutline = true; @@ -2516,12 +2516,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } return; } - int minTopPosition = 0; + int minTopPosition; NotificationSection lastSection = getLastVisibleSection(); if (mStatusBarState != StatusBarState.KEYGUARD) { minTopPosition = (int) (mTopPadding + mStackTranslation); } else if (lastSection == null) { minTopPosition = mTopPadding; + } else { + // The first sections could be empty while there could still be elements in later + // sections. The position of these first few sections is determined by the position of + // the first visible section. + NotificationSection firstVisibleSection = getFirstVisibleSection(); + firstVisibleSection.updateBounds(0 /* minTopPosition*/, 0 /* minBottomPosition */, + false /* shiftPulsingWithFirst */); + minTopPosition = firstVisibleSection.getBounds().top; } boolean shiftPulsingWithFirst = mAmbientPulseManager.getAllEntries().count() <= 1; for (NotificationSection section : mSections) { @@ -5161,6 +5169,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return; } mPulsing = pulsing; + updateClipping(); mAmbientState.setPulsing(pulsing); mSwipeHelper.setPulsing(pulsing); updateNotificationAnimationStates(); @@ -5768,7 +5777,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd currentIndex++; boolean beforeSpeedBump; if (mHighPriorityBeforeSpeedBump) { - beforeSpeedBump = row.getEntry().isHighPriority(); + beforeSpeedBump = row.getEntry().isTopBucket(); } else { beforeSpeedBump = !row.getEntry().ambient; } @@ -5826,9 +5835,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd case ROWS_ALL: return true; case ROWS_HIGH_PRIORITY: - return row.getEntry().isHighPriority(); + return row.getEntry().isTopBucket(); case ROWS_GENTLE: - return !row.getEntry().isHighPriority(); + return !row.getEntry().isTopBucket(); default: throw new IllegalArgumentException("Unknown selection: " + selection); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 60061c6a9ad2..d9f8c88e0d13 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -501,7 +501,8 @@ public class StackScrollAlgorithm { continue; } ExpandableNotificationRow row = (ExpandableNotificationRow) child; - if (!row.showingAmbientPulsing() || (i == 0 && ambientState.isPulseExpanding())) { + if (!row.showingAmbientPulsing() || ambientState.isFullyDark() + || (i == 0 && ambientState.isPulseExpanding())) { continue; } ExpandableViewState viewState = row.getViewState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 4d4818d51414..eccd70b4a597 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -132,6 +132,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { private BiometricSourceType mPendingAuthenticatedBioSourceType = null; private boolean mPendingShowBouncer; private boolean mHasScreenTurnedOnSinceAuthenticating; + private boolean mFadedAwayAfterWakeAndUnlock; private final TunerService.Tunable mFaceDismissedKeyguardTunable = new TunerService.Tunable() { @Override @@ -360,6 +361,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { @Override public void onStartedGoingToSleep(int why) { resetMode(); + mFadedAwayAfterWakeAndUnlock = false; mPendingAuthenticatedUserId = -1; mPendingAuthenticatedBioSourceType = null; } @@ -454,6 +456,9 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { } public void finishKeyguardFadingAway() { + if (isWakeAndUnlock()) { + mFadedAwayAfterWakeAndUnlock = true; + } resetMode(); } @@ -504,6 +509,14 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { } /** + * Successful authentication with fingerprint, face, or iris that wakes up the device. + * This will return {@code true} even after the keyguard fades away. + */ + public boolean unlockedByWakeAndUnlock() { + return isWakeAndUnlock() || mFadedAwayAfterWakeAndUnlock; + } + + /** * Successful authentication with fingerprint, face, or iris when the screen was either * on or off. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index a0cda693822f..595c1acaf56d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; +import android.graphics.Region; import android.util.Log; import android.util.Pools; import android.view.DisplayCutout; @@ -76,7 +77,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private int[] mTmpTwoArray = new int[2]; private boolean mHeadsUpGoingAway; private int mStatusBarState; - private Rect mTouchableRegion = new Rect(); + private Region mTouchableRegion = new Region(); private AnimationStateHandler mAnimationStateHandler; @@ -299,12 +300,16 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, info.touchableRegion.set(calculateTouchableRegion()); } - public Rect calculateTouchableRegion() { - if (!hasPinnedHeadsUp()) { + public Region calculateTouchableRegion() { + NotificationEntry topEntry = getTopEntry(); + // This call could be made in an inconsistent state while the pinnedMode hasn't been + // updated yet, but callbacks leading out of the headsUp manager, querying it. Let's + // therefore also check if the topEntry is null. + if (!hasPinnedHeadsUp() || topEntry == null) { mTouchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight); updateRegionForNotch(mTouchableRegion); + } else { - NotificationEntry topEntry = getTopEntry(); if (topEntry.isChildInGroup()) { final NotificationEntry groupSummary = mGroupManager.getGroupSummary(topEntry.notification); @@ -322,7 +327,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, return mTouchableRegion; } - private void updateRegionForNotch(Rect region) { + private void updateRegionForNotch(Region region) { DisplayCutout cutout = mStatusBarWindowView.getRootWindowInsets().getDisplayCutout(); if (cutout == null) { return; @@ -390,6 +395,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, super.dumpInternal(fd, pw, args); pw.print(" mBarState="); pw.println(mStatusBarState); + pw.print(" mTouchableRegion="); + pw.println(mTouchableRegion); } /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 1027046b0c28..bc205d676914 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -38,6 +38,7 @@ import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.Region; import android.os.PowerManager; import android.util.AttributeSet; import android.util.Log; @@ -620,9 +621,10 @@ public class NotificationPanelView extends PanelView implements private Rect calculateGestureExclusionRect() { Rect exclusionRect = null; - if (isFullyCollapsed()) { + Region touchableRegion = mHeadsUpManager.calculateTouchableRegion(); + if (isFullyCollapsed() && touchableRegion != null) { // Note: The heads up manager also calculates the non-pinned touchable region - exclusionRect = mHeadsUpManager.calculateTouchableRegion(); + exclusionRect = touchableRegion.getBounds(); } return exclusionRect != null ? exclusionRect @@ -732,8 +734,7 @@ public class NotificationPanelView extends PanelView implements if (suppressedSummary) { continue; } - if (!mLockscreenUserManager.shouldShowOnKeyguard( - row.getStatusBarNotification())) { + if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) { continue; } if (row.isRemoved()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 1aa8bd79af35..c6de829e49be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -482,9 +482,12 @@ public class StatusBar extends SystemUI implements DemoMode, WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT); final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean( com.android.internal.R.bool.config_dozeSupportsAodWallpaper); + final boolean imageWallpaperInAmbient = + !DozeParameters.getInstance(mContext).getDisplayNeedsBlanking(); // If WallpaperInfo is null, it must be ImageWallpaper. final boolean supportsAmbientMode = deviceSupportsAodWallpaper - && (info == null || info.supportsAmbientMode()); + && ((info == null && imageWallpaperInAmbient) + || (info != null && info.supportsAmbientMode())); mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); @@ -1213,6 +1216,7 @@ public class StatusBar extends SystemUI implements DemoMode, mDozeScrimController, keyguardViewMediator, mScrimController, this, UnlockMethodCache.getInstance(mContext), new Handler(), mKeyguardUpdateMonitor, Dependency.get(TunerService.class)); + putComponent(BiometricUnlockController.class, mBiometricUnlockController); mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, getBouncerContainer(), mNotificationPanel, mBiometricUnlockController, mStatusBarWindow.findViewById(R.id.lock_icon_container)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java index 329ef1c19a2b..7ea6493da83d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java @@ -56,6 +56,9 @@ public class FalsingManagerProxyTest extends SysuiTestCase { mHandler = new Handler(mTestableLooper.getLooper()); mDefaultConfigValue = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, false); + // In case it runs on a device where it's been set to true, set it to false by hand. + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + BRIGHTLINE_FALSING_MANAGER_ENABLED, "false", false); } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java index 87ae85f6d302..f07edf331f13 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java @@ -18,6 +18,7 @@ package com.android.systemui.doze; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,6 +30,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.DozeParameters; import org.junit.Before; @@ -44,12 +46,14 @@ public class DozeWallpaperStateTest extends SysuiTestCase { private DozeWallpaperState mDozeWallpaperState; @Mock IWallpaperManager mIWallpaperManager; + @Mock BiometricUnlockController mBiometricUnlockController; @Mock DozeParameters mDozeParameters; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mDozeParameters); + mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mBiometricUnlockController, + mDozeParameters); } @Test @@ -102,6 +106,20 @@ public class DozeWallpaperStateTest extends SysuiTestCase { } @Test + public void testDoesNotAnimate_whenWakeAndUnlock() throws RemoteException { + // Pre-conditions + when(mDozeParameters.getAlwaysOn()).thenReturn(true); + when(mBiometricUnlockController.unlockedByWakeAndUnlock()).thenReturn(true); + + mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED, + DozeMachine.State.DOZE_AOD); + clearInvocations(mIWallpaperManager); + + mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH); + verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(0L)); + } + + @Test public void testTransitionTo_requestPulseIsAmbientMode() throws RemoteException { mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.DOZE_REQUEST_PULSE); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index 44191147f914..a83c4b653ce7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -48,6 +48,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.wakelock.SettableWakeLock; @@ -177,6 +178,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Test public void onMetadataChanged_updatesSlice() { + mProvider.onStateChanged(StatusBarState.KEYGUARD); mProvider.onDozingChanged(true); reset(mContentResolver); mProvider.onMetadataOrStateChanged(mock(MediaMetadata.class), PlaybackState.STATE_PLAYING); @@ -190,6 +192,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Test public void onDozingChanged_updatesSliceIfMedia() { + mProvider.onStateChanged(StatusBarState.KEYGUARD); mProvider.onMetadataOrStateChanged(mock(MediaMetadata.class), PlaybackState.STATE_PLAYING); reset(mContentResolver); // Show media when dozing diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index 49a263a8d781..57dd8c94c790 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -38,7 +38,6 @@ import android.os.Handler; import android.os.Looper; import android.os.UserManager; import android.provider.Settings; -import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -48,6 +47,7 @@ import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -166,7 +166,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1); when(mNotificationData.isHighPriority(any())).thenReturn(false); - assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class))); + assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class))); } @Test @@ -179,7 +179,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0); when(mNotificationData.isHighPriority(any())).thenReturn(false); - assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class))); + assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class))); } private class TestNotificationLockscreenUserManager diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java index 73abda9a5da7..59d0f912d38e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java @@ -263,6 +263,8 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { when(notifRow.getVisibility()).thenReturn(View.VISIBLE); when(notifRow.getEntry().isHighPriority()) .thenReturn(children[i] == ChildType.HIPRI); + when(notifRow.getEntry().isTopBucket()) + .thenReturn(children[i] == ChildType.HIPRI); when(notifRow.getParent()).thenReturn(mNssl); child = notifRow; break; diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index bc7da3fe2edc..30a356325ada 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -413,15 +413,15 @@ final class UiModeManagerService extends SystemService { try { synchronized (mLock) { if (mNightMode != mode) { - if (UserManager.get(getContext()).isPrimaryUser()) { - SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, - Integer.toString(mode)); - } - // Only persist setting if not in car mode if (!mCarModeEnabled) { Secure.putIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, mode, user); + + if (UserManager.get(getContext()).isPrimaryUser()) { + SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, + Integer.toString(mode)); + } } mNightMode = mode; diff --git a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java index 5cbd237a0722..4ef63c05325c 100644 --- a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java +++ b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java @@ -122,7 +122,7 @@ public class PasswordSlotManager { */ public void markSlotDeleted(int slot) throws RuntimeException { ensureSlotMapLoaded(); - if (mSlotMap.containsKey(slot) && mSlotMap.get(slot) != getMode()) { + if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) { throw new RuntimeException("password slot " + slot + " cannot be deleted"); } mSlotMap.remove(slot); diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 6f28675d051b..934511bf88d1 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -296,22 +296,12 @@ final class OverlayManagerServiceImpl { */ private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName, final int userId, final int flags) { - final List<OverlayInfo> ois = new ArrayList<>(); - - // Framework overlays added first because order matters when resolving a resource - if (!"android".equals(targetPackageName)) { - ois.addAll(mSettings.getOverlaysForTarget("android", userId)); - } - - // Then add the targeted, non-framework overlays which have higher priority - ois.addAll(mSettings.getOverlaysForTarget(targetPackageName, userId)); - - final List<String> enabledBaseCodePaths = new ArrayList<>(ois.size()); + final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName, + userId); + // Update the state for any overlay that targets this package. boolean modified = false; - final int n = ois.size(); - for (int i = 0; i < n; i++) { - final OverlayInfo oi = ois.get(i); + for (final OverlayInfo oi : targetOverlays) { final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName, userId); if (overlayPackage == null) { @@ -324,25 +314,39 @@ final class OverlayManagerServiceImpl { Slog.e(TAG, "failed to update settings", e); modified |= mSettings.remove(oi.packageName, userId); } - - if (oi.isEnabled() && overlayPackage.applicationInfo != null) { - enabledBaseCodePaths.add(overlayPackage.applicationInfo.getBaseCodePath()); - } } } if (!modified) { + // Update the overlay paths of the target within package manager if necessary. + final List<String> enabledOverlayPaths = new ArrayList<>(targetOverlays.size()); + + // Framework overlays are first in the overlay paths of a package within PackageManager. + for (final OverlayInfo oi : mSettings.getOverlaysForTarget("android", userId)) { + if (oi.isEnabled()) { + enabledOverlayPaths.add(oi.baseCodePath); + } + } + + for (final OverlayInfo oi : targetOverlays) { + if (oi.isEnabled()) { + enabledOverlayPaths.add(oi.baseCodePath); + } + } + + // TODO(): Use getEnabledOverlayPaths(userId, targetPackageName) instead of + // resourceDirs if in the future resourceDirs contains APKs other than overlays PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, userId); ApplicationInfo appInfo = packageInfo == null ? null : packageInfo.applicationInfo; String[] resourceDirs = appInfo == null ? null : appInfo.resourceDirs; // If the lists aren't the same length, the enabled overlays have changed - if (ArrayUtils.size(resourceDirs) != enabledBaseCodePaths.size()) { + if (ArrayUtils.size(resourceDirs) != enabledOverlayPaths.size()) { modified = true; } else if (resourceDirs != null) { // If any element isn't equal, an overlay or the order of overlays has changed for (int index = 0; index < resourceDirs.length; index++) { - if (!resourceDirs[index].equals(enabledBaseCodePaths.get(index))) { + if (!resourceDirs[index].equals(enabledOverlayPaths.get(index))) { modified = true; break; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 24a0c885223b..94d262b896a7 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -318,6 +318,7 @@ import com.android.server.pm.permission.PermissionManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; import com.android.server.pm.permission.PermissionsState; +import com.android.server.policy.PermissionPolicyInternal; import com.android.server.security.VerityUtils; import com.android.server.storage.DeviceStorageMonitorInternal; import com.android.server.wm.ActivityTaskManagerInternal; @@ -11032,14 +11033,15 @@ public class PackageManagerService extends IPackageManager.Stub final String realPkgName = request.realPkgName; final List<String> changedAbiCodePath = result.changedAbiCodePath; final PackageSetting pkgSetting; + if (request.pkgSetting != null && request.pkgSetting.sharedUser != null + && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) { + // shared user changed, remove from old shared user + request.pkgSetting.sharedUser.removePackage(request.pkgSetting); + } if (result.existingSettingCopied) { pkgSetting = request.pkgSetting; pkgSetting.updateFrom(result.pkgSetting); pkg.mExtras = pkgSetting; - if (pkgSetting.sharedUser != null - && pkgSetting.sharedUser.removePackage(result.pkgSetting)) { - pkgSetting.sharedUser.addPackage(pkgSetting); - } } else { pkgSetting = result.pkgSetting; if (originalPkgSetting != null) { @@ -11049,6 +11051,9 @@ public class PackageManagerService extends IPackageManager.Stub mTransferedPackages.add(originalPkgSetting.name); } } + if (pkgSetting.sharedUser != null) { + pkgSetting.sharedUser.addPackage(pkgSetting); + } // TODO(toddke): Consider a method specifically for modifying the Package object // post scan; or, moving this stuff out of the Package object since it has nothing // to do with the package on disk. @@ -16591,13 +16596,13 @@ public class PackageManagerService extends IPackageManager.Stub && compareSignatures(sharedUserSignatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { - if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 28) { + if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) { // Mismatched signatures is an error and silently skipping system // packages will likely break the device in unforeseen ways. - // However, - // we allow the device to boot anyway because, prior to P, - // vendors were - // not expecting the platform to crash in this situation. + // However, we allow the device to boot anyway because, prior to Q, + // vendors were not expecting the platform to crash in this + // situation. + // This WILL be a hard failure on any new API levels after Q. throw new ReconcileFailure( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Signature mismatch for shared user: " @@ -21634,6 +21639,17 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.updateAllPermissions( StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(), mPermissionCallback); + + final PermissionPolicyInternal permissionPolicyInternal = + LocalServices.getService(PermissionPolicyInternal.class); + permissionPolicyInternal.setOnInitializedCallback(userId -> { + // The SDK updated case is already handled when we run during the ctor. + synchronized (mPackages) { + mPermissionManager.updateAllPermissions( + StorageManager.UUID_PRIVATE_INTERNAL, false /*sdkUpdated*/, + mPackages.values(), mPermissionCallback); + } + }); } // Watch for external volumes that come and go over time diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index f8c4f6b2cdba..4550446f88c5 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -1170,6 +1170,11 @@ public final class DefaultPermissionGrantPolicy { final int flags = mContext.getPackageManager().getPermissionFlags( permission, pkg.packageName, user); + // If we are trying to grant as system fixed and already system fixed + // then the system can change the system fixed grant state. + final boolean changingGrantForSystemFixed = systemFixed + && (flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0; + // Certain flags imply that the permission's current state by the system or // device/profile owner or the user. In these cases we do not want to clobber the // current state. @@ -1177,7 +1182,8 @@ public final class DefaultPermissionGrantPolicy { // Unless the caller wants to override user choices. The override is // to make sure we can grant the needed permission to the default // sms and phone apps after the user chooses this in the UI. - if (!isFixedOrUserSet(flags) || ignoreSystemPackage) { + if (!isFixedOrUserSet(flags) || ignoreSystemPackage + || changingGrantForSystemFixed) { // Never clobber policy fixed permissions. // We must allow the grant of a system-fixed permission because // system-fixed is sticky, but the permission itself may be revoked. @@ -1196,6 +1202,14 @@ public final class DefaultPermissionGrantPolicy { PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user); } + // If the system tries to change a system fixed permission from one fixed + // state to another we need to drop the fixed flag to allow the grant. + if (changingGrantForSystemFixed) { + mContext.getPackageManager().updatePermissionFlags(permission, + pkg.packageName, flags, + flags & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, user); + } + if (pm.checkPermission(permission, pkg.packageName) != PackageManager.PERMISSION_GRANTED) { mContext.getPackageManager() diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index d3e5df5d62d1..8884821c770e 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -97,6 +97,7 @@ import com.android.server.pm.SharedUserSetting; import com.android.server.pm.UserManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; import com.android.server.pm.permission.PermissionsState.PermissionState; +import com.android.server.policy.PermissionPolicyInternal; import com.android.server.policy.SoftRestrictedPermissionPolicy; import libcore.util.EmptyArray; @@ -197,6 +198,9 @@ public class PermissionManagerService { @GuardedBy("mLock") private boolean mSystemReady; + @GuardedBy("mLock") + private PermissionPolicyInternal mPermissionPolicyInternal; + /** * For each foreground/background permission the mapping: * Background permission -> foreground permissions @@ -1080,6 +1084,13 @@ public class PermissionManagerService { boolean softRestricted = bp.isSoftRestricted(); for (int userId : currentUserIds) { + // If permission policy is not ready we don't deal with restricted + // permissions as the policy may whitelist some permissions. Once + // the policy is initialized we would re-evaluate permissions. + final boolean permissionPolicyInitialized = + mPermissionPolicyInternal != null + && mPermissionPolicyInternal.isInitialized(userId); + PermissionState permState = origPermissions .getRuntimePermissionState(perm, userId); int flags = permState != null ? permState.getFlags() : 0; @@ -1094,7 +1105,7 @@ public class PermissionManagerService { if (appSupportsRuntimePermissions) { // If hard restricted we don't allow holding it - if (hardRestricted) { + if (permissionPolicyInitialized && hardRestricted) { if (!restrictionExempt) { if (permState != null && permState.isGranted() && permissionsState.revokeRuntimePermission( @@ -1107,7 +1118,7 @@ public class PermissionManagerService { } } // If soft restricted we allow holding in a restricted form - } else if (softRestricted) { + } else if (permissionPolicyInitialized && softRestricted) { // Regardless if granted set the restriction flag as it // may affect app treatment based on this permission. if (!restrictionExempt && !restrictionApplied) { @@ -1126,7 +1137,8 @@ public class PermissionManagerService { flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE; wasChanged = true; // Hard restricted permissions cannot be held. - } else if (!hardRestricted || restrictionExempt) { + } else if (!permissionPolicyInitialized + || (!hardRestricted || restrictionExempt)) { if (permState != null && permState.isGranted()) { if (permissionsState.grantRuntimePermission(bp, userId) == PERMISSION_OPERATION_FAILURE) { @@ -1155,33 +1167,28 @@ public class PermissionManagerService { // If legacy app always grant the permission but if restricted // and not exempt take a note a restriction should be applied. - if ((hardRestricted || softRestricted) - && !restrictionExempt && !restrictionApplied) { + if (permissionPolicyInitialized + && (hardRestricted || softRestricted) + && !restrictionExempt && !restrictionApplied) { flags |= FLAG_PERMISSION_APPLY_RESTRICTION; wasChanged = true; } } // If unrestricted or restriction exempt, don't apply restriction. - if (!(hardRestricted || softRestricted) || restrictionExempt) { - if (restrictionApplied) { - flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION; - // Dropping restriction on a legacy app requires a review. - if (!appSupportsRuntimePermissions) { - flags |= FLAG_PERMISSION_REVIEW_REQUIRED; + if (permissionPolicyInitialized) { + if (!(hardRestricted || softRestricted) || restrictionExempt) { + if (restrictionApplied) { + flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION; + // Dropping restriction on a legacy app implies a review + if (!appSupportsRuntimePermissions) { + flags |= FLAG_PERMISSION_REVIEW_REQUIRED; + } + wasChanged = true; } - wasChanged = true; } } - if (hardRestricted && !restrictionExempt - && (flags & FLAG_PERMISSION_SYSTEM_FIXED) != 0) { - // Applying a hard restriction implies revoking it. This might - // lead to a system-fixed, revoked permission. - flags &= ~FLAG_PERMISSION_SYSTEM_FIXED; - wasChanged = true; - } - if (wasChanged) { updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); } @@ -1216,6 +1223,13 @@ public class PermissionManagerService { boolean softRestricted = bp.isSoftRestricted(); for (int userId : currentUserIds) { + // If permission policy is not ready we don't deal with restricted + // permissions as the policy may whitelist some permissions. Once + // the policy is initialized we would re-evaluate permissions. + final boolean permissionPolicyInitialized = + mPermissionPolicyInternal != null + && mPermissionPolicyInternal.isInitialized(userId); + boolean wasChanged = false; boolean restrictionExempt = @@ -1226,7 +1240,7 @@ public class PermissionManagerService { if (appSupportsRuntimePermissions) { // If hard restricted we don't allow holding it - if (hardRestricted) { + if (permissionPolicyInitialized && hardRestricted) { if (!restrictionExempt) { if (permState != null && permState.isGranted() && permissionsState.revokeRuntimePermission( @@ -1239,7 +1253,7 @@ public class PermissionManagerService { } } // If soft restricted we allow holding in a restricted form - } else if (softRestricted) { + } else if (permissionPolicyInitialized && softRestricted) { // Regardless if granted set the restriction flag as it // may affect app treatment based on this permission. if (!restrictionExempt && !restrictionApplied) { @@ -1258,7 +1272,8 @@ public class PermissionManagerService { flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE; wasChanged = true; // Hard restricted permissions cannot be held. - } else if (!hardRestricted || restrictionExempt) { + } else if (!permissionPolicyInitialized || + (!hardRestricted || restrictionExempt)) { if (permissionsState.grantRuntimePermission(bp, userId) != PERMISSION_OPERATION_FAILURE) { wasChanged = true; @@ -1274,22 +1289,25 @@ public class PermissionManagerService { // If legacy app always grant the permission but if restricted // and not exempt take a note a restriction should be applied. - if ((hardRestricted || softRestricted) - && !restrictionExempt && !restrictionApplied) { + if (permissionPolicyInitialized + && (hardRestricted || softRestricted) + && !restrictionExempt && !restrictionApplied) { flags |= FLAG_PERMISSION_APPLY_RESTRICTION; wasChanged = true; } } // If unrestricted or restriction exempt, don't apply restriction. - if (!(hardRestricted || softRestricted) || restrictionExempt) { - if (restrictionApplied) { - flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION; - // Dropping restriction on a legacy app requires a review. - if (!appSupportsRuntimePermissions) { - flags |= FLAG_PERMISSION_REVIEW_REQUIRED; + if (permissionPolicyInitialized) { + if (!(hardRestricted || softRestricted) || restrictionExempt) { + if (restrictionApplied) { + flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION; + // Dropping restriction on a legacy app implies a review + if (!appSupportsRuntimePermissions) { + flags |= FLAG_PERMISSION_REVIEW_REQUIRED; + } + wasChanged = true; } - wasChanged = true; } } @@ -2900,6 +2918,7 @@ public class PermissionManagerService { } mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class); + mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class); } private static String getVolumeUuidForPackage(PackageParser.Package pkg) { diff --git a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java index 7760c1edd9e6..6084c6718577 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java @@ -18,6 +18,7 @@ package com.android.server.policy; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.Intent; /** @@ -26,6 +27,19 @@ import android.content.Intent; public abstract class PermissionPolicyInternal { /** + * Callback for initializing the permission policy service. + */ + public interface OnInitializedCallback { + + /** + * Called when initialized for the given user. + * + * @param userId The initialized user. + */ + void onInitialized(@UserIdInt int userId); + } + + /** * Check whether an activity should be started. * * @param intent the {@link Intent} for the activity start @@ -36,4 +50,17 @@ public abstract class PermissionPolicyInternal { */ public abstract boolean checkStartActivity(@NonNull Intent intent, int callingUid, @Nullable String callingPackage); + + /** + * @return Whether the policy is initialized for a user. + */ + public abstract boolean isInitialized(@UserIdInt int userId); + + /** + * Set a callback for users being initialized. If the user is already + * initialized the callback will not be invoked. + * + * @param callback The callback to register. + */ + public abstract void setOnInitializedCallback(@NonNull OnInitializedCallback callback); } diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 037293f9536c..3d543c96aacc 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -66,6 +66,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.permission.PermissionManagerServiceInternal; +import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; @@ -86,6 +87,10 @@ public final class PermissionPolicyService extends SystemService { @GuardedBy("mLock") private final SparseBooleanArray mIsStarted = new SparseBooleanArray(); + /** Callbacks for when a user is initialized */ + @GuardedBy("mLock") + private OnInitializedCallback mOnInitializedCallback; + /** * Whether an async {@link #synchronizePackagePermissionsAndAppOpsForUser} is currently * scheduled for a package/user. @@ -240,12 +245,20 @@ public final class PermissionPolicyService extends SystemService { grantOrUpgradeDefaultRuntimePermissionsIfNeeded(userId); + final OnInitializedCallback callback; + synchronized (mLock) { mIsStarted.put(userId, true); + callback = mOnInitializedCallback; } // Force synchronization as permissions might have changed synchronizePermissionsAndAppOpsForUser(userId); + + // Tell observers we are initialized for this user. + if (callback != null) { + callback.onInitialized(userId); + } } @Override @@ -798,7 +811,7 @@ public final class PermissionPolicyService extends SystemService { @Override public boolean checkStartActivity(@NonNull Intent intent, int callingUid, @Nullable String callingPackage) { - if (callingPackage != null && isActionRemovedForCallingPackage(intent.getAction(), + if (callingPackage != null && isActionRemovedForCallingPackage(intent, callingUid, callingPackage)) { Slog.w(LOG_TAG, "Action Removed: starting " + intent.toString() + " from " + callingPackage + " (uid=" + callingUid + ")"); @@ -807,12 +820,25 @@ public final class PermissionPolicyService extends SystemService { return true; } + @Override + public boolean isInitialized(int userId) { + return isStarted(userId); + } + + @Override + public void setOnInitializedCallback(@NonNull OnInitializedCallback callback) { + synchronized (mLock) { + mOnInitializedCallback = callback; + } + } + /** * Check if the intent action is removed for the calling package (often based on target SDK * version). If the action is removed, we'll silently cancel the activity launch. */ - private boolean isActionRemovedForCallingPackage(@Nullable String action, + private boolean isActionRemovedForCallingPackage(@NonNull Intent intent, int callingUid, @NonNull String callingPackage) { + String action = intent.getAction(); if (action == null) { return false; } @@ -821,15 +847,19 @@ public final class PermissionPolicyService extends SystemService { case Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT: { ApplicationInfo applicationInfo; try { - applicationInfo = getContext().getPackageManager().getApplicationInfo( - callingPackage, 0); + applicationInfo = getContext().getPackageManager().getApplicationInfoAsUser( + callingPackage, 0, UserHandle.getUserId(callingUid)); + if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) { + // Applications targeting Q or higher should use + // RoleManager.createRequestRoleIntent() instead. + return true; + } } catch (PackageManager.NameNotFoundException e) { Slog.i(LOG_TAG, "Cannot find application info for " + callingPackage); - return false; } - // Applications targeting Q should use RoleManager.createRequestRoleIntent() - // instead. - return applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q; + // Make sure RequestRoleActivity can know the calling package if we allow it. + intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage); + return false; } default: return false; diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java index d53f6854dfdf..c1a6dbd8ae14 100644 --- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java +++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java @@ -28,11 +28,14 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INST import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; +import static java.lang.Integer.min; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.os.Build; import android.os.UserHandle; @@ -73,6 +76,41 @@ public abstract class SoftRestrictedPermissionPolicy { }; /** + * TargetSDK is per package. To make sure two apps int the same shared UID do not fight over + * what to set, always compute the combined targetSDK. + * + * @param context A context + * @param appInfo The app that is changed + * @param user The user the app belongs to + * + * @return The minimum targetSDK of all apps sharing the uid of the app + */ + private static int getMinimumTargetSDK(@NonNull Context context, + @NonNull ApplicationInfo appInfo, @NonNull UserHandle user) { + PackageManager pm = context.getPackageManager(); + + int minimumTargetSDK = appInfo.targetSdkVersion; + + String[] uidPkgs = pm.getPackagesForUid(appInfo.uid); + if (uidPkgs != null) { + for (String uidPkg : uidPkgs) { + if (!uidPkg.equals(appInfo.packageName)) { + ApplicationInfo uidPkgInfo; + try { + uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user); + } catch (PackageManager.NameNotFoundException e) { + continue; + } + + minimumTargetSDK = min(minimumTargetSDK, uidPkgInfo.targetSdkVersion); + } + } + } + + return minimumTargetSDK; + } + + /** * Get the policy for a soft restricted permission. * * @param context A context to use @@ -99,12 +137,36 @@ public abstract class SoftRestrictedPermissionPolicy { final int targetSDK; if (appInfo != null) { - flags = context.getPackageManager().getPermissionFlags(permission, - appInfo.packageName, user); + PackageManager pm = context.getPackageManager(); + flags = pm.getPermissionFlags(permission, appInfo.packageName, user); applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; - hasRequestedLegacyExternalStorage = appInfo.hasRequestedLegacyExternalStorage(); - targetSDK = appInfo.targetSdkVersion; + targetSDK = getMinimumTargetSDK(context, appInfo, user); + + boolean hasAnyRequestedLegacyExternalStorage = + appInfo.hasRequestedLegacyExternalStorage(); + + // hasRequestedLegacyExternalStorage is per package. To make sure two apps in + // the same shared UID do not fight over what to set, always compute the + // combined hasRequestedLegacyExternalStorage + String[] uidPkgs = pm.getPackagesForUid(appInfo.uid); + if (uidPkgs != null) { + for (String uidPkg : uidPkgs) { + if (!uidPkg.equals(appInfo.packageName)) { + ApplicationInfo uidPkgInfo; + try { + uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user); + } catch (PackageManager.NameNotFoundException e) { + continue; + } + + hasAnyRequestedLegacyExternalStorage |= + uidPkgInfo.hasRequestedLegacyExternalStorage(); + } + } + } + + hasRequestedLegacyExternalStorage = hasAnyRequestedLegacyExternalStorage; } else { flags = 0; applyRestriction = false; @@ -155,7 +217,7 @@ public abstract class SoftRestrictedPermissionPolicy { final int flags = context.getPackageManager().getPermissionFlags(permission, appInfo.packageName, user); isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; - targetSDK = appInfo.targetSdkVersion; + targetSDK = getMinimumTargetSDK(context, appInfo, user); } else { isWhiteListed = false; targetSDK = 0; diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING index c7e241b35e9a..17392e0a67bb 100644 --- a/services/core/java/com/android/server/policy/TEST_MAPPING +++ b/services/core/java/com/android/server/policy/TEST_MAPPING @@ -33,6 +33,9 @@ "options": [ { "include-filter": "android.permission2.cts.RestrictedPermissionsTest" + }, + { + "include-filter": "android.permission2.cts.RestrictedStoragePermissionSharedUidTest" } ] }, diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 03cae429904f..eab5e0dd270e 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -79,6 +79,7 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.logWithStack; import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY; +import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; @@ -540,6 +541,18 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // If the app was already visible, don't reset the waitingToShow state. if (isHidden()) { waitingToShow = true; + + // Let's reset the draw state in order to prevent the starting window to be + // immediately dismissed when the app still has the surface. + forAllWindows(w -> { + if (w.mWinAnimator.mDrawState == HAS_DRAWN) { + w.mWinAnimator.resetDrawState(); + + // Force add to mResizingWindows, so that we are guaranteed to get + // another reportDrawn callback. + w.resetLastContentInsets(); + } + }, true /* traverseTopToBottom */); } } diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index b90d60227be4..c0942c908f3b 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -936,6 +936,7 @@ class ScreenRotationAnimation { } } + t.setEarlyWakeup(); setSnapshotTransform(t, mSnapshotFinalMatrix, mExitTransformation.getAlpha()); } diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 14585c531203..19fbfedfc251 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -292,6 +292,10 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { private int getPreferredLaunchDisplay(@Nullable TaskRecord task, @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams) { + if (!mSupervisor.mService.mSupportsMultiDisplay) { + return DEFAULT_DISPLAY; + } + int displayId = INVALID_DISPLAY; final int optionLaunchId = options != null ? options.getLaunchDisplayId() : INVALID_DISPLAY; if (optionLaunchId != INVALID_DISPLAY) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index fb57d73c9a21..436a5c729b86 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7670,10 +7670,12 @@ public class WindowManagerService extends IWindowManager.Stub isDown = motionEvent.getAction() == MotionEvent.ACTION_DOWN; isUp = motionEvent.getAction() == MotionEvent.ACTION_UP; } + final boolean isMouseEvent = ev.getSource() == InputDevice.SOURCE_MOUSE; // For ACTION_DOWN, syncInputTransactions before injecting input. + // For all mouse events, also sync before injecting. // For ACTION_UP, sync after injecting. - if (isDown) { + if (isDown || isMouseEvent) { syncInputTransactions(); } final boolean result = diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 43ad091b08c0..703fe4ac867b 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1623,7 +1623,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP || !mRelayoutCalled || (atoken == null && mToken.isHidden()) || (atoken != null && atoken.hiddenRequested) - || isParentWindowHidden() + || isParentWindowGoneForLayout() || (mAnimatingExit && !isAnimatingLw()) || mDestroying; } @@ -3795,6 +3795,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return parent != null && parent.mHidden; } + private boolean isParentWindowGoneForLayout() { + final WindowState parent = getParentWindow(); + return parent != null && parent.isGoneForLayoutLw(); + } + void setWillReplaceWindow(boolean animate) { for (int i = mChildren.size() - 1; i >= 0; i--) { final WindowState c = mChildren.get(i); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 6f7af3f49b57..656af982859e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1974,6 +1974,11 @@ public final class SystemServer { } traceEnd(); + // Permission policy service + traceBeginAndSlog("StartPermissionPolicyService"); + mSystemServiceManager.startService(PermissionPolicyService.class); + traceEnd(); + traceBeginAndSlog("MakePackageManagerServiceReady"); mPackageManagerService.systemReady(); traceEnd(); @@ -2008,11 +2013,6 @@ public final class SystemServer { mSystemServiceManager.startBootPhase(SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY); traceEnd(); - // Permission policy service - traceBeginAndSlog("StartPermissionPolicyService"); - mSystemServiceManager.startService(PermissionPolicyService.class); - traceEnd(); - // These are needed to propagate to the runnable below. final NetworkManagementService networkManagementF = networkManagement; final NetworkStatsService networkStatsF = networkStats; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index f918149e6781..58614c650363 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -1225,6 +1225,22 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(startingBounds, adjustedBounds); } + @Test + public void testNoMultiDisplaySupports() { + final boolean orgValue = mService.mSupportsMultiDisplay; + final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN); + mCurrent.mPreferredDisplayId = display.mDisplayId; + + try { + mService.mSupportsMultiDisplay = false; + assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null, + mActivity, /* source */ null, /* options */ null, mCurrent, mResult)); + assertEquals(DEFAULT_DISPLAY, mResult.mPreferredDisplayId); + } finally { + mService.mSupportsMultiDisplay = orgValue; + } + } + private TestActivityDisplay createNewActivityDisplay(int windowingMode) { final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); display.setWindowingMode(windowingMode); diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java index a1bea4d417f9..d4ed9234569b 100644 --- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java @@ -21,6 +21,7 @@ import android.content.ContentResolver; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.os.RemoteException; import android.provider.Settings; import android.telephony.TelephonyManager; @@ -28,7 +29,9 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.server.SystemConfig; import java.util.ArrayList; @@ -140,9 +143,12 @@ public final class CarrierAppUtils { try { for (ApplicationInfo ai : candidates) { String packageName = ai.packageName; - boolean hasPrivileges = telephonyManager != null && - telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) == - TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + String[] restrictedCarrierApps = Resources.getSystem().getStringArray( + R.array.config_restrictedPreinstalledCarrierApps); + boolean hasPrivileges = telephonyManager != null + && telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS + && !ArrayUtils.contains(restrictedCarrierApps, packageName); // add hiddenUntilInstalled flag for carrier apps and associated apps packageManager.setSystemAppHiddenUntilInstalled(packageName, true); |