summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityManagerInternal.java2
-rw-r--r--core/java/android/app/ContextImpl.java3
-rw-r--r--core/java/android/app/IActivityManager.aidl1
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/ResourcesManager.java6
-rw-r--r--core/java/android/app/TaskInfo.java3
-rw-r--r--core/java/android/content/AttributionSource.java20
-rw-r--r--core/java/android/hardware/ISensorPrivacyManager.aidl2
-rw-r--r--core/java/android/hardware/SensorPrivacyManager.java8
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java14
-rw-r--r--core/java/android/hardware/location/ContextHubClientCallback.java7
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java3
-rwxr-xr-xcore/java/android/os/Build.java95
-rw-r--r--core/java/android/permission/PermissionManager.java11
-rw-r--r--core/java/android/provider/Settings.java2
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java12
-rw-r--r--core/java/android/service/voice/AbstractHotwordDetector.java6
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java2
-rw-r--r--core/java/android/util/apk/ApkSignatureVerifier.java13
-rw-r--r--core/java/android/view/InsetsController.java16
-rw-r--r--core/java/android/view/ViewRootImpl.java52
-rw-r--r--core/java/android/view/ViewRootInsetsControllerHost.java18
-rw-r--r--core/java/android/widget/AnalogClock.java20
-rw-r--r--core/java/android/widget/EdgeEffect.java8
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl4
-rw-r--r--core/java/com/android/internal/app/PlatLogoActivity.java476
-rw-r--r--core/java/com/android/internal/view/RecyclerViewCaptureHelper.java27
-rw-r--r--core/java/com/android/internal/view/ScrollCaptureInternal.java2
-rw-r--r--core/java/com/android/internal/widget/ConversationHeaderLinearLayout.java179
-rw-r--r--core/java/com/android/internal/widget/NotificationExpandButton.java7
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);
}