diff options
Diffstat (limited to 'core/java')
30 files changed, 653 insertions, 375 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index cb4e10fb6670..fe75415968aa 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -486,7 +486,7 @@ public abstract class ActivityManagerInternal { * not associated with an FGS; ensure display; or only update if already displayed. */ public abstract ServiceNotificationPolicy applyForegroundServiceNotification( - Notification notification, int id, String pkg, @UserIdInt int userId); + Notification notification, String tag, int id, String pkg, @UserIdInt int userId); /** * Callback from the notification subsystem that the given FGS notification has diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 5e99c79a7497..f52fdc562b13 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -3149,7 +3149,8 @@ class ContextImpl extends Context { // If we want to access protected data on behalf of another app we need to // tell the OS that we opt in to participate in the attribution chain. if (nextAttributionSource != null) { - getSystemService(PermissionManager.class).registerAttributionSource(attributionSource); + attributionSource = getSystemService(PermissionManager.class) + .registerAttributionSource(attributionSource); } return attributionSource; } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 313a34067cd0..b90b9a11611e 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -508,7 +508,6 @@ interface IActivityManager { boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) void suppressResizeConfigChanges(boolean suppress); - boolean isAppStartModeDisabled(int uid, in String packageName); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) boolean unlockUser(int userid, in byte[] token, in byte[] secret, in IProgressListener listener); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 6454d2027f58..9d149cf340e2 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5380,14 +5380,15 @@ public class Notification implements Parcelable private void bindExpandButton(RemoteViews contentView, StandardTemplateParams p) { // set default colors - int textColor = getPrimaryTextColor(p); - int pillColor = getColors(p).getProtectionColor(); + int bgColor = getBackgroundColor(p); + int pillColor = Colors.flattenAlpha(getColors(p).getProtectionColor(), bgColor); + int textColor = Colors.flattenAlpha(getPrimaryTextColor(p), pillColor); contentView.setInt(R.id.expand_button, "setDefaultTextColor", textColor); contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor); // Use different highlighted colors for conversations' unread count if (p.mHighlightExpander) { - textColor = getBackgroundColor(p); - pillColor = getPrimaryAccentColor(p); + pillColor = Colors.flattenAlpha(getPrimaryAccentColor(p), bgColor); + textColor = Colors.flattenAlpha(bgColor, pillColor); } contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor); contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 20afffc1f562..198c33e83707 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -1158,9 +1158,15 @@ public class ResourcesManager { } else { activityResources.overrideConfig.unset(); } + // Update the Activity's override display id. activityResources.overrideDisplayId = displayId; + // If a application info update was scheduled to occur in this process but has not + // occurred yet, apply it now so the resources objects will have updated paths if + // the assets sequence changed. + applyAllPendingAppInfoUpdates(); + if (DEBUG) { Throwable here = new Throwable(); here.fillInStackTrace(); diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index c1871be80462..444cc4eedcb1 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -353,7 +353,8 @@ public class TaskInfo { && (!topActivityInSizeCompat || configuration.windowConfiguration.getBounds() .equals(that.configuration.windowConfiguration.getBounds())) && (!topActivityInSizeCompat || configuration.getLayoutDirection() - == that.configuration.getLayoutDirection()); + == that.configuration.getLayoutDirection()) + && (!topActivityInSizeCompat || isVisible == that.isVisible); } /** diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index c499f691b69a..0e22705146af 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -88,6 +88,8 @@ import java.util.Set; public final class AttributionSource implements Parcelable { private static final String DESCRIPTOR = "android.content.AttributionSource"; + private static final Binder sDefaultToken = new Binder(DESCRIPTOR); + private final @NonNull AttributionSourceState mAttributionSourceState; private @Nullable AttributionSource mNextCached; @@ -97,7 +99,7 @@ public final class AttributionSource implements Parcelable { @TestApi public AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag) { - this(uid, packageName, attributionTag, new Binder(DESCRIPTOR)); + this(uid, packageName, attributionTag, sDefaultToken); } /** @hide */ @@ -132,7 +134,7 @@ public final class AttributionSource implements Parcelable { AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String[] renouncedPermissions, @Nullable AttributionSource next) { - this(uid, packageName, attributionTag, new Binder(DESCRIPTOR), renouncedPermissions, next); + this(uid, packageName, attributionTag, sDefaultToken, renouncedPermissions, next); } AttributionSource(int uid, @Nullable String packageName, @Nullable String attributionTag, @@ -150,6 +152,10 @@ public final class AttributionSource implements Parcelable { AttributionSource(@NonNull Parcel in) { this(AttributionSourceState.CREATOR.createFromParcel(in)); + + // Since we just unpacked this object as part of it transiting a Binder + // call, this is the perfect time to enforce that its UID can be trusted + enforceCallingUid(); } /** @hide */ @@ -170,6 +176,12 @@ public final class AttributionSource implements Parcelable { } /** @hide */ + public AttributionSource withToken(@NonNull Binder token) { + return new AttributionSource(getUid(), getPackageName(), getAttributionTag(), + token, mAttributionSourceState.renouncedPermissions, getNext()); + } + + /** @hide */ public @NonNull AttributionSourceState asState() { return mAttributionSourceState; } @@ -543,7 +555,9 @@ public final class AttributionSource implements Parcelable { if ((mBuilderFieldsSet & 0x10) == 0) { mAttributionSourceState.next = null; } - mAttributionSourceState.token = new Binder(DESCRIPTOR); + + mAttributionSourceState.token = sDefaultToken; + if (mAttributionSourceState.next == null) { // The NDK aidl backend doesn't support null parcelable arrays. mAttributionSourceState.next = new AttributionSourceState[0]; diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl index 6105c26dc651..debc074ea21a 100644 --- a/core/java/android/hardware/ISensorPrivacyManager.aidl +++ b/core/java/android/hardware/ISensorPrivacyManager.aidl @@ -46,6 +46,6 @@ interface ISensorPrivacyManager { void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable); // =============== End of transactions used on native side as well ============================ - void suppressIndividualSensorPrivacyReminders(int userId, String packageName, IBinder token, + void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token, boolean suppress); }
\ No newline at end of file diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java index c392fbb52de0..b7d95e7dea74 100644 --- a/core/java/android/hardware/SensorPrivacyManager.java +++ b/core/java/android/hardware/SensorPrivacyManager.java @@ -461,9 +461,9 @@ public final class SensorPrivacyManager { * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public void suppressSensorPrivacyReminders(@NonNull String packageName, + public void suppressSensorPrivacyReminders(int sensor, boolean suppress) { - suppressSensorPrivacyReminders(packageName, suppress, mContext.getUserId()); + suppressSensorPrivacyReminders(sensor, suppress, mContext.getUserId()); } /** @@ -476,10 +476,10 @@ public final class SensorPrivacyManager { * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) - public void suppressSensorPrivacyReminders(@NonNull String packageName, + public void suppressSensorPrivacyReminders(int sensor, boolean suppress, @UserIdInt int userId) { try { - mService.suppressIndividualSensorPrivacyReminders(userId, packageName, + mService.suppressIndividualSensorPrivacyReminders(userId, sensor, token, suppress); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 0cb996b118b4..dc1a50fa6616 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -1382,12 +1382,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing String[] msgArray = context.getResources().getStringArray( com.android.internal.R.array.fingerprint_error_vendor); if (vendorCode < msgArray.length) { - if (Build.IS_ENG || Build.IS_USERDEBUG) { - return msgArray[vendorCode]; - } else { - return context.getString( - com.android.internal.R.string.fingerprint_error_unable_to_process); - } + return msgArray[vendorCode]; } } } @@ -1427,12 +1422,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing String[] msgArray = context.getResources().getStringArray( com.android.internal.R.array.fingerprint_acquired_vendor); if (vendorCode < msgArray.length) { - if (Build.IS_ENG || Build.IS_USERDEBUG) { - return msgArray[vendorCode]; - } else { - return context.getString( - com.android.internal.R.string.fingerprint_error_unable_to_process); - } + return msgArray[vendorCode]; } } break; diff --git a/core/java/android/hardware/location/ContextHubClientCallback.java b/core/java/android/hardware/location/ContextHubClientCallback.java index 35d00f03de67..9309c5b0d8e3 100644 --- a/core/java/android/hardware/location/ContextHubClientCallback.java +++ b/core/java/android/hardware/location/ContextHubClientCallback.java @@ -68,8 +68,11 @@ public class ContextHubClientCallback { /** * Callback invoked when a nanoapp is dynamically loaded at the attached Context Hub through - * the {@link android.hardware.location.ContextHubManager}. This callback is not invoked for a - * nanoapp that is loaded internally by CHRE (e.g. nanoapps that are preloaded by the system). + * the {@link android.hardware.location.ContextHubManager}. + * + * NOTE: This callback is <b>not</b> invoked for a nanoapp that is loaded internally by CHRE + * (e.g. nanoapps that are preloaded by the system). To check the availability of these + * nanoapps, use the {@link ContextHubManager#queryNanoApps(ContextHubInfo)} API. * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been loaded diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index f69a7d7e5f16..9af0e09ee97a 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -128,7 +128,8 @@ public final class ContextHubManager { public static final int AUTHORIZATION_GRANTED = 2; /** - * Constants describing the type of events from a Context Hub. + * Constants describing the type of events from a Context Hub, as defined in + * {@link ContextHubClientCallback}. * {@hide} */ @Retention(RetentionPolicy.SOURCE) diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index a5b7e995293a..6bf394dc347b 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -441,23 +441,30 @@ public class Build { public static final int CUR_DEVELOPMENT = 10000; /** - * October 2008: The original, first, version of Android. Yay! + * The original, first, version of Android. Yay! + * + * <p>Released publicly as Android 1.0 in September 2008. */ public static final int BASE = 1; /** - * February 2009: First Android update, officially called 1.1. + * First Android update. + * + * <p>Released publicly as Android 1.1 in February 2009. */ public static final int BASE_1_1 = 2; /** - * May 2009: Android 1.5. + * C. + * + * <p>Released publicly as Android 1.5 in April 2009. */ public static final int CUPCAKE = 3; /** - * September 2009: Android 1.6. + * D. * + * <p>Released publicly as Android 1.6 in September 2009. * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> @@ -481,8 +488,9 @@ public class Build { public static final int DONUT = 4; /** - * November 2009: Android 2.0 + * E. * + * <p>Released publicly as Android 2.0 in October 2009. * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> @@ -501,23 +509,30 @@ public class Build { public static final int ECLAIR = 5; /** - * December 2009: Android 2.0.1 + * E incremental update. + * + * <p>Released publicly as Android 2.0.1 in December 2009. */ public static final int ECLAIR_0_1 = 6; /** - * January 2010: Android 2.1 + * E MR1. + * + * <p>Released publicly as Android 2.1 in January 2010. */ public static final int ECLAIR_MR1 = 7; /** - * June 2010: Android 2.2 + * F. + * + * <p>Released publicly as Android 2.2 in May 2010. */ public static final int FROYO = 8; /** - * November 2010: Android 2.3 + * G. * + * <p>Released publicly as Android 2.3 in December 2010. * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> @@ -528,13 +543,16 @@ public class Build { public static final int GINGERBREAD = 9; /** - * February 2011: Android 2.3.3. + * G MR1. + * + * <p>Released publicly as Android 2.3.3 in February 2011. */ public static final int GINGERBREAD_MR1 = 10; /** - * February 2011: Android 3.0. + * H. * + * <p>Released publicly as Android 3.0 in February 2011. * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> @@ -573,13 +591,16 @@ public class Build { public static final int HONEYCOMB = 11; /** - * May 2011: Android 3.1. + * H MR1. + * + * <p>Released publicly as Android 3.1 in May 2011. */ public static final int HONEYCOMB_MR1 = 12; /** - * June 2011: Android 3.2. + * H MR2. * + * <p>Released publicly as Android 3.2 in July 2011. * <p>Update to Honeycomb MR1 to support 7 inch tablets, improve * screen compatibility mode, etc.</p> * @@ -626,8 +647,9 @@ public class Build { public static final int HONEYCOMB_MR2 = 13; /** - * October 2011: Android 4.0. + * I. * + * <p>Released publicly as Android 4.0 in October 2011. * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> @@ -672,13 +694,16 @@ public class Build { public static final int ICE_CREAM_SANDWICH = 14; /** - * December 2011: Android 4.0.3. + * I MR1. + * + * <p>Released publicly as Android 4.03 in December 2011. */ public static final int ICE_CREAM_SANDWICH_MR1 = 15; /** - * June 2012: Android 4.1. + * J. * + * <p>Released publicly as Android 4.1 in July 2012. * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> @@ -720,8 +745,9 @@ public class Build { public static final int JELLY_BEAN = 16; /** - * November 2012: Android 4.2, Moar jelly beans! + * J MR1. * + * <p>Released publicly as Android 4.2 in November 2012. * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> @@ -740,13 +766,16 @@ public class Build { public static final int JELLY_BEAN_MR1 = 17; /** - * July 2013: Android 4.3, the revenge of the beans. + * J MR2. + * + * <p>Released publicly as Android 4.3 in July 2013. */ public static final int JELLY_BEAN_MR2 = 18; /** - * October 2013: Android 4.4, KitKat, another tasty treat. + * K. * + * <p>Released publicly as Android 4.4 in October 2013. * <p>Applications targeting this or a later release will get these * new changes in behavior. For more information about this release, see the * <a href="/about/versions/kitkat/">Android KitKat overview</a>.</p> @@ -778,8 +807,9 @@ public class Build { public static final int KITKAT = 19; /** - * June 2014: Android 4.4W. KitKat for watches, snacks on the run. + * K for watches. * + * <p>Released publicly as Android 4.4W in June 2014. * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> @@ -796,8 +826,9 @@ public class Build { public static final int L = 21; /** - * November 2014: Lollipop. A flat one with beautiful shadows. But still tasty. + * L. * + * <p>Released publicly as Android 5.0 in November 2014. * <p>Applications targeting this or a later release will get these * new changes in behavior. For more information about this release, see the * <a href="/about/versions/lollipop/">Android Lollipop overview</a>.</p> @@ -828,15 +859,18 @@ public class Build { public static final int LOLLIPOP = 21; /** - * March 2015: Lollipop with an extra sugar coating on the outside! - * For more information about this release, see the + * L MR1. + * + * <p>Released publicly as Android 5.1 in March 2015. + * <p>For more information about this release, see the * <a href="/about/versions/android-5.1">Android 5.1 APIs</a>. */ public static final int LOLLIPOP_MR1 = 22; /** - * M is for Marshmallow! + * M. * + * <p>Released publicly as Android 6.0 in October 2015. * <p>Applications targeting this or a later release will get these * new changes in behavior. For more information about this release, see the * <a href="/about/versions/marshmallow/">Android 6.0 Marshmallow overview</a>.</p> @@ -867,8 +901,9 @@ public class Build { public static final int M = 23; /** - * N is for Nougat. + * N. * + * <p>Released publicly as Android 7.0 in August 2016. * <p>Applications targeting this or a later release will get these * new changes in behavior. For more information about this release, see * the <a href="/about/versions/nougat/">Android Nougat overview</a>.</p> @@ -921,7 +956,10 @@ public class Build { public static final int N = 24; /** - * N MR1: Nougat++. For more information about this release, see + * N MR1. + * + * <p>Released publicly as Android 7.1 in October 2016. + * <p>For more information about this release, see * <a href="/about/versions/nougat/android-7.1">Android 7.1 for * Developers</a>. */ @@ -930,6 +968,7 @@ public class Build { /** * O. * + * <p>Released publicly as Android 8.0 in August 2017. * <p>Applications targeting this or a later release will get these * new changes in behavior. For more information about this release, see * the <a href="/about/versions/oreo/">Android Oreo overview</a>.</p> @@ -1020,6 +1059,7 @@ public class Build { /** * O MR1. * + * <p>Released publicly as Android 8.1 in December 2017. * <p>Applications targeting this or a later release will get these * new changes in behavior. For more information about this release, see * <a href="/about/versions/oreo/android-8.1">Android 8.1 features and @@ -1037,6 +1077,7 @@ public class Build { /** * P. * + * <p>Released publicly as Android 9 in August 2018. * <p>Applications targeting this or a later release will get these * new changes in behavior. For more information about this release, see the * <a href="/about/versions/pie/">Android 9 Pie overview</a>.</p> @@ -1054,6 +1095,7 @@ public class Build { /** * Q. * + * <p>Released publicly as Android 10 in September 2019. * <p>Applications targeting this or a later release will get these new changes in behavior. * For more information about this release, see the * <a href="/about/versions/10">Android 10 overview</a>.</p> @@ -1069,6 +1111,7 @@ public class Build { /** * R. * + * <p>Released publicly as Android 11 in September 2020. * <p>Applications targeting this or a later release will get these new changes in behavior. * For more information about this release, see the * <a href="/about/versions/11">Android 11 overview</a>.</p> diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 4ef0e6e785e8..a52ede87880e 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -44,6 +44,7 @@ import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.media.AudioManager; +import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -1163,18 +1164,24 @@ public final class PermissionManager { * that doesn't participate in an attribution chain. * * @param source The attribution source to register. + * @return The registered new attribution source. * * @see #isRegisteredAttributionSource(AttributionSource) * * @hide */ @TestApi - public void registerAttributionSource(@NonNull AttributionSource source) { + public @NonNull AttributionSource registerAttributionSource(@NonNull AttributionSource source) { + // We use a shared static token for sources that are not registered since the token's + // only used for process death detection. If we are about to use the source for security + // enforcement we need to replace the binder with a unique one. + final AttributionSource registeredSource = source.withToken(new Binder()); try { - mPermissionManager.registerAttributionSource(source); + mPermissionManager.registerAttributionSource(registeredSource); } catch (RemoteException e) { e.rethrowFromSystemServer(); } + return registeredSource; } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0bce20f42170..75e334277ddb 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8758,8 +8758,6 @@ public final class Settings { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi - @Readable public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; /** diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index ff692818863a..ee8353a9f203 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -1969,7 +1969,17 @@ public class ZenModeConfig implements Parcelable { } public boolean isAutomaticActive() { - return enabled && !snoozing && pkg != null && isTrueOrUnknown(); + return enabled && !snoozing && getPkg() != null && isTrueOrUnknown(); + } + + public String getPkg() { + return !TextUtils.isEmpty(pkg) + ? pkg + : (component != null) + ? component.getPackageName() + : (configurationActivity != null) + ? configurationActivity.getPackageName() + : null; } public boolean isTrueOrUnknown() { diff --git a/core/java/android/service/voice/AbstractHotwordDetector.java b/core/java/android/service/voice/AbstractHotwordDetector.java index 54ccf309a58e..dbe108974684 100644 --- a/core/java/android/service/voice/AbstractHotwordDetector.java +++ b/core/java/android/service/voice/AbstractHotwordDetector.java @@ -20,7 +20,9 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityThread; import android.media.AudioFormat; +import android.media.permission.Identity; import android.os.Handler; import android.os.Looper; import android.os.ParcelFileDescriptor; @@ -111,8 +113,10 @@ abstract class AbstractHotwordDetector implements HotwordDetector { if (DEBUG) { Slog.d(TAG, "updateStateLocked()"); } + Identity identity = new Identity(); + identity.packageName = ActivityThread.currentOpPackageName(); try { - mManagerService.updateState(options, sharedMemory, callback); + mManagerService.updateState(identity, options, sharedMemory, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index ad09a48cf4c3..725e20f2a74d 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -2014,7 +2014,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall return mIndex; } - /**s + /** * @return the total number of activities for which the assist data is * being returned. */ diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java index bff168d1d72a..36d97af6fb0d 100644 --- a/core/java/android/util/apk/ApkSignatureVerifier.java +++ b/core/java/android/util/apk/ApkSignatureVerifier.java @@ -210,6 +210,7 @@ public class ApkSignatureVerifier { ApkSignatureSchemeV4Verifier.extractCertificates(apkPath); Certificate[][] signerCerts = new Certificate[][]{vSigner.certs}; Signature[] signerSigs = convertToSignatures(signerCerts); + Signature[] pastSignerSigs = null; if (verifyFull) { Map<Integer, byte[]> nonstreamingDigests; @@ -222,6 +223,15 @@ public class ApkSignatureVerifier { ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath); nonstreamingDigests = v3Signer.contentDigests; nonstreamingCerts = new Certificate[][]{v3Signer.certs}; + if (v3Signer.por != null) { + // populate proof-of-rotation information + pastSignerSigs = new Signature[v3Signer.por.certs.size()]; + for (int i = 0; i < pastSignerSigs.length; i++) { + pastSignerSigs[i] = new Signature( + v3Signer.por.certs.get(i).getEncoded()); + pastSignerSigs[i].setFlags(v3Signer.por.flagsList.get(i)); + } + } } catch (SignatureNotFoundException e) { try { ApkSignatureSchemeV2Verifier.VerifiedSigner v2Signer = @@ -262,7 +272,8 @@ public class ApkSignatureVerifier { } return new SigningDetailsWithDigests(new PackageParser.SigningDetails(signerSigs, - SignatureSchemeVersion.SIGNING_BLOCK_V4), vSigner.contentDigests); + SignatureSchemeVersion.SIGNING_BLOCK_V4, pastSignerSigs), + vSigner.contentDigests); } catch (SignatureNotFoundException e) { throw e; } catch (Exception e) { diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 145607ada4f4..6f915c9182d2 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -128,6 +128,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation */ @Appearance int getSystemBarsAppearance(); + default boolean isSystemBarsAppearanceControlled() { + return false; + } + /** * @see WindowInsetsController#setSystemBarsBehavior */ @@ -138,6 +142,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation */ @Behavior int getSystemBarsBehavior(); + default boolean isSystemBarsBehaviorControlled() { + return false; + } + /** * Releases a surface and ensure that this is done after {@link #applySurfaceParams} has * finished applying params. @@ -1520,6 +1528,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public @Appearance int getSystemBarsAppearance() { + if (!mHost.isSystemBarsAppearanceControlled()) { + // We only return the requested appearance, not the implied one. + return 0; + } return mHost.getSystemBarsAppearance(); } @@ -1544,6 +1556,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public @Behavior int getSystemBarsBehavior() { + if (!mHost.isSystemBarsBehaviorControlled()) { + // We only return the requested behavior, not the implied one. + return 0; + } return mHost.getSystemBarsBehavior(); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e98408bf0529..4cae8cae6014 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1957,22 +1957,23 @@ public final class ViewRootImpl implements ViewParent, return mBoundsLayer; } - Surface getOrCreateBLASTSurface(int width, int height, - @Nullable WindowManager.LayoutParams params) { + Surface getOrCreateBLASTSurface() { if (!mSurfaceControl.isValid()) { return null; } - int format = params == null ? PixelFormat.TRANSLUCENT : params.format; Surface ret = null; if (mBlastBufferQueue == null) { - mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl, width, height, - format); + mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl, + mSurfaceSize.x, mSurfaceSize.y, + mWindowAttributes.format); // We only return the Surface the first time, as otherwise // it hasn't changed and there is no need to update. ret = mBlastBufferQueue.createSurface(); } else { - mBlastBufferQueue.update(mSurfaceControl, width, height, format); + mBlastBufferQueue.update(mSurfaceControl, + mSurfaceSize.x, mSurfaceSize.y, + mWindowAttributes.format); } ScrollOptimizer.setBLASTBufferQueue(mBlastBufferQueue); @@ -2781,6 +2782,7 @@ public final class ViewRootImpl implements ViewParent, mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance); } } + final boolean wasReportNextDraw = mReportNextDraw; if (mFirst || windowShouldResize || viewVisibilityChanged || params != null || mForceNextWindowRelayout) { @@ -2827,6 +2829,16 @@ public final class ViewRootImpl implements ViewParent, final boolean dockedResizing = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0; final boolean dragResizing = freeformResizing || dockedResizing; + if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) { + if (DEBUG_BLAST) { + Log.d(mTag, "Relayout called with blastSync"); + } + reportNextDraw(); + if (isHardwareEnabled()) { + mNextDrawUseBlastSync = true; + } + } + if (mSurfaceControl.isValid()) { updateOpacity(mWindowAttributes, dragResizing); } @@ -3045,7 +3057,16 @@ public final class ViewRootImpl implements ViewParent, } } - if (!mStopped || mReportNextDraw) { + // TODO: In the CL "ViewRootImpl: Fix issue with early draw report in + // seamless rotation". We moved processing of RELAYOUT_RES_BLAST_SYNC + // earlier in the function, potentially triggering a call to + // reportNextDraw(). That same CL changed this and the next reference + // to wasReportNextDraw, such that this logic would remain undisturbed + // (it continues to operate as if the code was never moved). This was + // done to achieve a more hermetic fix for S, but it's entirely + // possible that checking the most recent value is actually more + // correct here. + if (!mStopped || wasReportNextDraw) { boolean focusChangedDueToTouchMode = ensureTouchModeLocally( (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0); if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() @@ -3115,7 +3136,7 @@ public final class ViewRootImpl implements ViewParent, prepareSurfaces(); } - final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); + final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw); boolean triggerGlobalLayoutListener = didLayout || mAttachInfo.mRecomputeGlobalAttributes; if (didLayout) { @@ -3271,21 +3292,10 @@ public final class ViewRootImpl implements ViewParent, mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); - final boolean wasReportNextDraw = mReportNextDraw; - // Remember if we must report the next draw. if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { reportNextDraw(); } - if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) { - if (DEBUG_BLAST) { - Log.d(mTag, "Relayout called with blastSync"); - } - reportNextDraw(); - if (isHardwareEnabled()) { - mNextDrawUseBlastSync = true; - } - } boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; @@ -3296,7 +3306,6 @@ public final class ViewRootImpl implements ViewParent, } mPendingTransitions.clear(); } - performDraw(); } else { if (isViewVisible) { @@ -7785,8 +7794,7 @@ public final class ViewRootImpl implements ViewParent, if (!useBLAST()) { mSurface.copyFrom(mSurfaceControl); } else { - final Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x, mSurfaceSize.y, - params); + final Surface blastSurface = getOrCreateBLASTSurface(); // If blastSurface == null that means it hasn't changed since the last time we // called. In this situation, avoid calling transferFrom as we would then // inc the generation ID and cause EGL resources to be recreated. diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java index 27821fd6608d..ce882da1a6da 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -180,14 +180,15 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { @Override public int getSystemBarsAppearance() { - if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { - // We only return the requested appearance, not the implied one. - return 0; - } return mViewRoot.mWindowAttributes.insetsFlags.appearance; } @Override + public boolean isSystemBarsAppearanceControlled() { + return (mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) != 0; + } + + @Override public void setSystemBarsBehavior(int behavior) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED; if (mViewRoot.mWindowAttributes.insetsFlags.behavior != behavior) { @@ -199,14 +200,15 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { @Override public int getSystemBarsBehavior() { - if ((mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) == 0) { - // We only return the requested behavior, not the implied one. - return 0; - } return mViewRoot.mWindowAttributes.insetsFlags.behavior; } @Override + public boolean isSystemBarsBehaviorControlled() { + return (mViewRoot.mWindowAttributes.privateFlags & PRIVATE_FLAG_BEHAVIOR_CONTROLLED) != 0; + } + + @Override public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) { // At the time we receive new leashes (e.g. InsetsSourceConsumer is processing diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 9c1285064afb..3df09c24ca30 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -740,8 +740,22 @@ public class AnalogClock extends View { } } - private void onTimeChanged() { - Instant now = mClock.instant(); + /** + * Return the current Instant to be used for drawing the clockface. Protected to allow + * subclasses to override this to show a different time from the system clock. + * + * @return the Instant to be shown on the clockface + * @hide + */ + protected Instant now() { + return mClock.instant(); + } + + /** + * @hide + */ + protected void onTimeChanged() { + Instant now = now(); onTimeChanged(now.atZone(mClock.getZone()).toLocalTime(), now.toEpochMilli()); } @@ -789,7 +803,7 @@ public class AnalogClock extends View { return; } - Instant now = mClock.instant(); + Instant now = now(); ZonedDateTime zonedDateTime = now.atZone(mClock.getZone()); LocalTime localTime = zonedDateTime.toLocalTime(); diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 472e3e72ab2f..c110ab956030 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -365,6 +365,10 @@ public class EdgeEffect { mDuration = PULL_TIME; mPullDistance += deltaDistance; + if (edgeEffectBehavior == TYPE_STRETCH) { + // Don't allow stretch beyond 1 + mPullDistance = Math.min(1f, mPullDistance); + } mDistance = Math.max(0f, mPullDistance); mVelocity = 0; @@ -783,6 +787,10 @@ public class EdgeEffect { + mDampedFreq * sinCoeff * Math.cos(mDampedFreq * deltaT)); mDistance = (float) distance / mHeight; mVelocity = (float) velocity; + if (mDistance > 1f) { + mDistance = 1f; + mVelocity = 0f; + } if (isAtEquilibrium()) { mDistance = 0; mVelocity = 0; diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index dddc08a88062..c8a4425409e8 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -231,6 +231,9 @@ interface IVoiceInteractionManagerService { /** * Set configuration and pass read-only data to hotword detection service. + * Caller must provide an identity, used for permission tracking purposes. + * The uid/pid elements of the identity will be ignored by the server and replaced with the ones + * provided by binder. * * @param options Application configuration data to provide to the * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or @@ -241,6 +244,7 @@ interface IVoiceInteractionManagerService { * @param callback Use this to report {@link HotwordDetectionService} status. */ void updateState( + in Identity originatorIdentity, in PersistableBundle options, in SharedMemory sharedMemory, in IHotwordRecognitionStatusCallback callback); diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java index 986bbc8628ec..b7f6a615a452 100644 --- a/core/java/com/android/internal/app/PlatLogoActivity.java +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -16,9 +16,9 @@ package com.android.internal.app; +import static android.graphics.PixelFormat.TRANSLUCENT; + import android.animation.ObjectAnimator; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.ActionBar; import android.app.Activity; import android.content.ActivityNotFoundException; @@ -26,22 +26,21 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.ColorFilter; -import android.graphics.LinearGradient; import android.graphics.Paint; -import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.provider.Settings; -import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.Log; +import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; -import android.view.animation.PathInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.AnalogClock; import android.widget.FrameLayout; import android.widget.ImageView; @@ -49,17 +48,22 @@ import com.android.internal.R; import org.json.JSONObject; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + /** * @hide */ public class PlatLogoActivity extends Activity { - private static final boolean WRITE_SETTINGS = true; - - private static final String R_EGG_UNLOCK_SETTING = "egg_mode_r"; + private static final String TAG = "PlatLogoActivity"; - private static final int UNLOCK_TRIES = 3; + private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s"; - BigDialView mDialView; + private SettableAnalogClock mClock; + private ImageView mLogo; + private BubblesDrawable mBg; @Override protected void onPause() { @@ -69,42 +73,81 @@ public class PlatLogoActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final float dp = getResources().getDisplayMetrics().density; - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); getWindow().setNavigationBarColor(0); getWindow().setStatusBarColor(0); final ActionBar ab = getActionBar(); if (ab != null) ab.hide(); - mDialView = new BigDialView(this, null); - if (Settings.System.getLong(getContentResolver(), - R_EGG_UNLOCK_SETTING, 0) == 0) { - mDialView.setUnlockTries(UNLOCK_TRIES); - } else { - mDialView.setUnlockTries(0); - } - final FrameLayout layout = new FrameLayout(this); - layout.setBackgroundColor(0xFFFF0000); - layout.addView(mDialView, FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT); + + mClock = new SettableAnalogClock(this); + + final DisplayMetrics dm = getResources().getDisplayMetrics(); + final float dp = dm.density; + final int minSide = Math.min(dm.widthPixels, dm.heightPixels); + final int widgetSize = (int) (minSide * 0.75); + final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(widgetSize, widgetSize); + lp.gravity = Gravity.CENTER; + layout.addView(mClock, lp); + + mLogo = new ImageView(this); + mLogo.setVisibility(View.GONE); + mLogo.setImageResource(R.drawable.platlogo); + layout.addView(mLogo, lp); + + mBg = new BubblesDrawable(); + mBg.setLevel(0); + mBg.avoid = widgetSize / 2; + mBg.padding = 0.5f * dp; + mBg.minR = 1 * dp; + layout.setBackground(mBg); + setContentView(layout); } + private boolean shouldWriteSettings() { + return getPackageName().equals("android"); + } + private void launchNextStage(boolean locked) { + mClock.animate() + .alpha(0f).scaleX(0.5f).scaleY(0.5f) + .withEndAction(() -> mClock.setVisibility(View.GONE)) + .start(); + + mLogo.setAlpha(0f); + mLogo.setScaleX(0.5f); + mLogo.setScaleY(0.5f); + mLogo.setVisibility(View.VISIBLE); + mLogo.animate() + .alpha(1f) + .scaleX(1f) + .scaleY(1f) + .setInterpolator(new OvershootInterpolator()) + .start(); + + mLogo.postDelayed(() -> { + final ObjectAnimator anim = ObjectAnimator.ofInt(mBg, "level", 0, 10000); + anim.setInterpolator(new DecelerateInterpolator(1f)); + anim.start(); + }, + 500 + ); + final ContentResolver cr = getContentResolver(); try { - if (WRITE_SETTINGS) { + if (shouldWriteSettings()) { + Log.v(TAG, "Saving egg unlock=" + locked); + syncTouchPressure(); Settings.System.putLong(cr, - R_EGG_UNLOCK_SETTING, + S_EGG_UNLOCK_SETTING, locked ? 0 : System.currentTimeMillis()); } } catch (RuntimeException e) { - Log.e("com.android.internal.app.PlatLogoActivity", "Can't write settings", e); + Log.e(TAG, "Can't write settings", e); } try { @@ -151,7 +194,7 @@ public class PlatLogoActivity extends Activity { if (mPressureMax >= 0) { touchData.put("min", mPressureMin); touchData.put("max", mPressureMax); - if (WRITE_SETTINGS) { + if (shouldWriteSettings()) { Settings.System.putString(getContentResolver(), TOUCH_STATS, touchData.toString()); } @@ -173,44 +216,35 @@ public class PlatLogoActivity extends Activity { super.onStop(); } - class BigDialView extends ImageView { - private static final int COLOR_GREEN = 0xff3ddc84; - private static final int COLOR_BLUE = 0xff4285f4; - private static final int COLOR_NAVY = 0xff073042; - private static final int COLOR_ORANGE = 0xfff86734; - private static final int COLOR_CHARTREUSE = 0xffeff7cf; - private static final int COLOR_LIGHTBLUE = 0xffd7effe; - - private static final int STEPS = 11; - private static final float VALUE_CHANGE_MAX = 1f / STEPS; - - private BigDialDrawable mDialDrawable; - private boolean mWasLocked; - - BigDialView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(); - } - - BigDialView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(); - } - - BigDialView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - init(); - } + /** + * Subclass of AnalogClock that allows the user to flip up the glass and adjust the hands. + */ + public class SettableAnalogClock extends AnalogClock { + private int mOverrideHour = -1; + private int mOverrideMinute = -1; + private boolean mOverride = false; - private void init() { - mDialDrawable = new BigDialDrawable(); - setImageDrawable(mDialDrawable); + public SettableAnalogClock(Context context) { + super(context); } @Override - public void onDraw(Canvas c) { - super.onDraw(c); + protected Instant now() { + final Instant realNow = super.now(); + final ZoneId tz = Clock.systemDefaultZone().getZone(); + final ZonedDateTime zdTime = realNow.atZone(tz); + if (mOverride) { + if (mOverrideHour < 0) { + mOverrideHour = zdTime.getHour(); + } + return Clock.fixed(zdTime + .withHour(mOverrideHour) + .withMinute(mOverrideMinute) + .withSecond(0) + .toInstant(), tz).instant(); + } else { + return realNow; + } } double toPositiveDegrees(double rad) { @@ -221,226 +255,174 @@ public class PlatLogoActivity extends Activity { public boolean onTouchEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: - mWasLocked = mDialDrawable.isLocked(); + mOverride = true; // pass through case MotionEvent.ACTION_MOVE: + measureTouchPressure(ev); + float x = ev.getX(); float y = ev.getY(); - float cx = (getLeft() + getRight()) / 2f; - float cy = (getTop() + getBottom()) / 2f; + float cx = getWidth() / 2f; + float cy = getHeight() / 2f; float angle = (float) toPositiveDegrees(Math.atan2(x - cx, y - cy)); - final int oldLevel = mDialDrawable.getUserLevel(); - mDialDrawable.touchAngle(angle); - final int newLevel = mDialDrawable.getUserLevel(); - if (oldLevel != newLevel) { - performHapticFeedback(newLevel == STEPS - ? HapticFeedbackConstants.CONFIRM - : HapticFeedbackConstants.CLOCK_TICK); + + int minutes = (75 - (int) (angle / 6)) % 60; + int minuteDelta = minutes - mOverrideMinute; + if (minuteDelta != 0) { + if (Math.abs(minuteDelta) > 45 && mOverrideHour >= 0) { + int hourDelta = (minuteDelta < 0) ? 1 : -1; + mOverrideHour = (mOverrideHour + 24 + hourDelta) % 24; + } + mOverrideMinute = minutes; + if (mOverrideMinute == 0) { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + if (getScaleX() == 1f) { + setScaleX(1.05f); + setScaleY(1.05f); + animate().scaleX(1f).scaleY(1f).setDuration(150).start(); + } + } else { + performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); + } + + onTimeChanged(); + postInvalidate(); } + return true; case MotionEvent.ACTION_UP: - if (mWasLocked != mDialDrawable.isLocked()) { - launchNextStage(mDialDrawable.isLocked()); + if (mOverrideMinute == 0 && (mOverrideHour % 12) == 0) { + Log.v(TAG, "12:00 let's gooooo"); + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + launchNextStage(false); } return true; } return false; } + } - @Override - public boolean performClick() { - if (mDialDrawable.getUserLevel() < STEPS - 1) { - mDialDrawable.setUserLevel(mDialDrawable.getUserLevel() + 1); - performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); - } - return true; - } - - void setUnlockTries(int tries) { - mDialDrawable.setUnlockTries(tries); - } + static class Bubble { + public float x, y, r; + public int color; + } - private class BigDialDrawable extends Drawable { - public final int STEPS = 10; - private int mUnlockTries = 0; - final Paint mPaint = new Paint(); - final Drawable mEleven; - private boolean mNightMode; - private float mValue = 0f; - float mElevenAnim = 0f; - ObjectAnimator mElevenShowAnimator = ObjectAnimator.ofFloat(this, "elevenAnim", 0f, - 1f).setDuration(300); - ObjectAnimator mElevenHideAnimator = ObjectAnimator.ofFloat(this, "elevenAnim", 1f, - 0f).setDuration(500); - - BigDialDrawable() { - mNightMode = getContext().getResources().getConfiguration().isNightModeActive(); - mEleven = getContext().getDrawable(R.drawable.ic_number11); - mElevenShowAnimator.setInterpolator(new PathInterpolator(0.4f, 0f, 0.2f, 1f)); - mElevenHideAnimator.setInterpolator(new PathInterpolator(0.8f, 0.2f, 0.6f, 1f)); - } + class BubblesDrawable extends Drawable { + private static final int MAX_BUBBS = 2000; - public void setUnlockTries(int count) { - if (mUnlockTries != count) { - mUnlockTries = count; - setValue(getValue()); - invalidateSelf(); - } - } + private final int[] mColorIds = { + android.R.color.system_accent1_400, + android.R.color.system_accent1_500, + android.R.color.system_accent1_600, - boolean isLocked() { - return mUnlockTries > 0; - } + android.R.color.system_accent2_400, + android.R.color.system_accent2_500, + android.R.color.system_accent2_600, + }; - public void setValue(float v) { - // until the dial is "unlocked", you can't turn it all the way to 11 - final float max = isLocked() ? 1f - 1f / STEPS : 1f; - mValue = v < 0f ? 0f : v > max ? max : v; - invalidateSelf(); - } + private int[] mColors = new int[mColorIds.length]; - public float getValue() { - return mValue; - } + private final Bubble[] mBubbs = new Bubble[MAX_BUBBS]; + private int mNumBubbs; - public int getUserLevel() { - return Math.round(getValue() * STEPS - 0.25f); - } + private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - public void setUserLevel(int i) { - setValue(getValue() + ((float) i) / STEPS); - } + public float avoid = 0f; + public float padding = 0f; + public float minR = 0f; - public float getElevenAnim() { - return mElevenAnim; + BubblesDrawable() { + for (int i = 0; i < mColorIds.length; i++) { + mColors[i] = getColor(mColorIds[i]); } - - public void setElevenAnim(float f) { - if (mElevenAnim != f) { - mElevenAnim = f; - invalidateSelf(); - } + for (int j = 0; j < mBubbs.length; j++) { + mBubbs[j] = new Bubble(); } + } - @Override - public void draw(@NonNull Canvas canvas) { - final Rect bounds = getBounds(); - final int w = bounds.width(); - final int h = bounds.height(); - final float w2 = w / 2f; - final float h2 = h / 2f; - final float radius = w / 4f; - - canvas.drawColor(mNightMode ? COLOR_NAVY : COLOR_LIGHTBLUE); - - canvas.save(); - canvas.rotate(45, w2, h2); - canvas.clipRect(w2, h2 - radius, Math.min(w, h), h2 + radius); - final int gradientColor = mNightMode ? 0x60000020 : (0x10FFFFFF & COLOR_NAVY); - mPaint.setShader( - new LinearGradient(w2, h2, Math.min(w, h), h2, gradientColor, - 0x00FFFFFF & gradientColor, Shader.TileMode.CLAMP)); - mPaint.setColor(Color.BLACK); - canvas.drawPaint(mPaint); - mPaint.setShader(null); - canvas.restore(); - - mPaint.setStyle(Paint.Style.FILL); - mPaint.setColor(COLOR_GREEN); - - canvas.drawCircle(w2, h2, radius, mPaint); - - mPaint.setColor(mNightMode ? COLOR_LIGHTBLUE : COLOR_NAVY); - final float cx = w * 0.85f; - for (int i = 0; i < STEPS; i++) { - final float f = (float) i / STEPS; - canvas.save(); - final float angle = valueToAngle(f); - canvas.rotate(-angle, w2, h2); - canvas.drawCircle(cx, h2, (i <= getUserLevel()) ? 20 : 5, mPaint); - canvas.restore(); - } - - if (mElevenAnim > 0f) { - final int color = COLOR_ORANGE; - final int size2 = (int) ((0.5 + 0.5f * mElevenAnim) * w / 14); - final float cx11 = cx + size2 / 4f; - mEleven.setBounds((int) cx11 - size2, (int) h2 - size2, - (int) cx11 + size2, (int) h2 + size2); - final int alpha = 0xFFFFFF | ((int) clamp(0xFF * 2 * mElevenAnim, 0, 0xFF) - << 24); - mEleven.setTint(alpha & color); - mEleven.draw(canvas); - } - - // don't want to use the rounded value here since the quantization will be visible - final float angle = valueToAngle(mValue); - - // it's easier to draw at far-right and rotate backwards - canvas.rotate(-angle, w2, h2); - mPaint.setColor(Color.WHITE); - final float dimple = w2 / 12f; - canvas.drawCircle(w - radius - dimple * 2, h2, dimple, mPaint); + @Override + public void draw(Canvas canvas) { + final float f = getLevel() / 10000f; + mPaint.setStyle(Paint.Style.FILL); + int drawn = 0; + for (int j = 0; j < mNumBubbs; j++) { + if (mBubbs[j].color == 0 || mBubbs[j].r == 0) continue; + mPaint.setColor(mBubbs[j].color); + canvas.drawCircle(mBubbs[j].x, mBubbs[j].y, mBubbs[j].r * f, mPaint); + drawn++; } + } - float clamp(float x, float a, float b) { - return x < a ? a : x > b ? b : x; - } + @Override + protected boolean onLevelChange(int level) { + invalidateSelf(); + return true; + } - float angleToValue(float a) { - return 1f - clamp(a / (360 - 45), 0f, 1f); - } + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + randomize(); + } - // rotation: min is at 4:30, max is at 3:00 - float valueToAngle(float v) { - return (1f - v) * (360 - 45); + private void randomize() { + final float w = getBounds().width(); + final float h = getBounds().height(); + final float maxR = Math.min(w, h) / 3f; + mNumBubbs = 0; + if (avoid > 0f) { + mBubbs[mNumBubbs].x = w / 2f; + mBubbs[mNumBubbs].y = h / 2f; + mBubbs[mNumBubbs].r = avoid; + mBubbs[mNumBubbs].color = 0; + mNumBubbs++; } - - public void touchAngle(float a) { - final int oldUserLevel = getUserLevel(); - final float newValue = angleToValue(a); - // this is how we prevent the knob from snapping from max back to min, or from - // jumping around wherever the user presses. The new value must be pretty close - // to the - // previous one. - if (Math.abs(newValue - getValue()) < VALUE_CHANGE_MAX) { - setValue(newValue); - - if (isLocked() && oldUserLevel != STEPS - 1 && getUserLevel() == STEPS - 1) { - mUnlockTries--; - } else if (!isLocked() && getUserLevel() == 0) { - mUnlockTries = UNLOCK_TRIES; + for (int j = 0; j < MAX_BUBBS; j++) { + // a simple but time-tested bubble-packing algorithm: + // 1. pick a spot + // 2. shrink the bubble until it is no longer overlapping any other bubble + // 3. if the bubble hasn't popped, keep it + int tries = 5; + while (tries-- > 0) { + float x = (float) Math.random() * w; + float y = (float) Math.random() * h; + float r = Math.min(Math.min(x, w - x), Math.min(y, h - y)); + + // shrink radius to fit other bubbs + for (int i = 0; i < mNumBubbs; i++) { + r = (float) Math.min(r, + Math.hypot(x - mBubbs[i].x, y - mBubbs[i].y) - mBubbs[i].r + - padding); + if (r < minR) break; } - if (!isLocked()) { - if (getUserLevel() == STEPS && mElevenAnim != 1f - && !mElevenShowAnimator.isRunning()) { - mElevenHideAnimator.cancel(); - mElevenShowAnimator.start(); - } else if (getUserLevel() != STEPS && mElevenAnim == 1f - && !mElevenHideAnimator.isRunning()) { - mElevenShowAnimator.cancel(); - mElevenHideAnimator.start(); - } + if (r >= minR) { + // we have found a spot for this bubble to live, let's save it and move on + r = Math.min(maxR, r); + + mBubbs[mNumBubbs].x = x; + mBubbs[mNumBubbs].y = y; + mBubbs[mNumBubbs].r = r; + mBubbs[mNumBubbs].color = mColors[(int) (Math.random() * mColors.length)]; + mNumBubbs++; + break; } } } + Log.v(TAG, String.format("successfully placed %d bubbles (%d%%)", + mNumBubbs, (int) (100f * mNumBubbs / MAX_BUBBS))); + } - @Override - public void setAlpha(int i) { - } + @Override + public void setAlpha(int alpha) { } - @Override - public void setColorFilter(@Nullable ColorFilter colorFilter) { - } + @Override + public void setColorFilter(ColorFilter colorFilter) { } - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } + @Override + public int getOpacity() { + return TRANSLUCENT; } } -} - - +} diff --git a/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java b/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java index 848a5ba77317..d14adf6f3c20 100644 --- a/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java +++ b/core/java/com/android/internal/view/RecyclerViewCaptureHelper.java @@ -16,11 +16,6 @@ package com.android.internal.view; -import static com.android.internal.view.ScrollCaptureViewSupport.computeScrollAmount; -import static com.android.internal.view.ScrollCaptureViewSupport.findScrollingReferenceView; -import static com.android.internal.view.ScrollCaptureViewSupport.transformFromContainerToRequest; -import static com.android.internal.view.ScrollCaptureViewSupport.transformFromRequestToContainer; - import android.annotation.NonNull; import android.graphics.Rect; import android.util.Log; @@ -43,6 +38,7 @@ import android.view.ViewParent; */ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGroup> { private static final String TAG = "RVCaptureHelper"; + private int mScrollDelta; private boolean mScrollBarWasEnabled; private int mOverScrollMode; @@ -66,7 +62,6 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr result.scrollDelta = mScrollDelta; result.availableArea = new Rect(); // empty - Log.d(TAG, "current scrollDelta: " + mScrollDelta); if (!recyclerView.isVisibleToUser() || recyclerView.getChildCount() == 0) { Log.w(TAG, "recyclerView is empty or not visible, cannot continue"); return result; // result.availableArea == empty Rect @@ -76,22 +71,18 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr Rect requestedContainerBounds = new Rect(requestRect); requestedContainerBounds.offset(0, -mScrollDelta); requestedContainerBounds.offset(scrollBounds.left, scrollBounds.top); - // requestedContainerBounds is now in recyclerview-local coordinates - Log.d(TAG, "requestedContainerBounds: " + requestedContainerBounds); // Save a copy for later View anchor = findChildNearestTarget(recyclerView, requestedContainerBounds); if (anchor == null) { - Log.d(TAG, "Failed to locate anchor view"); - return result; // result.availableArea == null + Log.w(TAG, "Failed to locate anchor view"); + return result; // result.availableArea == empty rect } - Log.d(TAG, "Anchor view:" + anchor); Rect requestedContentBounds = new Rect(requestedContainerBounds); recyclerView.offsetRectIntoDescendantCoords(anchor, requestedContentBounds); - Log.d(TAG, "requestedContentBounds = " + requestedContentBounds); int prevAnchorTop = anchor.getTop(); // Note: requestChildRectangleOnScreen may modify rectangle, must pass pass in a copy here Rect input = new Rect(requestedContentBounds); @@ -101,34 +92,27 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr if (remainingHeight > 0) { input.inset(0, -remainingHeight / 2); } - Log.d(TAG, "input (post center adjustment) = " + input); if (recyclerView.requestChildRectangleOnScreen(anchor, input, true)) { int scrolled = prevAnchorTop - anchor.getTop(); // inverse of movement - Log.d(TAG, "RecyclerView scrolled by " + scrolled + " px"); mScrollDelta += scrolled; // view.top-- is equivalent to parent.scrollY++ result.scrollDelta = mScrollDelta; - Log.d(TAG, "requestedContentBounds, (post-request-rect) = " + requestedContentBounds); } requestedContainerBounds.set(requestedContentBounds); recyclerView.offsetDescendantRectToMyCoords(anchor, requestedContainerBounds); - Log.d(TAG, "requestedContainerBounds, (post-scroll): " + requestedContainerBounds); Rect recyclerLocalVisible = new Rect(scrollBounds); recyclerView.getLocalVisibleRect(recyclerLocalVisible); - Log.d(TAG, "recyclerLocalVisible: " + recyclerLocalVisible); if (!requestedContainerBounds.intersect(recyclerLocalVisible)) { // Requested area is still not visible - Log.d(TAG, "requested bounds not visible!"); return result; } Rect available = new Rect(requestedContainerBounds); available.offset(-scrollBounds.left, -scrollBounds.top); available.offset(0, mScrollDelta); result.availableArea = available; - Log.d(TAG, "availableArea: " + result.availableArea); return result; } @@ -154,22 +138,17 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr Rect parentLocalVis = new Rect(); parent.getLocalVisibleRect(parentLocalVis); - Log.d(TAG, "findChildNearestTarget: parentVis=" + parentLocalVis - + " targetRect=" + targetRect); Rect frame = new Rect(); for (int i = 0; i < parent.getChildCount(); i++) { final View child = parent.getChildAt(i); child.getHitRect(frame); - Log.d(TAG, "child #" + i + " hitRect=" + frame); if (child.getVisibility() != View.VISIBLE) { - Log.d(TAG, "child #" + i + " is not visible"); continue; } int centerDistance = Math.abs(targetRect.centerY() - frame.centerY()); - Log.d(TAG, "child #" + i + " : center to center: " + centerDistance + "px"); if (centerDistance < minCenterDistance) { // closer to center diff --git a/core/java/com/android/internal/view/ScrollCaptureInternal.java b/core/java/com/android/internal/view/ScrollCaptureInternal.java index ffee16a151df..e3a9fda7b000 100644 --- a/core/java/com/android/internal/view/ScrollCaptureInternal.java +++ b/core/java/com/android/internal/view/ScrollCaptureInternal.java @@ -34,7 +34,7 @@ public class ScrollCaptureInternal { private static final String TAG = "ScrollCaptureInternal"; // Log found scrolling views - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; // Log all investigated views, as well as heuristic checks private static final boolean DEBUG_VERBOSE = false; diff --git a/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java b/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java new file mode 100644 index 000000000000..481183e700a2 --- /dev/null +++ b/core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2021 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.internal.widget; + +import android.annotation.Nullable; +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.RemoteViews; + +import java.util.LinkedList; +import java.util.List; + +/** + * This is a subclass of LinearLayout meant to be used in the Conversation header, to fix a bug + * when multiple user-provided strings are shown in the same conversation header. b/189723284 + * + * This works around a deficiency in LinearLayout when shrinking views that it can't fully reduce + * all contents if any of the oversized views reaches zero. + */ +@RemoteViews.RemoteView +public class ConversationHeaderLinearLayout extends LinearLayout { + + public ConversationHeaderLinearLayout(Context context) { + super(context); + } + + public ConversationHeaderLinearLayout(Context context, + @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public ConversationHeaderLinearLayout(Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + private int calculateTotalChildLength() { + final int count = getChildCount(); + int totalLength = 0; + + for (int i = 0; i < count; ++i) { + final View child = getChildAt(i); + if (child == null || child.getVisibility() == GONE) { + continue; + } + final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) + child.getLayoutParams(); + totalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; + } + return totalLength + getPaddingLeft() + getPaddingRight(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + final int containerWidth = getMeasuredWidth(); + final int contentsWidth = calculateTotalChildLength(); + + int excessContents = contentsWidth - containerWidth; + if (excessContents <= 0) { + return; + } + final int count = getChildCount(); + + float remainingWeight = 0; + List<ViewInfo> visibleChildrenToShorten = null; + + // Find children which need to be shortened in order to ensure the contents fit. + for (int i = 0; i < count; ++i) { + final View child = getChildAt(i); + if (child == null || child.getVisibility() == View.GONE) { + continue; + } + final float weight = ((LayoutParams) child.getLayoutParams()).weight; + if (weight == 0) { + continue; + } + if (child.getMeasuredWidth() == 0) { + continue; + } + if (visibleChildrenToShorten == null) { + visibleChildrenToShorten = new LinkedList<>(); + } + visibleChildrenToShorten.add(new ViewInfo(child)); + remainingWeight += Math.max(0, weight); + } + if (visibleChildrenToShorten == null || visibleChildrenToShorten.isEmpty()) { + return; + } + balanceViewWidths(visibleChildrenToShorten, remainingWeight, excessContents); + remeasureChangedChildren(visibleChildrenToShorten); + } + + /** + * Measure any child with a width that has changed. + */ + private void remeasureChangedChildren(List<ViewInfo> childrenInfo) { + for (ViewInfo info : childrenInfo) { + if (info.mWidth != info.mStartWidth) { + final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( + Math.max(0, info.mWidth), MeasureSpec.EXACTLY); + final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + info.mView.getMeasuredHeight(), MeasureSpec.EXACTLY); + info.mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); + } + } + } + + /** + * Given a list of view, use the weights to remove width from each view proportionally to the + * weight (and ignoring the view's actual width), but do this iteratively whenever a view is + * reduced to zero width, because in that case other views need reduction. + */ + void balanceViewWidths(List<ViewInfo> viewInfos, float weightSum, int excessContents) { + boolean performAnotherPass = true; + // Loops only when all of the following are true: + // * `performAnotherPass` -- a view clamped to 0 width (or the first iteration) + // * `excessContents > 0` -- there is still horizontal space to allocate + // * `weightSum > 0` -- at least 1 view with nonzero width AND nonzero weight left + while (performAnotherPass && excessContents > 0 && weightSum > 0) { + int excessRemovedDuringThisPass = 0; + float weightSumForNextPass = 0; + performAnotherPass = false; + for (ViewInfo info : viewInfos) { + if (info.mWeight <= 0) { + continue; + } + if (info.mWidth <= 0) { + continue; + } + int newWidth = (int) (info.mWidth - (excessContents * (info.mWeight / weightSum))); + if (newWidth < 0) { + newWidth = 0; + performAnotherPass = true; + } + excessRemovedDuringThisPass += info.mWidth - newWidth; + info.mWidth = newWidth; + if (info.mWidth > 0) { + weightSumForNextPass += info.mWeight; + } + } + excessContents -= excessRemovedDuringThisPass; + weightSum = weightSumForNextPass; + } + } + + /** + * A helper class for measuring children. + */ + static class ViewInfo { + final View mView; + final float mWeight; + final int mStartWidth; + int mWidth; + + ViewInfo(View view) { + this.mView = view; + this.mWeight = ((LayoutParams) view.getLayoutParams()).weight; + this.mStartWidth = this.mWidth = view.getMeasuredWidth(); + } + } +} diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java index 1974b0c2e5fc..07ee9b5d2ff1 100644 --- a/core/java/com/android/internal/widget/NotificationExpandButton.java +++ b/core/java/com/android/internal/widget/NotificationExpandButton.java @@ -20,7 +20,6 @@ import android.annotation.ColorInt; import android.annotation.Nullable; import android.content.Context; import android.content.res.ColorStateList; -import android.graphics.PorterDuff; import android.graphics.Rect; import android.util.AttributeSet; import android.view.RemotableViewMethod; @@ -159,8 +158,7 @@ public class NotificationExpandButton extends FrameLayout { if (mHighlightPillColor != 0) { mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor)); } - mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN); - mIconView.setColorFilter(mHighlightTextColor, PorterDuff.Mode.SRC_IN); + mIconView.setColorFilter(mHighlightTextColor); if (mHighlightTextColor != 0) { mNumberView.setTextColor(mHighlightTextColor); } @@ -168,8 +166,7 @@ public class NotificationExpandButton extends FrameLayout { if (mDefaultPillColor != 0) { mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor)); } - mPillView.setBackgroundTintMode(PorterDuff.Mode.SRC_IN); - mIconView.setColorFilter(mDefaultTextColor, PorterDuff.Mode.SRC_IN); + mIconView.setColorFilter(mDefaultTextColor); if (mDefaultTextColor != 0) { mNumberView.setTextColor(mDefaultTextColor); } |