summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/hid/Android.bp2
-rw-r--r--cmds/uinput/Android.bp2
-rw-r--r--core/api/current.txt1
-rw-r--r--core/api/system-current.txt5
-rw-r--r--core/java/android/app/Notification.java40
-rw-r--r--core/java/android/content/pm/multiuser.aconfig30
-rw-r--r--core/java/android/hardware/OWNERS3
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java71
-rw-r--r--core/java/android/provider/ContactsContract.java194
-rw-r--r--core/java/android/view/Display.java7
-rw-r--r--core/java/android/window/BackMotionEvent.java34
-rw-r--r--core/java/android/window/BackTouchTracker.java10
-rw-r--r--core/java/android/window/ImeOnBackInvokedDispatcher.java4
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java2
-rw-r--r--core/java/com/android/internal/widget/NotificationProgressDrawable.java722
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/OWNERS1
-rw-r--r--core/jni/android_hardware_Camera.cpp23
-rw-r--r--core/jni/android_media_AudioFormat.h5
-rw-r--r--core/res/res/drawable/notification_progress_icon_background.xml20
-rw-r--r--core/res/res/layout/notification_template_material_progress.xml121
-rw-r--r--core/res/res/values/attrs.xml38
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/coretests/src/android/window/BackTouchTrackerTest.kt57
-rw-r--r--core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java2
-rw-r--r--keystore/OWNERS3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt72
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt6
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp24
-rw-r--r--libs/hwui/DeferredLayerUpdater.h9
-rw-r--r--media/java/android/media/AudioFormat.java23
-rw-r--r--media/java/android/media/AudioSystem.java2
-rw-r--r--nfc/Android.bp4
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java38
-rw-r--r--packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java5
-rw-r--r--packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml100
-rw-r--r--packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml221
-rw-r--r--packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml223
-rw-r--r--packages/SystemUI/res/drawable/contextual_edu_all_apps.xml25
-rw-r--r--packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml24
-rw-r--r--packages/SystemUI/res/drawable/contextual_edu_swipe_back.xml25
-rw-r--r--packages/SystemUI/res/drawable/contextual_edu_swipe_up.xml28
-rw-r--r--packages/SystemUI/res/layout/contextual_edu_dialog.xml45
-rw-r--r--packages/SystemUI/res/values-night/styles.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/res/values/styles.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt5
-rw-r--r--ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java15
-rw-r--r--ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt2
-rw-r--r--services/accessibility/accessibility.aconfig7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java11
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java11
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java12
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java13
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java20
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java69
-rw-r--r--services/core/java/com/android/server/hdmi/PowerManagerWrapper.java8
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java14
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java40
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java2
-rw-r--r--services/core/java/com/android/server/uri/UriPermission.java64
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java22
-rw-r--r--services/core/java/com/android/server/wm/Transition.java1
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java28
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java77
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java54
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java143
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java10
88 files changed, 2211 insertions, 932 deletions
diff --git a/cmds/hid/Android.bp b/cmds/hid/Android.bp
index a6e27698e36c..b93227a60d99 100644
--- a/cmds/hid/Android.bp
+++ b/cmds/hid/Android.bp
@@ -22,5 +22,5 @@ java_binary {
name: "hid",
wrapper: "hid.sh",
srcs: ["**/*.java"],
- required: ["libhidcommand_jni"],
+ jni_libs: ["libhidcommand_jni"],
}
diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp
index da497dcf908e..cec8a0d88b99 100644
--- a/cmds/uinput/Android.bp
+++ b/cmds/uinput/Android.bp
@@ -25,7 +25,7 @@ java_binary {
"src/**/*.java",
":uinputcommand_aidl",
],
- required: ["libuinputcommand_jni"],
+ jni_libs: ["libuinputcommand_jni"],
}
filegroup {
diff --git a/core/api/current.txt b/core/api/current.txt
index efede837d7a9..44b3c6232d59 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -21415,6 +21415,7 @@ package android.media {
field public static final int ENCODING_AAC_XHE = 16; // 0x10
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_AC4 = 17; // 0x11
+ field @FlaggedApi("android.media.audio.dolby_ac4_level4_encoding_api") public static final int ENCODING_AC4_L4 = 32; // 0x20
field public static final int ENCODING_DEFAULT = 1; // 0x1
field public static final int ENCODING_DOLBY_MAT = 19; // 0x13
field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 91c16c2dffde..8edfc21036ad 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -11957,6 +11957,11 @@ package android.provider {
}
@FlaggedApi("android.provider.new_default_account_api_enabled") public static final class ContactsContract.RawContacts.DefaultAccount {
+ method @FlaggedApi("android.provider.new_default_account_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS) public static java.util.List<android.accounts.Account> getEligibleCloudAccounts(@NonNull android.content.ContentResolver);
+ method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(allOf={android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS}) public static int getNumberOfMovableLocalContacts(@NonNull android.content.ContentResolver);
+ method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(allOf={android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS}) public static int getNumberOfMovableSimContacts(@NonNull android.content.ContentResolver);
+ method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(allOf={android.Manifest.permission.WRITE_CONTACTS, android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS}) public static void moveLocalContactsToCloudDefaultAccount(@NonNull android.content.ContentResolver);
+ method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(allOf={android.Manifest.permission.WRITE_CONTACTS, android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS}) public static void moveSimContactsToCloudDefaultAccount(@NonNull android.content.ContentResolver);
method @FlaggedApi("android.provider.new_default_account_api_enabled") @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS) public static void setDefaultAccountForNewContacts(@NonNull android.content.ContentResolver, @NonNull android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 38632bdeeff5..bc7ebce5c5c2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -810,6 +810,11 @@ public class Notification implements Parcelable
}
private static boolean isStandardLayout(int layoutId) {
+ if (Flags.apiRichOngoing()) {
+ if (layoutId == R.layout.notification_template_material_progress) {
+ return true;
+ }
+ }
return STANDARD_LAYOUTS.contains(layoutId);
}
@@ -7683,6 +7688,10 @@ public class Notification implements Parcelable
return R.layout.notification_template_material_conversation;
}
+ private int getProgressLayoutResource() {
+ return R.layout.notification_template_material_progress;
+ }
+
private int getActionLayoutResource() {
return R.layout.notification_material_action;
}
@@ -11640,6 +11649,37 @@ public class Notification implements Parcelable
return getStandardView(mBuilder.getHeadsUpBaseLayoutResource(), p, null /* result */);
}
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeBigContentView() {
+ StandardTemplateParams p = mBuilder.mParams.reset()
+ .viewType(StandardTemplateParams.VIEW_TYPE_BIG)
+ .allowTextWithProgress(true)
+ .fillTextsFrom(mBuilder);
+
+ // Replace the text with the big text, but only if the big text is not empty.
+ RemoteViews contentView = getStandardView(mBuilder.getProgressLayoutResource(), p,
+ null /* result */);
+
+ // Bind progress start and end icons.
+ if (mStartIcon != null) {
+ contentView.setViewVisibility(R.id.notification_progress_start_icon, View.VISIBLE);
+ contentView.setImageViewIcon(R.id.notification_progress_start_icon, mStartIcon);
+ } else {
+ contentView.setViewVisibility(R.id.notification_progress_start_icon, View.GONE);
+ }
+
+ if (mEndIcon != null) {
+ contentView.setViewVisibility(R.id.notification_progress_end_icon, View.VISIBLE);
+ contentView.setImageViewIcon(R.id.notification_progress_end_icon, mEndIcon);
+ } else {
+ contentView.setViewVisibility(R.id.notification_progress_end_icon, View.GONE);
+ }
+
+ return contentView;
+ }
private static @NonNull ArrayList<Bundle> getProgressSegmentsAsBundleList(
@Nullable List<Segment> progressSegments) {
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index cf65539946a9..fa26837a0429 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -208,6 +208,36 @@ flag {
}
flag {
+ name: "cache_profile_ids"
+ namespace: "multiuser"
+ description: "Cache getProfileIds to avoid unnecessary binder calls"
+ bug: "350421409"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "cache_profile_type"
+ namespace: "multiuser"
+ description: "Cache getProfileType to avoid unnecessary binder calls"
+ bug: "350417403"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "cache_profiles"
+ namespace: "multiuser"
+ description: "Cache getProfiles to avoid unnecessary binder calls"
+ bug: "350419395"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "fix_disabling_of_mu_toggle_when_restriction_applied"
namespace: "multiuser"
description: "When no_user_switch is set but no EnforcedAdmin is present, the toggle has to be disabled"
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 43d3f5466ccf..f11625ed9d61 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -19,3 +19,6 @@ per-file DataSpace* = file:/graphics/java/android/graphics/OWNERS
# OverlayProperties
per-file OverlayProperties* = file:/graphics/java/android/graphics/OWNERS
+
+# Lut related files
+per-file *Lut* = file:/graphics/java/android/graphics/OWNERS \ No newline at end of file
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 9e3a9b389b05..b7856303fc05 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -19,6 +19,7 @@ package android.hardware.camera2;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
import static android.content.Context.DEVICE_ID_DEFAULT;
+import static android.content.Context.DEVICE_ID_INVALID;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
@@ -36,6 +37,7 @@ import android.companion.virtual.VirtualDeviceManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.Overridable;
+import android.content.AttributionSource;
import android.content.AttributionSourceState;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -676,8 +678,8 @@ public final class CameraManager {
}
try {
for (String physicalCameraId : physicalCameraIds) {
- AttributionSourceState clientAttribution = getClientAttribution();
- clientAttribution.deviceId = DEVICE_ID_DEFAULT;
+ AttributionSourceState clientAttribution = getClientAttribution(DEVICE_ID_DEFAULT,
+ /* useContextAttributionSource= */ false);
CameraMetadataNative physicalCameraInfo =
cameraService.getCameraCharacteristics(
physicalCameraId,
@@ -974,27 +976,58 @@ public final class CameraManager {
}
/**
- * Constructs an AttributionSourceState with only the uid, pid, and deviceId fields set
+ * Retrieves the AttributionSourceState to pass to the CameraService.
*
- * <p>This method is a temporary stopgap in the transition to using AttributionSource. Currently
- * AttributionSourceState is only used as a vehicle for passing deviceId, uid, and pid
- * arguments.</p>
+ * @param deviceIdOverride An override of the AttributionSource's deviceId, if not equal to
+ * DEVICE_ID_INVALID
+ * @param useContextAttributionSource Whether to return the full attribution source provided by
+ * the Context.
+ *
+ * @hide
+ */
+ public AttributionSourceState getClientAttribution(int deviceIdOverride,
+ boolean useContextAttributionSource) {
+ AttributionSource contextAttributionSource = mContext.getAttributionSource();
+ if (deviceIdOverride != DEVICE_ID_INVALID) {
+ contextAttributionSource = contextAttributionSource.withDeviceId(deviceIdOverride);
+ }
+ AttributionSourceState contextAttributionSourceState =
+ contextAttributionSource.asState();
+
+ if (Flags.useContextAttributionSource() && useContextAttributionSource) {
+ return contextAttributionSourceState;
+ } else {
+ AttributionSourceState clientAttribution =
+ new AttributionSourceState();
+ clientAttribution.uid = USE_CALLING_UID;
+ clientAttribution.pid = USE_CALLING_PID;
+ clientAttribution.deviceId = contextAttributionSourceState.deviceId;
+ clientAttribution.packageName = mContext.getOpPackageName();
+ clientAttribution.attributionTag = mContext.getAttributionTag();
+ clientAttribution.next = new AttributionSourceState[0];
+ return clientAttribution;
+ }
+ }
+
+ /**
+ * Retrieves the AttributionSourceState to pass to the CameraService.
+ *
+ * @param useContextAttributionSource Whether to return the full attribution source provided by
+ * the Context.
+ *
+ * @hide
+ */
+ public AttributionSourceState getClientAttribution(boolean useContextAttributionSource) {
+ return getClientAttribution(DEVICE_ID_INVALID, useContextAttributionSource);
+ }
+
+ /**
+ * Retrieves the AttributionSourceState to pass to the CameraService.
*
* @hide
*/
public AttributionSourceState getClientAttribution() {
- // TODO: Send the full contextAttribution over aidl, remove USE_CALLING_*
- AttributionSourceState contextAttribution =
- mContext.getAttributionSource().asState();
- AttributionSourceState clientAttribution =
- new AttributionSourceState();
- clientAttribution.uid = USE_CALLING_UID;
- clientAttribution.pid = USE_CALLING_PID;
- clientAttribution.deviceId = contextAttribution.deviceId;
- clientAttribution.packageName = mContext.getOpPackageName();
- clientAttribution.attributionTag = mContext.getAttributionTag();
- clientAttribution.next = new AttributionSourceState[0];
- return clientAttribution;
+ return getClientAttribution(DEVICE_ID_INVALID, /* useContextAttributionSource= */ false);
}
/**
@@ -1049,7 +1082,7 @@ public final class CameraManager {
}
AttributionSourceState clientAttribution =
- getClientAttribution();
+ getClientAttribution(/* useContextAttributionSource= */ true);
cameraUser =
cameraService.connectDevice(
callbacks,
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d557046280d9..98d58d0c991f 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3028,6 +3028,13 @@ public final class ContactsContract {
@FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
public static final class DefaultAccount {
/**
+ * no public constructor since this is a utility class
+ */
+ private DefaultAccount() {
+
+ }
+
+ /**
* Key in the outgoing Bundle for the default account list.
*
* @hide
@@ -3063,11 +3070,6 @@ public final class ContactsContract {
public static final String QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD =
"queryDefaultAccountForNewContacts";
- private DefaultAccount() {
-
- }
-
-
/**
* Represents the state of the default account, and the actual {@link Account} if it's
* a cloud account.
@@ -3356,6 +3358,188 @@ public final class ContactsContract {
nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
SET_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD, null, extras);
}
+
+ /**
+ * Get a list of cloud accounts that is eligible to set as default account with state of
+ * {@link DefaultAccountAndState#DEFAULT_ACCOUNT_STATE_CLOUD}. May be empty but never
+ * null.
+ *
+ * @param resolver content resolver to query.
+ * @return a of cloud accounts that is eligible to set as default account with state of
+ * {@link DefaultAccountAndState#DEFAULT_ACCOUNT_STATE_CLOUD}.
+ * @throws RuntimeException if the query fails.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
+ @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+ @SystemApi
+ public static @NonNull List<Account> getEligibleCloudAccounts(
+ @NonNull ContentResolver resolver) {
+ Bundle response = nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
+ QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD, null, null);
+ List<Account> result = response.getParcelableArrayList(
+ KEY_ELIGIBLE_DEFAULT_ACCOUNTS, Account.class);
+ if (result == null) {
+ return new ArrayList<>();
+ }
+ return result;
+ }
+
+
+
+ /**
+ * The method to invoke to move local {@link RawContacts} and {@link Groups} from local
+ * account(s) to the Cloud Default Account (if any).
+ *
+ * @hide
+ */
+ public static final String MOVE_LOCAL_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD =
+ "moveLocalContactsToCloudDefaultAccount";
+
+ /**
+ * Move {@link RawContacts} and {@link Groups} (if any) from the local account to the
+ * Cloud Default Account (if any).
+ * @param resolver the ContentResolver to query.
+ * @throws RuntimeException if it fails to move contacts to the default account.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+ @RequiresPermission(allOf = {android.Manifest.permission.WRITE_CONTACTS,
+ android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
+ public static void moveLocalContactsToCloudDefaultAccount(
+ @NonNull ContentResolver resolver) {
+
+ Bundle extras = new Bundle();
+ Bundle result = nullSafeCall(
+ resolver,
+ ContactsContract.AUTHORITY_URI,
+ MOVE_LOCAL_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD,
+ null,
+ extras);
+ }
+
+ /**
+ * The method to invoke to move {@link RawContacts} and {@link Groups} from SIM
+ * account(s) to the Cloud Default Account (if any).
+ *
+ * @hide
+ */
+ public static final String MOVE_SIM_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD =
+ "moveSimContactsToCloudDefaultAccount";
+
+ /**
+ * Move {@link RawContacts} and {@link Groups} (if any) from the local account to the
+ * Cloud Default Account (if any).
+ * @param resolver the ContentResolver to query.
+ * @throws RuntimeException if it fails to move contacts to the default account.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+ @RequiresPermission(allOf = {android.Manifest.permission.WRITE_CONTACTS,
+ android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
+ public static void moveSimContactsToCloudDefaultAccount(
+ @NonNull ContentResolver resolver) {
+ Bundle result = nullSafeCall(
+ resolver,
+ ContactsContract.AUTHORITY_URI,
+ MOVE_SIM_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD,
+ /* arg= */ null,
+ /* extras= */ null);
+ }
+
+ /**
+ * The method to invoke to get the number of {@link RawContacts} that are in local
+ * account(s) and movable to the Cloud Default Account (if any).
+ *
+ * @hide
+ */
+ public static final String GET_NUMBER_OF_MOVABLE_LOCAL_CONTACTS_METHOD =
+ "getNumberOfMovableLocalContacts";
+
+ /**
+ * The result key for moving local {@link RawContacts} and {@link Groups} from SIM
+ * account(s) to the Cloud Default Account (if any).
+ *
+ * @hide
+ */
+ public static final String KEY_NUMBER_OF_MOVABLE_LOCAL_CONTACTS =
+ "key_number_of_movable_local_contacts";
+
+ /**
+ * Gets the number of {@link RawContacts} in the local account(s) which may be moved
+ * using {@link DefaultAccount#moveLocalContactsToCloudDefaultAccount} (if any).
+ * @param resolver the ContentResolver to query.
+ * @return the number of {@link RawContacts} in the local account(s), or 0 if there is
+ * no Cloud Default Account.
+ * @throws RuntimeException if it fails get the number of movable local contacts.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+ @RequiresPermission(allOf = {android.Manifest.permission.READ_CONTACTS,
+ android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
+ public static int getNumberOfMovableLocalContacts(
+ @NonNull ContentResolver resolver) {
+ Bundle result = nullSafeCall(
+ resolver,
+ ContactsContract.AUTHORITY_URI,
+ GET_NUMBER_OF_MOVABLE_LOCAL_CONTACTS_METHOD,
+ /* arg= */ null,
+ /* extras= */ null);
+ return result.getInt(KEY_NUMBER_OF_MOVABLE_LOCAL_CONTACTS,
+ /* defaultValue= */ 0);
+ }
+
+ /**
+ * The method to invoke to get the number of {@link RawContacts} that are in SIM
+ * account(s) and movable to the Cloud Default Account (if any).
+ *
+ * @hide
+ */
+ public static final String GET_NUMBER_OF_MOVABLE_SIM_CONTACTS_METHOD =
+ "getNumberOfMovableSimContacts";
+
+ /**
+ * The result key for moving local {@link RawContacts} and {@link Groups} from SIM
+ * account(s) to the Cloud Default Account (if any).
+ *
+ * @hide
+ */
+ public static final String KEY_NUMBER_OF_MOVABLE_SIM_CONTACTS =
+ "key_number_of_movable_sim_contacts";
+
+ /**
+ * Gets the number of {@link RawContacts} in the SIM account(s) which may be moved using
+ * {@link DefaultAccount#moveSimContactsToCloudDefaultAccount} (if any).
+ * @param resolver the ContentResolver to query.
+ * @return the number of {@link RawContacts} in the SIM account(s), or 0 if there is
+ * no Cloud Default Account.
+ * @throws RuntimeException if it fails get the number of movable sim contacts.
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+ @RequiresPermission(allOf = {android.Manifest.permission.READ_CONTACTS,
+ android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
+ public static int getNumberOfMovableSimContacts(
+ @NonNull ContentResolver resolver) {
+ Bundle result = nullSafeCall(
+ resolver,
+ ContactsContract.AUTHORITY_URI,
+ GET_NUMBER_OF_MOVABLE_SIM_CONTACTS_METHOD,
+ /* arg= */ null,
+ /* extras= */ null);
+ return result.getInt(KEY_NUMBER_OF_MOVABLE_SIM_CONTACTS,
+ /* defaultValue= */ 0);
+ }
+
}
/**
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 53935e810913..8a8022c0206a 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -449,6 +449,13 @@ public final class Display {
public static final int TYPE_VIRTUAL = 5;
/**
+ * The maximum display type value.
+ * Helpful to get all possible display values.
+ * @hide
+ */
+ public static final int TYPE_MAX = TYPE_VIRTUAL;
+
+ /**
* Display state: The display state is unknown.
*
* @see #getState
diff --git a/core/java/android/window/BackMotionEvent.java b/core/java/android/window/BackMotionEvent.java
index 7cda3a36da95..8ac68abd8d8e 100644
--- a/core/java/android/window/BackMotionEvent.java
+++ b/core/java/android/window/BackMotionEvent.java
@@ -34,8 +34,6 @@ public final class BackMotionEvent implements Parcelable {
private final float mTouchX;
private final float mTouchY;
private final float mProgress;
- private final float mVelocityX;
- private final float mVelocityY;
private final boolean mTriggerBack;
@BackEvent.SwipeEdge
@@ -51,10 +49,6 @@ public final class BackMotionEvent implements Parcelable {
* @param touchX Absolute X location of the touch point of this event.
* @param touchY Absolute Y location of the touch point of this event.
* @param progress Value between 0 and 1 on how far along the back gesture is.
- * @param velocityX X velocity computed from the touch point of this event.
- * Value in pixels/second. {@link Float#NaN} if was not computed.
- * @param velocityY Y velocity computed from the touch point of this event.
- * Value in pixels/second. {@link Float#NaN} if was not computed.
* @param triggerBack Indicates whether the back arrow is in the triggered state or not
* @param swipeEdge Indicates which edge the swipe starts from.
* @param departingAnimationTarget The remote animation target of the departing
@@ -64,16 +58,12 @@ public final class BackMotionEvent implements Parcelable {
float touchX,
float touchY,
float progress,
- float velocityX,
- float velocityY,
boolean triggerBack,
@BackEvent.SwipeEdge int swipeEdge,
@Nullable RemoteAnimationTarget departingAnimationTarget) {
mTouchX = touchX;
mTouchY = touchY;
mProgress = progress;
- mVelocityX = velocityX;
- mVelocityY = velocityY;
mTriggerBack = triggerBack;
mSwipeEdge = swipeEdge;
mDepartingAnimationTarget = departingAnimationTarget;
@@ -83,8 +73,6 @@ public final class BackMotionEvent implements Parcelable {
mTouchX = in.readFloat();
mTouchY = in.readFloat();
mProgress = in.readFloat();
- mVelocityX = in.readFloat();
- mVelocityY = in.readFloat();
mTriggerBack = in.readBoolean();
mSwipeEdge = in.readInt();
mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
@@ -113,8 +101,6 @@ public final class BackMotionEvent implements Parcelable {
dest.writeFloat(mTouchX);
dest.writeFloat(mTouchY);
dest.writeFloat(mProgress);
- dest.writeFloat(mVelocityX);
- dest.writeFloat(mVelocityY);
dest.writeBoolean(mTriggerBack);
dest.writeInt(mSwipeEdge);
dest.writeTypedObject(mDepartingAnimationTarget, flags);
@@ -145,24 +131,6 @@ public final class BackMotionEvent implements Parcelable {
}
/**
- * Returns the X velocity computed from the touch point.
- *
- * @return value in pixels/second or {@link Float#NaN} if was not computed.
- */
- public float getVelocityX() {
- return mVelocityX;
- }
-
- /**
- * Returns the Y velocity computed from the touch point.
- *
- * @return value in pixels/second or {@link Float#NaN} if was not computed.
- */
- public float getVelocityY() {
- return mVelocityY;
- }
-
- /**
* Returns whether the back arrow is in the triggered state or not
*
* @return boolean indicating whether the back arrow is in the triggered state or not
@@ -195,8 +163,6 @@ public final class BackMotionEvent implements Parcelable {
+ "mTouchX=" + mTouchX
+ ", mTouchY=" + mTouchY
+ ", mProgress=" + mProgress
- + ", mVelocityX=" + mVelocityX
- + ", mVelocityY=" + mVelocityY
+ ", mTriggerBack=" + mTriggerBack
+ ", mSwipeEdge" + mSwipeEdge
+ ", mDepartingAnimationTarget" + mDepartingAnimationTarget
diff --git a/core/java/android/window/BackTouchTracker.java b/core/java/android/window/BackTouchTracker.java
index eb23af27a24d..290c494b1bff 100644
--- a/core/java/android/window/BackTouchTracker.java
+++ b/core/java/android/window/BackTouchTracker.java
@@ -48,8 +48,6 @@ public class BackTouchTracker {
*/
private float mInitTouchX;
private float mInitTouchY;
- private float mLatestVelocityX;
- private float mLatestVelocityY;
private float mStartThresholdX;
private int mSwipeEdge;
private boolean mShouldUpdateStartLocation = false;
@@ -58,7 +56,7 @@ public class BackTouchTracker {
/**
* Updates the tracker with a new motion event.
*/
- public void update(float touchX, float touchY, float velocityX, float velocityY) {
+ public void update(float touchX, float touchY) {
/**
* If back was previously cancelled but the user has started swiping in the forward
* direction again, restart back.
@@ -73,8 +71,6 @@ public class BackTouchTracker {
}
mLatestTouchX = touchX;
mLatestTouchY = touchY;
- mLatestVelocityX = velocityX;
- mLatestVelocityY = velocityY;
}
/** Sets whether the back gesture is past the trigger threshold. */
@@ -156,8 +152,6 @@ public class BackTouchTracker {
/* touchX = */ mInitTouchX,
/* touchY = */ mInitTouchY,
/* progress = */ 0,
- /* velocityX = */ 0,
- /* velocityY = */ 0,
/* triggerBack = */ mTriggerBack,
/* swipeEdge = */ mSwipeEdge,
/* departingAnimationTarget = */ target);
@@ -242,8 +236,6 @@ public class BackTouchTracker {
/* touchX = */ mLatestTouchX,
/* touchY = */ mLatestTouchY,
/* progress = */ progress,
- /* velocityX = */ mLatestVelocityX,
- /* velocityY = */ mLatestVelocityY,
/* triggerBack = */ mTriggerBack,
/* swipeEdge = */ mSwipeEdge,
/* departingAnimationTarget = */ null);
diff --git a/core/java/android/window/ImeOnBackInvokedDispatcher.java b/core/java/android/window/ImeOnBackInvokedDispatcher.java
index 771dc7a99c0e..66c35e2fe837 100644
--- a/core/java/android/window/ImeOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ImeOnBackInvokedDispatcher.java
@@ -237,7 +237,7 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc
try {
mIOnBackInvokedCallback.onBackStarted(
new BackMotionEvent(backEvent.getTouchX(), backEvent.getTouchY(),
- backEvent.getProgress(), 0f, 0f, false, backEvent.getSwipeEdge(),
+ backEvent.getProgress(), false, backEvent.getSwipeEdge(),
null));
} catch (RemoteException e) {
Log.e(TAG, "Exception when invoking forwarded callback. e: ", e);
@@ -249,7 +249,7 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc
try {
mIOnBackInvokedCallback.onBackProgressed(
new BackMotionEvent(backEvent.getTouchX(), backEvent.getTouchY(),
- backEvent.getProgress(), 0f, 0f, false, backEvent.getSwipeEdge(),
+ backEvent.getProgress(), false, backEvent.getSwipeEdge(),
null));
} catch (RemoteException e) {
Log.e(TAG, "Exception when invoking forwarded callback. e: ", e);
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 51bc7d5c571b..44a374fb7c20 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -124,7 +124,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
if (!isBackGestureInProgress() || ev == null || ev.getAction() != MotionEvent.ACTION_MOVE) {
return;
}
- mTouchTracker.update(ev.getX(), ev.getY(), Float.NaN, Float.NaN);
+ mTouchTracker.update(ev.getX(), ev.getY());
if (mTouchTracker.shouldUpdateStartLocation()) {
// Reset the start location on the first event after starting back, so that
// the beginning of the animation feels smooth.
diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
new file mode 100644
index 000000000000..4d88546a1bd8
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2024 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.content.pm.ActivityInfo.Config;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.DashPathEffect;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * This is used by NotificationProgressBar for displaying a custom background. It composes of
+ * segments, which have non-zero length, and points, which have zero length.
+ *
+ * @see Segment
+ * @see Point
+ */
+public final class NotificationProgressDrawable extends Drawable {
+ private static final String TAG = "NotifProgressDrawable";
+
+ private State mState;
+ private boolean mMutated;
+
+ private final ArrayList<Part> mParts = new ArrayList<>();
+
+ private final Rect mPointRect = new Rect();
+ private final RectF mPointRectF = new RectF();
+
+ private final Paint mStrokePaint = new Paint();
+ private final Paint mDashedStrokePaint = new Paint();
+ private final Paint mFillPaint = new Paint();
+
+ {
+ mStrokePaint.setStyle(Paint.Style.STROKE);
+ mStrokePaint.setStrokeCap(Paint.Cap.ROUND);
+
+ mDashedStrokePaint.setStyle(Paint.Style.STROKE);
+
+ mFillPaint.setStyle(Paint.Style.FILL);
+ }
+
+ private int mAlpha;
+
+ public NotificationProgressDrawable() {
+ this(new State(), null);
+ }
+
+ /**
+ * <p>Set the stroke width and default color for the drawable.</p>
+ * <p>Note: changing this property will affect all instances of a drawable loaded from a
+ * resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param width The width in pixels of the stroke
+ * @param color The color of the stroke
+ * @see #mutate()
+ * @see #setStroke(int, int, float, float)
+ */
+ public void setStroke(int width, @ColorInt int color) {
+ setStroke(width, color, 0, 0);
+ }
+
+ /**
+ * <p>Set the stroke width and default color for the drawable. This method can also be used
+ * to dash the stroke for the dashed segments.</p>
+ * <p>Note: changing this property will affect all instances of a drawable loaded from a
+ * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
+ *
+ * @param width The width in pixels of the stroke
+ * @param color The color of the stroke
+ * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes
+ * @param dashGap The gap in pixels between dashes
+ * @see #mutate()
+ * @see #setStroke(int, int)
+ */
+ public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) {
+ mState.setStroke(width, color, dashWidth, dashGap);
+ setStrokeInternal(width, dashWidth, dashGap);
+ }
+
+ /**
+ * <p>Set the stroke default color for the drawable.</p>
+ * <p>Note: changing this property will affect all instances of a drawable loaded from a
+ * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
+ *
+ * @param color The color of the stroke
+ * @see #mutate()
+ * @see #setStroke(int, int, float, float)
+ */
+ public void setStrokeDefaultColor(@ColorInt int color) {
+ mState.mStrokeColor = color;
+ }
+
+ /**
+ * <p>Set the point rect default color for the drawable.</p>
+ * <p>Note: changing this property will affect all instances of a drawable loaded from a
+ * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
+ *
+ * @param color The color of the point rect
+ * @see #mutate()
+ */
+ public void setPointRectDefaultColor(@ColorInt int color) {
+ mState.mPointRectColor = color;
+ }
+
+ private void setStrokeInternal(int width, float dashWidth, float dashGap) {
+ mStrokePaint.setStrokeWidth(width);
+
+ mDashedStrokePaint.setStrokeWidth(width);
+ DashPathEffect e = null;
+ if (dashWidth > 0) {
+ e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0);
+ }
+ mDashedStrokePaint.setPathEffect(e);
+
+ invalidateSelf();
+ }
+
+ /**
+ *
+ */
+ public void setParts(@NonNull Part... parts) {
+ mParts.clear();
+ mParts.addAll(Arrays.asList(parts));
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ final float pointRadius =
+ mState.mPointRadius; // how big the point icon will be, halved
+
+ // generally, we will start drawing at (x, y) and end at (x+w, y)
+ float x = (float) getBounds().left;
+ final float centerY = (float) getBounds().centerY();
+ final float totalWidth = (float) getBounds().width();
+
+ final int numParts = mParts.size();
+ for (int iPart = 0; iPart < numParts; iPart++) {
+ final Part part = mParts.get(iPart);
+ final Part prevPart = iPart == 0 ? null : mParts.get(iPart - 1);
+ final Part nextPart = iPart + 1 == numParts ? null : mParts.get(iPart + 1);
+ if (part instanceof Segment segment) {
+ final float segWidth = segment.mFraction * totalWidth;
+ // Advance the start position to account for a point immediately prior.
+ final float startOffset = getSegStartOffset(prevPart, pointRadius,
+ mState.mSegPointGap);
+ final float start = x + startOffset;
+ // Retract the end position to account for the padding and a point immediately
+ // after.
+ final float endOffset = getSegEndOffset(nextPart, pointRadius, mState.mSegPointGap,
+ mState.mSegSegGap);
+ final float end = x + segWidth - endOffset;
+
+ // Transparent is not allowed (and also is the default in the data), so use that
+ // as a sentinel to be replaced by default
+ mStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
+ : mState.mStrokeColor);
+ mDashedStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
+ : mState.mStrokeColor);
+
+ // Leave space for the rounded line cap which extends beyond start/end.
+ final float capWidth = mStrokePaint.getStrokeWidth() / 2F;
+
+ canvas.drawLine(start + capWidth, centerY, end - capWidth, centerY,
+ segment.mDashed ? mDashedStrokePaint : mStrokePaint);
+
+ // Advance the current position to account for the segment's fraction of the total
+ // width (ignoring offset and padding)
+ x += segWidth;
+ } else if (part instanceof Point point) {
+ mPointRect.set((int) (x - pointRadius), (int) (centerY - pointRadius),
+ (int) (x + pointRadius), (int) (centerY + pointRadius));
+ if (point.mIcon != null) {
+ point.mIcon.setBounds(mPointRect);
+ point.mIcon.draw(canvas);
+ } else {
+ // TODO: b/367804171 - actually use a vector asset for the default point
+ // rather than drawing it as a box?
+ mPointRectF.set(mPointRect);
+ final float inset = mState.mPointRectInset;
+ final float cornerRadius = mState.mPointRectCornerRadius;
+ mPointRectF.inset(inset, inset);
+
+ mFillPaint.setColor(point.mColor != Color.TRANSPARENT ? point.mColor
+ : mState.mPointRectColor);
+
+ canvas.drawRoundRect(mPointRectF, cornerRadius, cornerRadius, mFillPaint);
+ }
+ }
+ }
+ }
+
+ private static float getSegStartOffset(Part prevPart, float pointRadius, float segPointGap) {
+ return (prevPart instanceof Point) ? pointRadius + segPointGap : 0F;
+ }
+
+ private static float getSegEndOffset(Part nextPart, float pointRadius, float segPointGap,
+ float segSegGap) {
+ if (nextPart == null) return 0F;
+ return (nextPart instanceof Point) ? segPointGap + pointRadius : segSegGap;
+ }
+
+ @Override
+ public @Config int getChangingConfigurations() {
+ return super.getChangingConfigurations() | mState.getChangingConfigurations();
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ if (mAlpha != alpha) {
+ mAlpha = alpha;
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public int getAlpha() {
+ return mAlpha;
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ // NO-OP
+ }
+
+ @Override
+ public int getOpacity() {
+ // This method is deprecated. Hence we return UNKNOWN.
+ return PixelFormat.UNKNOWN;
+ }
+
+ @Override
+ public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Resources.Theme theme)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs, theme);
+
+ mState.setDensity(resolveDensity(r, 0));
+
+ final TypedArray a = obtainAttributes(r, theme, attrs,
+ R.styleable.NotificationProgressDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+
+ inflateChildElements(r, parser, attrs, theme);
+
+ updateLocalState();
+ }
+
+ @Override
+ public void applyTheme(@NonNull Theme t) {
+ super.applyTheme(t);
+
+ final State state = mState;
+ if (state == null) {
+ return;
+ }
+
+ state.setDensity(resolveDensity(t.getResources(), 0));
+
+ if (state.mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(
+ state.mThemeAttrs, R.styleable.NotificationProgressDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+ }
+
+ applyThemeChildElements(t);
+
+ updateLocalState();
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return (mState.canApplyTheme()) || super.canApplyTheme();
+ }
+
+ private void updateStateFromTypedArray(TypedArray a) {
+ final State state = mState;
+
+ // Account for any configuration changes.
+ state.mChangingConfigurations |= a.getChangingConfigurations();
+
+ // Extract the theme attributes, if any.
+ state.mThemeAttrs = a.extractThemeAttrs();
+
+ state.mSegSegGap = a.getDimension(R.styleable.NotificationProgressDrawable_segSegGap,
+ state.mSegSegGap);
+ state.mSegPointGap = a.getDimension(R.styleable.NotificationProgressDrawable_segPointGap,
+ state.mSegPointGap);
+ }
+
+ private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+ Theme theme) throws XmlPullParserException, IOException {
+ TypedArray a;
+ int type;
+
+ final int innerDepth = parser.getDepth() + 1;
+ int depth;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth) {
+ continue;
+ }
+
+ String name = parser.getName();
+
+ if (name.equals("segments")) {
+ a = obtainAttributes(r, theme, attrs,
+ R.styleable.NotificationProgressDrawableSegments);
+ updateSegmentsFromTypedArray(a);
+ a.recycle();
+ } else if (name.equals("points")) {
+ a = obtainAttributes(r, theme, attrs,
+ R.styleable.NotificationProgressDrawablePoints);
+ updatePointsFromTypedArray(a);
+ a.recycle();
+ } else {
+ Log.w(TAG, "Bad element under NotificationProgressDrawable: " + name);
+ }
+ }
+ }
+
+ private void applyThemeChildElements(Theme t) {
+ final State state = mState;
+
+ if (state.mThemeAttrsSegments != null) {
+ final TypedArray a = t.resolveAttributes(
+ state.mThemeAttrsSegments, R.styleable.NotificationProgressDrawableSegments);
+ updateSegmentsFromTypedArray(a);
+ a.recycle();
+ }
+
+ if (state.mThemeAttrsPoints != null) {
+ final TypedArray a = t.resolveAttributes(
+ state.mThemeAttrsPoints, R.styleable.NotificationProgressDrawablePoints);
+ updateSegmentsFromTypedArray(a);
+ a.recycle();
+ }
+ }
+
+ private void updateSegmentsFromTypedArray(TypedArray a) {
+ final State state = mState;
+
+ // Account for any configuration changes.
+ state.mChangingConfigurations |= a.getChangingConfigurations();
+
+ // Extract the theme attributes, if any.
+ state.mThemeAttrsSegments = a.extractThemeAttrs();
+
+ final int width = a.getDimensionPixelSize(
+ R.styleable.NotificationProgressDrawableSegments_width, state.mStrokeWidth);
+ final float dashWidth = a.getDimension(
+ R.styleable.NotificationProgressDrawableSegments_dashWidth, state.mStrokeDashWidth);
+
+ final int color = a.getColor(R.styleable.NotificationProgressDrawableSegments_color,
+ state.mStrokeColor);
+
+ if (dashWidth != 0.0f) {
+ final float dashGap = a.getDimension(
+ R.styleable.NotificationProgressDrawableSegments_dashGap, state.mStrokeDashGap);
+ setStroke(width, color, dashWidth, dashGap);
+ } else {
+ setStroke(width, color);
+ }
+ }
+
+ private void updatePointsFromTypedArray(TypedArray a) {
+ final State state = mState;
+
+ // Account for any configuration changes.
+ state.mChangingConfigurations |= a.getChangingConfigurations();
+
+ // Extract the theme attributes, if any.
+ state.mThemeAttrsPoints = a.extractThemeAttrs();
+
+ state.mPointRadius = a.getDimension(R.styleable.NotificationProgressDrawablePoints_radius,
+ state.mPointRadius);
+ state.mPointRectInset = a.getDimension(R.styleable.NotificationProgressDrawablePoints_inset,
+ state.mPointRectInset);
+ state.mPointRectCornerRadius = a.getDimension(
+ R.styleable.NotificationProgressDrawablePoints_cornerRadius,
+ state.mPointRectCornerRadius);
+ state.mPointRectColor = a.getColor(R.styleable.NotificationProgressDrawablePoints_color,
+ state.mPointRectColor);
+ }
+
+ static int resolveDensity(@Nullable Resources r, int parentDensity) {
+ final int densityDpi = r == null ? parentDensity : r.getDisplayMetrics().densityDpi;
+ return densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+ }
+
+ /**
+ * Scales a floating-point pixel value from the source density to the
+ * target density.
+ */
+ private static float scaleFromDensity(float pixels, int sourceDensity, int targetDensity) {
+ return pixels * targetDensity / sourceDensity;
+ }
+
+ /**
+ * Scales a pixel value from the source density to the target density.
+ * <p>
+ * Optionally, when {@code isSize} is true, handles the resulting pixel value as a size,
+ * which is rounded to the closest positive integer.
+ * <p>
+ * Note: Iteratively applying density changes could result in drift of the pixel values due
+ * to rounding, especially for paddings which are truncated. Therefore it should be avoided.
+ * This isn't an issue for the notifications because the inflation pipeline reinflates
+ * notification views on density change.
+ */
+ private static int scaleFromDensity(
+ int pixels, int sourceDensity, int targetDensity, boolean isSize) {
+ if (pixels == 0 || sourceDensity == targetDensity) {
+ return pixels;
+ }
+
+ final float result = pixels * targetDensity / (float) sourceDensity;
+ if (!isSize) {
+ return (int) result;
+ }
+
+ final int rounded = Math.round(result);
+ if (rounded != 0) {
+ return rounded;
+ } else if (pixels > 0) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * A part of the progress bar, which is either a S{@link Segment} with non-zero length, or a
+ * {@link Point} with zero length.
+ */
+ public interface Part {
+
+ }
+
+ /**
+ * A segment is a part of the progress bar with non-zero length. For example, it can
+ * represent a portion in a navigation journey with certain traffic condition.
+ */
+ public static final class Segment implements Part {
+ private final float mFraction;
+ @ColorInt private final int mColor;
+ private final boolean mDashed;
+
+ public Segment(float fraction) {
+ this(fraction, Color.TRANSPARENT);
+ }
+
+ public Segment(float fraction, @ColorInt int color) {
+ this(fraction, color, false);
+ }
+
+ public Segment(float fraction, @ColorInt int color, boolean dashed) {
+ mFraction = fraction;
+ mColor = color;
+ mDashed = dashed;
+ }
+
+ public float getFraction() {
+ return this.mFraction;
+ }
+
+ public int getColor() {
+ return this.mColor;
+ }
+
+ public boolean getDashed() {
+ return this.mDashed;
+ }
+
+ @Override
+ public String toString() {
+ return "Segment(fraction=" + this.mFraction + ", color=" + this.mColor + ", dashed="
+ + this.mDashed + ')';
+ }
+ }
+
+ /**
+ * A point is a part of the progress bar with zero length. Points are designated points within a
+ * progressbar to visualize distinct stages or milestones. For example, a stop in a multi-stop
+ * ride-share journey.
+ */
+ public static final class Point implements Part {
+ @Nullable
+ private final Drawable mIcon;
+ @ColorInt private final int mColor;
+
+ public Point(@Nullable Drawable icon) {
+ this(icon, Color.TRANSPARENT);
+ }
+
+ public Point(@Nullable Drawable icon, @ColorInt int color) {
+ mIcon = icon;
+ mColor = color;
+ }
+
+ @Nullable
+ public Drawable getIcon() {
+ return this.mIcon;
+ }
+
+ @Override
+ public String toString() {
+ return "Point(icon=" + this.mIcon + ", color=" + this.mColor + ')';
+ }
+ }
+
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mState = new State(mState, null);
+ updateLocalState();
+ mMutated = true;
+ }
+ return this;
+ }
+
+ @Override
+ public void clearMutated() {
+ super.clearMutated();
+ mMutated = false;
+ }
+
+ static final class State extends ConstantState {
+ @Config
+ int mChangingConfigurations;
+ float mSegSegGap = 0.0f;
+ float mSegPointGap = 0.0f;
+ int mStrokeWidth = 0;
+ int mStrokeColor;
+ float mStrokeDashWidth = 0.0f;
+ float mStrokeDashGap = 0.0f;
+ float mPointRadius;
+ float mPointRectInset;
+ float mPointRectCornerRadius;
+ int mPointRectColor;
+
+ int[] mThemeAttrs;
+ int[] mThemeAttrsSegments;
+ int[] mThemeAttrsPoints;
+
+ int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+
+ State() {
+ }
+
+ State(@NonNull State orig, @Nullable Resources res) {
+ mChangingConfigurations = orig.mChangingConfigurations;
+ mStrokeColor = orig.mStrokeColor;
+ mStrokeWidth = orig.mStrokeWidth;
+ mStrokeDashWidth = orig.mStrokeDashWidth;
+ mStrokeDashGap = orig.mStrokeDashGap;
+ mPointRadius = orig.mPointRadius;
+ mPointRectInset = orig.mPointRectInset;
+ mPointRectCornerRadius = orig.mPointRectCornerRadius;
+ mPointRectColor = orig.mPointRectColor;
+
+ mThemeAttrs = orig.mThemeAttrs;
+ mThemeAttrsSegments = orig.mThemeAttrsSegments;
+ mThemeAttrsPoints = orig.mThemeAttrsPoints;
+
+ mDensity = resolveDensity(res, orig.mDensity);
+ if (orig.mDensity != mDensity) {
+ applyDensityScaling(orig.mDensity, mDensity);
+ }
+ }
+
+ private void applyDensityScaling(int sourceDensity, int targetDensity) {
+ if (mStrokeWidth > 0) {
+ mStrokeWidth = scaleFromDensity(
+ mStrokeWidth, sourceDensity, targetDensity, true);
+ }
+ if (mStrokeDashWidth > 0) {
+ mStrokeDashWidth = scaleFromDensity(
+ mStrokeDashWidth, sourceDensity, targetDensity);
+ }
+ if (mStrokeDashGap > 0) {
+ mStrokeDashGap = scaleFromDensity(
+ mStrokeDashGap, sourceDensity, targetDensity);
+ }
+ if (mPointRadius > 0) {
+ mPointRadius = scaleFromDensity(
+ mPointRadius, sourceDensity, targetDensity);
+ }
+ if (mPointRectInset > 0) {
+ mPointRectInset = scaleFromDensity(
+ mPointRectInset, sourceDensity, targetDensity);
+ }
+ if (mPointRectCornerRadius > 0) {
+ mPointRectCornerRadius = scaleFromDensity(
+ mPointRectCornerRadius, sourceDensity, targetDensity);
+ }
+ }
+
+ @NonNull
+ @Override
+ public Drawable newDrawable() {
+ return new NotificationProgressDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(@Nullable Resources res) {
+ // If this drawable is being created for a different density,
+ // just create a new constant state and call it a day.
+ final State state;
+ final int density = resolveDensity(res, mDensity);
+ if (density != mDensity) {
+ state = new State(this, res);
+ } else {
+ state = this;
+ }
+
+ return new NotificationProgressDrawable(state, res);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null || mThemeAttrsSegments != null || mThemeAttrsPoints != null
+ || super.canApplyTheme();
+ }
+
+ public void setDensity(int targetDensity) {
+ if (mDensity != targetDensity) {
+ final int sourceDensity = mDensity;
+ mDensity = targetDensity;
+
+ applyDensityScaling(sourceDensity, targetDensity);
+ }
+ }
+
+ public void setStroke(int width, int color, float dashWidth, float dashGap) {
+ mStrokeWidth = width;
+ mStrokeColor = color;
+ mStrokeDashWidth = dashWidth;
+ mStrokeDashGap = dashGap;
+ }
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ mState.mChangingConfigurations = getChangingConfigurations();
+ return mState;
+ }
+
+ /**
+ * Creates a new themed NotificationProgressDrawable based on the specified constant state.
+ * <p>
+ * The resulting drawable is guaranteed to have a new constant state.
+ *
+ * @param state Constant state from which the drawable inherits
+ */
+ private NotificationProgressDrawable(@NonNull State state, @Nullable Resources res) {
+ mState = state;
+
+ updateLocalState();
+ }
+
+ private void updateLocalState() {
+ final State state = mState;
+
+ mStrokePaint.setStrokeWidth(state.mStrokeWidth);
+
+ if (state.mStrokeDashWidth != 0.0f) {
+ final DashPathEffect e = new DashPathEffect(
+ new float[] { state.mStrokeDashWidth, state.mStrokeDashGap }, 0);
+ mDashedStrokePaint.setPathEffect(e);
+ }
+ }
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 4d2195deebae..2bc32657bd4a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -308,6 +308,7 @@ cc_library_shared_for_libandroid_runtime {
"spatializer-aidl-cpp",
"av-types-aidl-cpp",
"android.hardware.camera.device@3.2",
+ "camera_platform_flags_c_lib",
"libandroid_net",
"libbattery",
"libnetdutils",
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index af106235bd77..af393fdc5ad4 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -119,3 +119,4 @@ per-file android_tracing_Perfetto* = file:platform/development:/tools/winscope/O
# ApplicationSharedMemory
per-file *ApplicationSharedMemory* = file:/PERFORMANCE_OWNERS
+per-file *PropertyInvalidatedCache* = file:/PERFORMANCE_OWNERS
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 3f74fac35bb7..10e49efee92e 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -25,6 +25,7 @@
#include <binder/Parcel.h>
#include <camera/Camera.h>
#include <camera/StringUtils.h>
+#include <com_android_internal_camera_flags.h>
#include <cutils/properties.h>
#include <gui/GLConsumer.h>
#include <gui/Surface.h>
@@ -37,6 +38,7 @@
#include "jni.h"
using namespace android;
+namespace flags = com::android::internal::camera::flags;
enum {
// Keep up to date with Camera.java
@@ -527,14 +529,19 @@ void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *b
}
static bool attributionSourceStateForJavaParcel(JNIEnv *env, jobject jClientAttributionParcel,
+ bool useContextAttributionSource,
AttributionSourceState &clientAttribution) {
const Parcel *clientAttributionParcel = parcelForJavaObject(env, jClientAttributionParcel);
if (clientAttribution.readFromParcel(clientAttributionParcel) != ::android::OK) {
jniThrowRuntimeException(env, "Fail to unparcel AttributionSourceState");
return false;
}
- clientAttribution.uid = Camera::USE_CALLING_UID;
- clientAttribution.pid = Camera::USE_CALLING_PID;
+
+ if (!(useContextAttributionSource && flags::use_context_attribution_source())) {
+ clientAttribution.uid = Camera::USE_CALLING_UID;
+ clientAttribution.pid = Camera::USE_CALLING_PID;
+ }
+
return true;
}
@@ -542,7 +549,9 @@ static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz
jobject jClientAttributionParcel,
jint devicePolicy) {
AttributionSourceState clientAttribution;
- if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel, clientAttribution)) {
+ if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel,
+ /* useContextAttributionSource= */ false,
+ clientAttribution)) {
return 0;
}
return Camera::getNumberOfCameras(clientAttribution, devicePolicy);
@@ -553,7 +562,9 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jin
jobject jClientAttributionParcel,
jint devicePolicy, jobject info_obj) {
AttributionSourceState clientAttribution;
- if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel, clientAttribution)) {
+ if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel,
+ /* useContextAttributionSource= */ false,
+ clientAttribution)) {
return;
}
@@ -587,7 +598,9 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj
jobject jClientAttributionParcel,
jint devicePolicy) {
AttributionSourceState clientAttribution;
- if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel, clientAttribution)) {
+ if (!attributionSourceStateForJavaParcel(env, jClientAttributionParcel,
+ /* useContextAttributionSource= */ true,
+ clientAttribution)) {
return -EACCES;
}
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index a9b19062b764..704aef3cd131 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -50,6 +50,7 @@
#define ENCODING_DTS_HD_MA 29
#define ENCODING_DTS_UHD_P2 30
#define ENCODING_DSD 31
+#define ENCODING_AC4_L4 32
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -95,6 +96,8 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_AAC_XHE;
case ENCODING_AC4:
return AUDIO_FORMAT_AC4;
+ case ENCODING_AC4_L4:
+ return AUDIO_FORMAT_AC4_L4;
case ENCODING_E_AC3_JOC:
return AUDIO_FORMAT_E_AC3_JOC;
case ENCODING_DEFAULT:
@@ -177,6 +180,8 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
return ENCODING_AAC_XHE;
case AUDIO_FORMAT_AC4:
return ENCODING_AC4;
+ case AUDIO_FORMAT_AC4_L4:
+ return ENCODING_AC4_L4;
case AUDIO_FORMAT_E_AC3_JOC:
return ENCODING_E_AC3_JOC;
case AUDIO_FORMAT_MAT:
diff --git a/core/res/res/drawable/notification_progress_icon_background.xml b/core/res/res/drawable/notification_progress_icon_background.xml
new file mode 100644
index 000000000000..8e843bea3d6a
--- /dev/null
+++ b/core/res/res/drawable/notification_progress_icon_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="#00000000" />
+ <corners android:radius="4dp" />
+</shape> \ No newline at end of file
diff --git a/core/res/res/layout/notification_template_material_progress.xml b/core/res/res/layout/notification_template_material_progress.xml
new file mode 100644
index 000000000000..b413c701d6c5
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_progress.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ android:tag="progress"
+ >
+
+ <LinearLayout
+ android:id="@+id/notification_action_list_margin_target"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/notification_content_margin"
+ android:orientation="vertical"
+ >
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="top"
+ >
+
+ <include layout="@layout/notification_template_header" />
+
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:orientation="vertical"
+ >
+
+ <include layout="@layout/notification_template_part_line1" />
+
+ <include layout="@layout/notification_template_text_multiline" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:layout_marginTop="@dimen/notification_progress_margin_top"
+ android:orientation="horizontal">
+
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/notification_progress_start_icon"
+ android:layout_width="@dimen/notification_progress_icon_size"
+ android:layout_height="@dimen/notification_progress_icon_size"
+ android:background="@drawable/notification_progress_icon_background"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:layout_marginEnd="@dimen/notification_progress_margin_horizontal"
+ android:scaleType="centerCrop"
+ android:maxDrawableWidth="@dimen/notification_progress_icon_size"
+ android:maxDrawableHeight="@dimen/notification_progress_icon_size"
+ />
+
+
+ <include
+ android:layout_width="0dp"
+ android:layout_height="@dimen/notification_progress_bar_height"
+ layout="@layout/notification_template_progress"
+ android:layout_weight="1"
+ />
+
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/notification_progress_end_icon"
+ android:layout_width="@dimen/notification_progress_icon_size"
+ android:layout_height="@dimen/notification_progress_icon_size"
+ android:background="@drawable/notification_progress_icon_background"
+ android:clipToOutline="true"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ android:layout_marginStart="@dimen/notification_progress_margin_horizontal"
+ android:maxDrawableWidth="@dimen/notification_progress_icon_size"
+ android:maxDrawableHeight="@dimen/notification_progress_icon_size"
+ />
+ </LinearLayout>
+ </LinearLayout>
+
+ <include layout="@layout/notification_template_right_icon" />
+ </FrameLayout>
+
+ <ViewStub
+ android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+
+ <include
+ layout="@layout/notification_template_smart_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:layout_marginTop="@dimen/notification_content_margin"
+ />
+
+ <include layout="@layout/notification_material_action_list" />
+ </LinearLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 440219de9561..02f9f3c5f0db 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7720,6 +7720,44 @@
<attr name="animation" />
</declare-styleable>
+ <!-- ================================== -->
+ <!-- NotificationProgressDrawable class -->
+ <!-- ================================== -->
+
+ <!-- Drawable used to render a segmented bar, with segments and points. -->
+ <!-- @hide internal use only -->
+ <declare-styleable name="NotificationProgressDrawable">
+ <!-- Default color for the parts. -->
+ <attr name="segSegGap" format="dimension" />
+ <attr name="segPointGap" format="dimension" />
+ </declare-styleable>
+
+ <!-- Used to config the segments of a NotificationProgressDrawable. -->
+ <!-- @hide internal use only -->
+ <declare-styleable name="NotificationProgressDrawableSegments">
+ <!-- Width of the stroke. -->
+ <attr name="width" />
+ <!-- Default color of the stroke. -->
+ <attr name="color" />
+ <!-- Length of a dash in the stroke for the dashed segments. -->
+ <attr name="dashWidth" />
+ <!-- Gap between dashes in the stroke for the dashed segments. -->
+ <attr name="dashGap" />
+ </declare-styleable>
+
+ <!-- Used to config the points of a NotificationProgressDrawable. -->
+ <!-- @hide internal use only -->
+ <declare-styleable name="NotificationProgressDrawablePoints">
+ <!-- Radius (1/2 size) of the point rect. -->
+ <attr name="radius" />
+ <!-- Inset of the point icon or rect. -->
+ <attr name="inset" />
+ <!-- Corner radius of the point rect. -->
+ <attr name="cornerRadius" format="dimension" />
+ <!-- Default color of the point rect. -->
+ <attr name="color" />
+ </declare-styleable>
+
<!-- ========================== -->
<!-- Animation class attributes -->
<!-- ========================== -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6683dc044c9a..b92aa2f355ed 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -304,6 +304,9 @@
<!-- The top margin before the notification progress bar. -->
<dimen name="notification_progress_margin_top">8dp</dimen>
+ <!-- The horizontal margin before and after the notification progress bar. -->
+ <dimen name="notification_progress_margin_horizontal">2dp</dimen>
+
<!-- height of the notification header -->
<dimen name="notification_header_height">56dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c50c336f8fd8..b7c876545f05 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -224,6 +224,8 @@
<java-symbol type="id" name="status_bar_latest_event_content" />
<java-symbol type="id" name="notification_main_column" />
<java-symbol type="id" name="notification_headerless_view_column" />
+ <java-symbol type="id" name="notification_progress_start_icon" />
+ <java-symbol type="id" name="notification_progress_end_icon" />
<java-symbol type="id" name="sms_short_code_confirm_message" />
<java-symbol type="id" name="sms_short_code_detail_layout" />
<java-symbol type="id" name="sms_short_code_detail_message" />
@@ -2390,6 +2392,7 @@
<java-symbol type="layout" name="notification_template_material_media" />
<java-symbol type="layout" name="notification_template_material_big_media" />
<java-symbol type="layout" name="notification_template_material_big_text" />
+ <java-symbol type="layout" name="notification_template_material_progress" />
<java-symbol type="layout" name="notification_template_header" />
<java-symbol type="layout" name="notification_material_media_action" />
<java-symbol type="color" name="notification_progress_background_color" />
@@ -3205,6 +3208,7 @@
<java-symbol type="dimen" name="notification_heading_margin_end" />
<java-symbol type="dimen" name="notification_content_margin_top" />
<java-symbol type="dimen" name="notification_content_margin" />
+ <java-symbol type="dimen" name="notification_progress_margin_horizontal" />
<java-symbol type="dimen" name="notification_header_background_height" />
<java-symbol type="dimen" name="notification_header_touchable_height" />
<java-symbol type="dimen" name="notification_header_expand_icon_size" />
@@ -4076,6 +4080,7 @@
<java-symbol type="dimen" name="text_size_body_2_material" />
<java-symbol type="dimen" name="notification_icon_circle_size" />
<java-symbol type="drawable" name="notification_icon_circle" />
+ <java-symbol type="drawable" name="notification_progress_icon_background" />
<java-symbol type="dimen" name="messaging_avatar_size" />
<java-symbol type="dimen" name="messaging_group_sending_progress_size" />
<java-symbol type="dimen" name="messaging_image_rounding" />
diff --git a/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt b/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
index b7bccd46cede..381b566018c7 100644
--- a/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
+++ b/core/tests/coretests/src/android/window/BackTouchTrackerTest.kt
@@ -46,45 +46,43 @@ class BackTouchTrackerTest {
val linearTracker = linearTouchTracker()
linearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
var touchX = 10f
- val velocityX = 0f
- val velocityY = 0f
// Pre-commit
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
// Post-commit
touchX += 100f
linearTracker.setTriggerBack(true)
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
// Cancel
touchX -= 10f
linearTracker.setTriggerBack(false)
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress(0f)
// Cancel more
touchX -= 10f
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress(0f)
// Restarted, but pre-commit
val restartX = touchX
touchX += 10f
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((touchX - restartX) / MAX_DISTANCE)
// continue restart within pre-commit
touchX += 10f
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((touchX - restartX) / MAX_DISTANCE)
// Restarted, post-commit
touchX += 10f
linearTracker.setTriggerBack(true)
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
}
@@ -93,46 +91,44 @@ class BackTouchTrackerTest {
val linearTracker = linearTouchTracker()
linearTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0f, BackEvent.EDGE_RIGHT)
var touchX = INITIAL_X_RIGHT_EDGE - 10 // Fake right edge
- val velocityX = 0f
- val velocityY = 0f
val target = MAX_DISTANCE
// Pre-commit
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
// Post-commit
touchX -= 100f
linearTracker.setTriggerBack(true)
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
// Cancel
touchX += 10f
linearTracker.setTriggerBack(false)
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress(0f)
// Cancel more
touchX += 10f
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress(0f)
// Restarted, but pre-commit
val restartX = touchX
touchX -= 10f
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((restartX - touchX) / target)
// continue restart within pre-commit
touchX -= 10f
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((restartX - touchX) / target)
// Restarted, post-commit
touchX -= 10f
linearTracker.setTriggerBack(true)
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
}
@@ -141,28 +137,26 @@ class BackTouchTrackerTest {
val nonLinearTracker = nonLinearTouchTracker()
nonLinearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
var touchX = 10f
- val velocityX = 0f
- val velocityY = 0f
val linearTarget = LINEAR_DISTANCE + (MAX_DISTANCE - LINEAR_DISTANCE) * NON_LINEAR_FACTOR
// Pre-commit: linear progress
- nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.update(touchX, 0f)
nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
// Post-commit: still linear progress
touchX += 100f
nonLinearTracker.setTriggerBack(true)
- nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.update(touchX, 0f)
nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
// still linear progress
touchX = INITIAL_X_LEFT_EDGE + LINEAR_DISTANCE
- nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.update(touchX, 0f)
nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
// non linear progress
touchX += 10
- nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.update(touchX, 0f)
val nonLinearTouch = (touchX - INITIAL_X_LEFT_EDGE) - LINEAR_DISTANCE
val nonLinearProgress = nonLinearTouch / NON_LINEAR_DISTANCE
val nonLinearTarget = MathUtils.lerp(linearTarget, MAX_DISTANCE, nonLinearProgress)
@@ -178,7 +172,7 @@ class BackTouchTrackerTest {
val velocityY = 0f
// assert that progress is increased when increasing touchX
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
// assert that progress is reset to 0 when start location is updated
@@ -187,13 +181,13 @@ class BackTouchTrackerTest {
// assert that progress remains 0 when touchX is decreased
touchX -= 50
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress(0f)
// assert that progress uses new minimal touchX for progress calculation
val newInitialTouchX = touchX
touchX += 100
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((touchX - newInitialTouchX) / MAX_DISTANCE)
// assert the same for triggerBack==true
@@ -207,11 +201,8 @@ class BackTouchTrackerTest {
linearTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0f, BackEvent.EDGE_RIGHT)
var touchX = INITIAL_X_RIGHT_EDGE - 100f
- val velocityX = 0f
- val velocityY = 0f
-
// assert that progress is increased when decreasing touchX
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / MAX_DISTANCE)
// assert that progress is reset to 0 when start location is updated
@@ -220,13 +211,13 @@ class BackTouchTrackerTest {
// assert that progress remains 0 when touchX is increased
touchX += 50
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress(0f)
// assert that progress uses new maximal touchX for progress calculation
val newInitialTouchX = touchX
touchX -= 100
- linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.update(touchX, 0f)
linearTracker.assertProgress((newInitialTouchX - touchX) / MAX_DISTANCE)
// assert the same for triggerBack==true
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index 0a4c5e6eb91a..bcbc3025d297 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -685,8 +685,6 @@ public class WindowOnBackInvokedDispatcherTest {
/* touchX = */ 0,
/* touchY = */ 0,
/* progress = */ progress,
- /* velocityX = */ 0,
- /* velocityY = */ 0,
/* triggerBack = */ false,
/* swipeEdge = */ BackEvent.EDGE_LEFT,
/* departingAnimationTarget = */ null);
diff --git a/keystore/OWNERS b/keystore/OWNERS
index 689177715711..ea783e7f0c06 100644
--- a/keystore/OWNERS
+++ b/keystore/OWNERS
@@ -1,5 +1,6 @@
# Bug component: 189335
+ascull@google.com
drysdale@google.com
-eranm@google.com
jbires@google.com
+sethmo@google.com
swillden@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index df80946a99aa..7c5f71647843 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -33,8 +33,6 @@ public interface BackAnimation {
*
* @param touchX the X touch position of the {@link MotionEvent}.
* @param touchY the Y touch position of the {@link MotionEvent}.
- * @param velocityX the X velocity computed from the {@link MotionEvent}.
- * @param velocityY the Y velocity computed from the {@link MotionEvent}.
* @param keyAction the original {@link KeyEvent#getAction()} when the event was dispatched to
* the process. This is forwarded separately because the input pipeline may mutate
* the {#event} action state later.
@@ -43,8 +41,6 @@ public interface BackAnimation {
void onBackMotion(
float touchX,
float touchY,
- float velocityX,
- float velocityY,
int keyAction,
@BackEvent.SwipeEdge int swipeEdge);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 5836085e0ddc..b90e6e2fab8a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -352,16 +352,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
public void onBackMotion(
float touchX,
float touchY,
- float velocityX,
- float velocityY,
int keyAction,
@BackEvent.SwipeEdge int swipeEdge
) {
mShellExecutor.execute(() -> onMotionEvent(
/* touchX = */ touchX,
/* touchY = */ touchY,
- /* velocityX = */ velocityX,
- /* velocityY = */ velocityY,
/* keyAction = */ keyAction,
/* swipeEdge = */ swipeEdge));
}
@@ -500,14 +496,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
public void onMotionEvent(
float touchX,
float touchY,
- float velocityX,
- float velocityY,
int keyAction,
@BackEvent.SwipeEdge int swipeEdge) {
BackTouchTracker activeTouchTracker = getActiveTracker();
if (activeTouchTracker != null) {
- activeTouchTracker.update(touchX, touchY, velocityX, velocityY);
+ activeTouchTracker.update(touchX, touchY);
}
// two gestures are waiting to be processed at the moment, skip any further user touches
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
index e5bfccf0682e..f2c08dc3d1e5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
@@ -17,14 +17,12 @@
package com.android.wm.shell.recents
import android.app.ActivityManager.RunningTaskInfo
-import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.os.IBinder
import android.util.ArrayMap
import android.view.SurfaceControl
-import android.view.WindowManager
import android.window.TransitionInfo
-import com.android.wm.shell.shared.TransitionUtil
import android.window.flags.DesktopModeFlags
+import com.android.wm.shell.shared.TransitionUtil
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import dagger.Lazy
@@ -40,9 +38,6 @@ class TaskStackTransitionObserver(
private val transitions: Lazy<Transitions>,
shellInit: ShellInit
) : Transitions.TransitionObserver {
-
- private val transitionToTransitionChanges: MutableMap<IBinder, TransitionChanges> =
- mutableMapOf()
private val taskStackTransitionObserverListeners =
ArrayMap<TaskStackTransitionObserverListener, Executor>()
@@ -63,9 +58,6 @@ class TaskStackTransitionObserver(
finishTransaction: SurfaceControl.Transaction
) {
if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) {
- val taskInfoList = mutableListOf<RunningTaskInfo>()
- val transitionTypeList = mutableListOf<Int>()
-
for (change in info.changes) {
if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) {
continue
@@ -76,59 +68,21 @@ class TaskStackTransitionObserver(
continue
}
- // Filter out changes that we care about
- if (change.mode == WindowManager.TRANSIT_OPEN) {
- change.taskInfo?.let { taskInfoList.add(it) }
- transitionTypeList.add(change.mode)
+ // Find the first task that is opening, this should be the one at the front after
+ // the transition
+ if (TransitionUtil.isOpeningType(change.mode)) {
+ notifyTaskStackTransitionObserverListeners(taskInfo)
+ break
}
}
- // Only add the transition to map if it has a change we care about
- if (taskInfoList.isNotEmpty()) {
- transitionToTransitionChanges.put(
- transition,
- TransitionChanges(taskInfoList, transitionTypeList)
- )
- }
}
}
override fun onTransitionStarting(transition: IBinder) {}
- override fun onTransitionMerged(merged: IBinder, playing: IBinder) {
- val mergedTransitionChanges =
- transitionToTransitionChanges.get(merged)
- ?:
- // We are adding changes of the merged transition to changes of the playing
- // transition so if there is no changes nothing to do.
- return
-
- transitionToTransitionChanges.remove(merged)
- val playingTransitionChanges = transitionToTransitionChanges.get(playing)
- if (playingTransitionChanges != null) {
- playingTransitionChanges.merge(mergedTransitionChanges)
- } else {
- transitionToTransitionChanges.put(playing, mergedTransitionChanges)
- }
- }
-
- override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
- val taskInfoList =
- transitionToTransitionChanges.getOrDefault(transition, TransitionChanges()).taskInfoList
- val typeList =
- transitionToTransitionChanges
- .getOrDefault(transition, TransitionChanges())
- .transitionTypeList
- transitionToTransitionChanges.remove(transition)
+ override fun onTransitionMerged(merged: IBinder, playing: IBinder) {}
- for ((index, taskInfo) in taskInfoList.withIndex()) {
- if (
- TransitionUtil.isOpeningType(typeList[index]) &&
- taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
- ) {
- notifyTaskStackTransitionObserverListeners(taskInfo)
- }
- }
- }
+ override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {}
fun addTaskStackTransitionObserverListener(
taskStackTransitionObserverListener: TaskStackTransitionObserverListener,
@@ -154,14 +108,4 @@ class TaskStackTransitionObserver(
/** Called when a task is moved to front. */
fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {}
}
-
- private data class TransitionChanges(
- val taskInfoList: MutableList<RunningTaskInfo> = ArrayList(),
- val transitionTypeList: MutableList<Int> = ArrayList(),
- ) {
- fun merge(transitionChanges: TransitionChanges) {
- taskInfoList.addAll(transitionChanges.taskInfoList)
- transitionTypeList.addAll(transitionChanges.transitionTypeList)
- }
- }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 227060d15640..dee0b23a42f5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -860,15 +860,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
}
private void doMotionEvent(int actionDown, int coordinate) {
- doMotionEvent(actionDown, coordinate, 0);
- }
-
- private void doMotionEvent(int actionDown, int coordinate, float velocity) {
mController.onMotionEvent(
/* touchX */ coordinate,
/* touchY */ coordinate,
- /* velocityX = */ velocity,
- /* velocityY = */ velocity,
/* keyAction */ actionDown,
/* swipeEdge */ BackEvent.EDGE_LEFT);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
index 9b019ddb8362..1da4ef6b5a8b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
@@ -54,8 +54,6 @@ public class BackProgressAnimatorTest {
/* touchX = */ touchX,
/* touchY = */ 0,
/* progress = */ progress,
- /* velocityX = */ 0,
- /* velocityY = */ 0,
/* triggerBack = */ false,
/* swipeEdge = */ BackEvent.EDGE_LEFT,
/* departingAnimationTarget = */ null);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
index 5b5ef6f48789..2235c20d7f21 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
@@ -222,8 +222,6 @@ class CustomCrossActivityBackAnimationTest : ShellTestCase() {
/* touchX = */ touchX,
/* touchY = */ 0f,
/* progress = */ progress,
- /* velocityX = */ 0f,
- /* velocityY = */ 0f,
/* triggerBack = */ false,
/* swipeEdge = */ BackEvent.EDGE_LEFT,
/* departingAnimationTarget = */ null
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
index 0e5efa650cc4..afdb68776d04 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
@@ -114,7 +114,7 @@ class TaskStackTransitionObserverTest {
@Test
@EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
- fun taskCreated_fullscreenWindow_listenerNotNotified() {
+ fun taskCreated_fullscreenWindow_listenerNotified() {
val listener = TestListener()
val executor = TestShellExecutor()
transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
@@ -130,9 +130,9 @@ class TaskStackTransitionObserverTest {
callOnTransitionFinished()
executor.flushAll()
- assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(0)
+ assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(1)
assertThat(listener.taskInfoToBeNotified.windowingMode)
- .isEqualTo(WindowConfiguration.WINDOWING_MODE_UNDEFINED)
+ .isEqualTo(WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
}
@Test
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index b763a96e8e8a..c0160705fd47 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -19,6 +19,7 @@
#include <GLES2/gl2ext.h>
// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead.
+#include <statslog_hwui.h>
#include <surfacetexture/surface_texture_platform.h>
#include "AutoBackendTextureRelease.h"
@@ -50,6 +51,14 @@ DeferredLayerUpdater::~DeferredLayerUpdater() {
setTransform(nullptr);
mRenderState.removeContextCallback(this);
destroyLayer();
+ if (mFirstTimeForDataspace > std::chrono::steady_clock::time_point::min()) {
+ auto currentTime = std::chrono::steady_clock::now();
+ stats_write(stats::TEXTURE_VIEW_EVENT, static_cast<int32_t>(getuid()),
+ static_cast<int64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
+ currentTime - mFirstTimeForDataspace)
+ .count()),
+ mDataspace);
+ }
}
void DeferredLayerUpdater::setSurfaceTexture(AutoTextureRelease&& consumer) {
@@ -195,6 +204,21 @@ void DeferredLayerUpdater::apply() {
updateLayer(forceFilter, layerImage, outTransform, currentCropRect,
maxLuminanceNits);
}
+
+ if (dataspace != mDataspace ||
+ mFirstTimeForDataspace == std::chrono::steady_clock::time_point::min()) {
+ auto currentTime = std::chrono::steady_clock::now();
+ if (mFirstTimeForDataspace > std::chrono::steady_clock::time_point::min()) {
+ stats_write(stats::TEXTURE_VIEW_EVENT, static_cast<int32_t>(getuid()),
+ static_cast<int64_t>(
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ currentTime - mFirstTimeForDataspace)
+ .count()),
+ mDataspace);
+ }
+ mFirstTimeForDataspace = currentTime;
+ mDataspace = dataspace;
+ }
}
}
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index a7f8f6189a8e..3abb47ca92d1 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -16,6 +16,8 @@
#pragma once
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
#include <SkBlendMode.h>
#include <SkColorFilter.h>
#include <SkImage.h>
@@ -24,9 +26,9 @@
#include <android/surface_texture.h>
#include <cutils/compiler.h>
#include <utils/Errors.h>
+#include <utils/Timers.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
+#include <chrono>
#include <map>
#include <memory>
@@ -154,6 +156,9 @@ private:
bool mGLContextAttached;
bool mUpdateTexImage;
int mCurrentSlot = -1;
+ android_dataspace mDataspace = HAL_DATASPACE_UNKNOWN;
+ std::chrono::steady_clock::time_point mFirstTimeForDataspace =
+ std::chrono::steady_clock::time_point::min();
Layer* mLayer;
};
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index c90c44152440..0da8371bc824 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -16,6 +16,9 @@
package android.media;
+import static android.media.audio.Flags.FLAG_DOLBY_AC4_LEVEL4_ENCODING_API;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -309,7 +312,7 @@ public final class AudioFormat implements Parcelable {
public static final int ENCODING_AAC_ELD = 15;
/** Audio data format: AAC xHE compressed */
public static final int ENCODING_AAC_XHE = 16;
- /** Audio data format: AC-4 sync frame transport format */
+ /** Audio data format: AC-4 (levels 0-3) sync frame transport format */
public static final int ENCODING_AC4 = 17;
/** Audio data format: E-AC-3-JOC compressed
* E-AC-3-JOC streams can be decoded by downstream devices supporting {@link #ENCODING_E_AC3}.
@@ -375,6 +378,9 @@ public final class AudioFormat implements Parcelable {
public static final int ENCODING_DTS_UHD_P2 = 30;
/** Audio data format: Direct Stream Digital */
public static final int ENCODING_DSD = 31;
+ /** Audio data format: AC-4 level 4 sync frame transport format */
+ @FlaggedApi(FLAG_DOLBY_AC4_LEVEL4_ENCODING_API)
+ public static final int ENCODING_AC4_L4 = 32;
/** @hide */
public static String toLogFriendlyEncoding(int enc) {
@@ -413,6 +419,8 @@ public final class AudioFormat implements Parcelable {
return "ENCODING_AAC_XHE";
case ENCODING_AC4:
return "ENCODING_AC4";
+ case ENCODING_AC4_L4:
+ return "ENCODING_AC4_L4";
case ENCODING_E_AC3_JOC:
return "ENCODING_E_AC3_JOC";
case ENCODING_DOLBY_MAT:
@@ -823,6 +831,7 @@ public final class AudioFormat implements Parcelable {
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
case ENCODING_AC4:
+ case ENCODING_AC4_L4:
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
case ENCODING_OPUS:
@@ -863,6 +872,7 @@ public final class AudioFormat implements Parcelable {
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
case ENCODING_AC4:
+ case ENCODING_AC4_L4:
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
case ENCODING_OPUS:
@@ -908,6 +918,7 @@ public final class AudioFormat implements Parcelable {
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
case ENCODING_AC4:
+ case ENCODING_AC4_L4:
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
case ENCODING_OPUS:
@@ -950,6 +961,7 @@ public final class AudioFormat implements Parcelable {
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
case ENCODING_AC4:
+ case ENCODING_AC4_L4:
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
case ENCODING_OPUS:
@@ -1238,6 +1250,7 @@ public final class AudioFormat implements Parcelable {
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
case ENCODING_AC4:
+ case ENCODING_AC4_L4:
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
case ENCODING_OPUS:
@@ -1468,6 +1481,7 @@ public final class AudioFormat implements Parcelable {
ENCODING_AAC_ELD,
ENCODING_AAC_XHE,
ENCODING_AC4,
+ ENCODING_AC4_L4,
ENCODING_E_AC3_JOC,
ENCODING_DOLBY_MAT,
ENCODING_OPUS,
@@ -1506,6 +1520,7 @@ public final class AudioFormat implements Parcelable {
ENCODING_AAC_ELD,
ENCODING_AAC_XHE,
ENCODING_AC4,
+ ENCODING_AC4_L4,
ENCODING_E_AC3_JOC,
ENCODING_DOLBY_MAT,
ENCODING_OPUS,
@@ -1533,6 +1548,7 @@ public final class AudioFormat implements Parcelable {
ENCODING_AAC_LC,
ENCODING_DOLBY_TRUEHD,
ENCODING_AC4,
+ ENCODING_AC4_L4,
ENCODING_E_AC3_JOC,
ENCODING_DOLBY_MAT,
ENCODING_MPEGH_BL_L3,
@@ -1554,6 +1570,7 @@ public final class AudioFormat implements Parcelable {
ENCODING_AAC_LC,
ENCODING_DOLBY_TRUEHD,
ENCODING_AC4,
+ ENCODING_AC4_L4,
ENCODING_E_AC3_JOC,
ENCODING_DOLBY_MAT,
ENCODING_MPEGH_BL_L3,
@@ -1592,7 +1609,9 @@ public final class AudioFormat implements Parcelable {
case ENCODING_DOLBY_TRUEHD:
return "Dolby TrueHD";
case ENCODING_AC4:
- return "Dolby AC-4";
+ return "Dolby AC-4 levels 0-3";
+ case ENCODING_AC4_L4:
+ return "Dolby AC-4 level 4";
case ENCODING_E_AC3_JOC:
return "Dolby Atmos in Dolby Digital Plus";
case ENCODING_DOLBY_MAT:
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index ebdfd3e41aa1..a8b863bc67f9 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -542,6 +542,8 @@ public class AudioSystem
return "AUDIO_FORMAT_AAC_LATM_HE_V2"; // (AAC_LATM | AAC_SUB_HE_V2)
case /* AUDIO_FORMAT_E_AC3_JOC */ 0xA000001:
return "AUDIO_FORMAT_E_AC3_JOC"; // (E_AC3 | E_AC3_SUB_JOC)
+ case /* AUDIO_FORMAT_AC4_L4 */ 0x22000001:
+ return "AUDIO_FORMAT_AC4_L4"; // (AC4 | AC4_SUB_L4)
case /* AUDIO_FORMAT_MAT_1_0 */ 0x24000001:
return "AUDIO_FORMAT_MAT_1_0"; // (MAT | MAT_SUB_1_0)
case /* AUDIO_FORMAT_MAT_2_0 */ 0x24000002:
diff --git a/nfc/Android.bp b/nfc/Android.bp
index db3dcb0631dd..7ad8c4c8de41 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -41,6 +41,10 @@ java_sdk_library {
"framework-permission-s.stubs.module_lib",
"framework-permission.stubs.module_lib",
],
+ stub_only_libs: [
+ // Needed for javadoc references.
+ "framework-permission-s.stubs.module_lib",
+ ],
static_libs: [
"android.nfc.flags-aconfig-java",
"android.permission.flags-aconfig-java",
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 824dd4a5fdaf..d688a1a036d1 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -44,6 +44,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -100,7 +101,8 @@ public class PackageInstallerActivity extends Activity {
private int mActivityResultCode = Activity.RESULT_CANCELED;
private int mPendingUserActionReason = -1;
- private final boolean mLocalLOGV = false;
+ private final boolean mLocalLOGV =
+ TextUtils.equals("userdebug", SystemProperties.get("ro.build.type", ""));
PackageManager mPm;
AppOpsManager mAppOpsManager;
UserManager mUserManager;
@@ -143,6 +145,11 @@ public class PackageInstallerActivity extends Activity {
private AlertDialog mDialog;
private void startInstallConfirm() {
+ if (mLocalLOGV) {
+ Log.d(TAG, "startInstallConfirm mAppInfo = " + mAppInfo
+ + ", existingUpdateOwner = " + getExistingUpdateOwner()
+ + ", mOriginatingPackage = " + mOriginatingPackage);
+ }
TextView viewToEnable;
if (mAppInfo != null) {
@@ -183,6 +190,10 @@ public class PackageInstallerActivity extends Activity {
try {
final String packageName = mPkgInfo.packageName;
final InstallSourceInfo sourceInfo = mPm.getInstallSourceInfo(packageName);
+ if (mLocalLOGV) {
+ Log.d(TAG, "getExistingUpdateOwner mAppInfo = " + mAppInfo
+ + ", packageName = " + packageName + ", sourceInfo = " + sourceInfo);
+ }
return sourceInfo.getUpdateOwnerPackageName();
} catch (NameNotFoundException e) {
return null;
@@ -303,6 +314,12 @@ public class PackageInstallerActivity extends Activity {
private void initiateInstall() {
final String existingUpdateOwner = getExistingUpdateOwner();
+ if (mLocalLOGV) {
+ Log.d(TAG, "initiateInstall mAppInfo = " + mAppInfo
+ + ", existingUpdateOwner = " + existingUpdateOwner
+ + ", mOriginatingPackage = " + mOriginatingPackage
+ + ", mSessionId = " + mSessionId);
+ }
if (mSessionId == SessionInfo.INVALID_ID &&
!TextUtils.isEmpty(existingUpdateOwner) &&
!TextUtils.equals(existingUpdateOwner, mOriginatingPackage)) {
@@ -814,15 +831,28 @@ public class PackageInstallerActivity extends Activity {
@Override
public void onOpChanged(String op, String packageName) {
+ if (mLocalLOGV) {
+ Log.d(TAG, "UnknownSourcesListener onOpChanged op = " + op
+ + ", packageName = " + packageName
+ + ", mOriginatingPackage = " + mOriginatingPackage);
+ }
if (!mOriginatingPackage.equals(packageName)) {
return;
}
unregister(this);
mActiveUnknownSourcesListeners.remove(this);
+ if (mLocalLOGV) {
+ Log.d(TAG, "UnknownSourcesListener onOpChanged isDestroyed() = "
+ + isDestroyed());
+ }
if (isDestroyed()) {
return;
}
new Handler(Looper.getMainLooper()).postDelayed(() -> {
+ if (mLocalLOGV) {
+ Log.d(TAG, "UnknownSourcesListener onOpChanged post isDestroyed()"
+ + "= " + isDestroyed() + ", getIntent() = " + getIntent());
+ }
if (!isDestroyed()) {
startActivity(getIntent());
// The start flag (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP) doesn't
@@ -840,6 +870,9 @@ public class PackageInstallerActivity extends Activity {
}
private void register(UnknownSourcesListener listener) {
+ if (mLocalLOGV) {
+ Log.d(TAG, "UnknownSourcesListener register");
+ }
mAppOpsManager.startWatchingMode(
AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES, mOriginatingPackage,
listener);
@@ -847,6 +880,9 @@ public class PackageInstallerActivity extends Activity {
}
private void unregister(UnknownSourcesListener listener) {
+ if (mLocalLOGV) {
+ Log.d(TAG, "UnknownSourcesListener unregister");
+ }
mAppOpsManager.stopWatchingMode(listener);
mActiveUnknownSourcesListeners.remove(listener);
}
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
index e6726dcbb17a..03a2101544be 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
@@ -255,4 +255,9 @@ public class SelectorWithWidgetPreference extends CheckBoxPreference {
a.recycle();
}
}
+
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+ public View getExtraWidget() {
+ return mExtraWidget;
+ }
}
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
deleted file mode 100644
index 8a77d88a7e83..000000000000
--- a/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2024, 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.
-*/
--->
-
-<!-- This is the screen that shows the 9 circle unlock widget and instructs
- the user how to unlock their device, or make an emergency call. This
- is the landscape layout. -->
-<com.android.keyguard.KeyguardPatternView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_pattern_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_horizontal|bottom"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="horizontal">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="2"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layoutDirection="ltr"
- android:orientation="vertical">
-
- <include layout="@layout/keyguard_bouncer_message_area"/>
-
- <com.android.systemui.bouncer.ui.BouncerMessageView
- android:id="@+id/bouncer_message_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- androidprv:layout_constraintBottom_toTopOf="@+id/lockPatternView"
- androidprv:layout_constraintTop_toTopOf="parent"
- androidprv:layout_constraintVertical_chainStyle="packed" />
-
- <include
- android:id="@+id/keyguard_selector_fade_container"
- layout="@layout/keyguard_eca"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|center_horizontal"
- android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
- android:layout_marginTop="@dimen/keyguard_eca_top_margin"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- androidprv:layout_constraintBottom_toBottomOf="parent" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/pattern_container"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="3"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layoutDirection="ltr"
- android:orientation="vertical">
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/pattern_top_guideline"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- androidprv:layout_constraintGuide_percent="0" />
-
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPatternView"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="horizontal"
- androidprv:layout_constraintDimensionRatio="1.0"
- androidprv:layout_constraintVertical_bias="1.0"
- androidprv:layout_constraintLeft_toLeftOf="parent"
- androidprv:layout_constraintRight_toRightOf="parent"
- androidprv:layout_constraintBottom_toBottomOf="parent"
- androidprv:layout_constraintTop_toBottomOf="@id/pattern_top_guideline"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml
deleted file mode 100644
index 4b8b63fe9396..000000000000
--- a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml
+++ /dev/null
@@ -1,221 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2024, 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.
-*/
--->
-<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
-<com.android.keyguard.KeyguardSimPinView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_sim_pin_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_horizontal|bottom"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="horizontal">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="2"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layoutDirection="ltr"
- android:orientation="vertical">
-
- <include layout="@layout/keyguard_bouncer_message_area"/>
-
- <ImageView
- android:id="@+id/keyguard_sim"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginBottom="3dp"
- android:src="@drawable/ic_lockscreen_sim"
- androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"
- androidprv:layout_constraintLeft_toLeftOf="parent"
- androidprv:layout_constraintRight_toRightOf="parent"
- app:tint="@color/background_protected"/>
-
- <include
- android:id="@+id/keyguard_esim_area"
- layout="@layout/keyguard_esim_area"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- androidprv:layout_constraintLeft_toLeftOf="parent"
- androidprv:layout_constraintRight_toRightOf="parent"
- androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"/>
-
- <com.android.keyguard.AlphaOptimizedRelativeLayout
- android:id="@+id/pin_entry_area"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
- androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container">
-
- <com.android.keyguard.PasswordTextView
- android:id="@+id/simPinEntry"
- style="@style/Widget.TextView.Password"
- android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="@dimen/keyguard_password_height"
- android:layout_centerHorizontal="true"
- android:layout_marginRight="72dp"
- android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
- androidprv:scaledTextSize="@integer/scaled_password_text_size" />
- </com.android.keyguard.AlphaOptimizedRelativeLayout>
-
- <include
- android:id="@+id/keyguard_selector_fade_container"
- layout="@layout/keyguard_eca"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|center_horizontal"
- android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
- android:layout_marginTop="@dimen/keyguard_eca_top_margin"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- androidprv:layout_constraintBottom_toBottomOf="parent"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/sim_pin_container"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="3"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layoutDirection="ltr"
- android:orientation="vertical">
-
- <androidx.constraintlayout.helper.widget.Flow
- android:id="@+id/flow1"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="horizontal"
- androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
- androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
- androidprv:flow_horizontalStyle="packed"
- androidprv:flow_maxElementsWrap="3"
- androidprv:flow_verticalBias="0.5"
- androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
- androidprv:flow_verticalStyle="packed"
- androidprv:flow_wrapMode="aligned"
- androidprv:layout_constraintLeft_toLeftOf="parent"
- androidprv:layout_constraintRight_toRightOf="parent"
- androidprv:layout_constraintTop_toTopOf="parent"
- androidprv:layout_constraintBottom_toBottomOf="parent"/>
-
- <com.android.keyguard.NumPadButton
- android:id="@+id/delete_button"
- style="@style/NumPadKey.Delete"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key0"
- android:contentDescription="@string/keyboardview_keycode_delete" />
-
- <com.android.keyguard.NumPadButton
- android:id="@+id/key_enter"
- style="@style/NumPadKey.Enter"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:contentDescription="@string/keyboardview_keycode_enter" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key1"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key2"
- androidprv:digit="1"
- androidprv:textView="@+id/simPinEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key2"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key3"
- androidprv:digit="2"
- androidprv:textView="@+id/simPinEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key3"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key4"
- androidprv:digit="3"
- androidprv:textView="@+id/simPinEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key4"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key5"
- androidprv:digit="4"
- androidprv:textView="@+id/simPinEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key5"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key6"
- androidprv:digit="5"
- androidprv:textView="@+id/simPinEntry" />
-
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key6"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key7"
- androidprv:digit="6"
- androidprv:textView="@+id/simPinEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key7"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key8"
- androidprv:digit="7"
- androidprv:textView="@+id/simPinEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key8"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key9"
- androidprv:digit="8"
- androidprv:textView="@+id/simPinEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key9"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/delete_button"
- androidprv:digit="9"
- androidprv:textView="@+id/simPinEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key0"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key_enter"
- androidprv:digit="0"
- androidprv:textView="@+id/simPinEntry" />
- </androidx.constraintlayout.widget.ConstraintLayout>
-</com.android.keyguard.KeyguardSimPinView>
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml
deleted file mode 100644
index 9012856c7bb4..000000000000
--- a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml
+++ /dev/null
@@ -1,223 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2024, 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.
-*/
--->
-<!-- This is the SIM PUK view that allows the user to recover their device by entering the
- carrier-provided PUK code and entering a new SIM PIN for it. -->
-<com.android.keyguard.KeyguardSimPukView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_sim_puk_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_horizontal|bottom"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="horizontal">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="2"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layoutDirection="ltr"
- android:orientation="vertical">
-
- <include layout="@layout/keyguard_bouncer_message_area"/>
-
- <ImageView
- android:id="@+id/keyguard_sim"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginBottom="3dp"
- android:src="@drawable/ic_lockscreen_sim"
- androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"
- androidprv:layout_constraintLeft_toLeftOf="parent"
- androidprv:layout_constraintRight_toRightOf="parent"
- app:tint="@color/background_protected"/>
-
- <include
- android:id="@+id/keyguard_esim_area"
- layout="@layout/keyguard_esim_area"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- androidprv:layout_constraintLeft_toLeftOf="parent"
- androidprv:layout_constraintRight_toRightOf="parent"
- androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"/>
-
- <com.android.keyguard.AlphaOptimizedRelativeLayout
- android:id="@+id/pin_entry_area"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
- androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container">
-
- <com.android.keyguard.PasswordTextView
- android:id="@+id/pukEntry"
- style="@style/Widget.TextView.Password"
- android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="@dimen/keyguard_password_height"
- android:layout_centerHorizontal="true"
- android:layout_marginRight="72dp"
- android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
- androidprv:scaledTextSize="@integer/scaled_password_text_size" />
- </com.android.keyguard.AlphaOptimizedRelativeLayout>
-
- <include
- android:id="@+id/keyguard_selector_fade_container"
- layout="@layout/keyguard_eca"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|center_horizontal"
- android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
- android:layout_marginTop="@dimen/keyguard_eca_top_margin"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- androidprv:layout_constraintBottom_toBottomOf="parent"/>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/sim_puk_container"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="3"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layoutDirection="ltr"
- android:orientation="vertical">
-
- <androidx.constraintlayout.helper.widget.Flow
- android:id="@+id/flow1"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="horizontal"
- androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
- androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
- androidprv:flow_horizontalStyle="packed"
- androidprv:flow_maxElementsWrap="3"
- androidprv:flow_verticalBias="0.5"
- androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
- androidprv:flow_verticalStyle="packed"
- androidprv:flow_wrapMode="aligned"
- androidprv:layout_constraintLeft_toLeftOf="parent"
- androidprv:layout_constraintRight_toRightOf="parent"
- androidprv:layout_constraintTop_toTopOf="parent"
- androidprv:layout_constraintBottom_toBottomOf="parent"/>
-
- <com.android.keyguard.NumPadButton
- android:id="@+id/delete_button"
- style="@style/NumPadKey.Delete"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key0"
- android:contentDescription="@string/keyboardview_keycode_delete" />
-
- <com.android.keyguard.NumPadButton
- android:id="@+id/key_enter"
- style="@style/NumPadKey.Enter"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:contentDescription="@string/keyboardview_keycode_enter" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key1"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key2"
- androidprv:digit="1"
- androidprv:textView="@+id/pukEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key2"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key3"
- androidprv:digit="2"
- androidprv:textView="@+id/pukEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key3"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key4"
- androidprv:digit="3"
- androidprv:textView="@+id/pukEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key4"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key5"
- androidprv:digit="4"
- androidprv:textView="@+id/pukEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key5"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key6"
- androidprv:digit="5"
- androidprv:textView="@+id/pukEntry" />
-
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key6"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key7"
- androidprv:digit="6"
- androidprv:textView="@+id/pukEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key7"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key8"
- androidprv:digit="7"
- androidprv:textView="@+id/pukEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key8"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key9"
- androidprv:digit="8"
- androidprv:textView="@+id/pukEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key9"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/delete_button"
- androidprv:digit="9"
- androidprv:textView="@+id/pukEntry" />
-
- <com.android.keyguard.NumPadKey
- android:id="@+id/key0"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:accessibilityTraversalBefore="@id/key_enter"
- androidprv:digit="0"
- androidprv:textView="@+id/pukEntry" />
- </androidx.constraintlayout.widget.ConstraintLayout>
-</com.android.keyguard.KeyguardSimPukView>
diff --git a/packages/SystemUI/res/drawable/contextual_edu_all_apps.xml b/packages/SystemUI/res/drawable/contextual_edu_all_apps.xml
new file mode 100644
index 000000000000..263e11caf03d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contextual_edu_all_apps.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportHeight="32"
+ android:viewportWidth="32">
+ <path
+ android:fillColor="#001E2D"
+ android:pathData="M28.6 30.3l-4.1-4a5.2 5.2 0 0 1-2.7 0.7a5.2 5.2 0 0 1-5.3-5.3a5 5 0 0 1 1.5-3.6q1.6-1.6 3.8-1.6a5 5 0 0 1 3.7 1.6a5 5 0 0 1 1.3 5.1q-0.2 0.9-0.6 1.3l4.1 4l-1.7 1.8zm-21.7-3.3a5 5 0 0 1-3.7-1.5a5 5 0 0 1-1.5-3.7a5 5 0 0 1 1.5-3.7a5 5 0 0 1 3.7-1.6a5 5 0 0 1 3.8 1.6a5 5 0 0 1 1.5 3.7a5 5 0 0 1-1.5 3.7a5 5 0 0 1-3.8 1.5zm14.9-2.3q1 0 2-0.8q0.8-1 0.8-2q0-1.2-0.8-2t-2-0.8q-1.3 0-2 0.8q-0.9 0.8-0.9 2q0 1.1 0.9 2q0.8 0.8 2 0.8zm-14.9-12.5a5 5 0 0 1-3.7-1.5q-1.5-1.5-1.5-3.7a5 5 0 0 1 1.5-3.7a5 5 0 0 1 3.7-1.6a5 5 0 0 1 3.8 1.6a5 5 0 0 1 1.5 3.7q0 2.2-1.5 3.7a5 5 0 0 1-3.8 1.5zm14.9 0a5.2 5.2 0 0 1-5.3-5.3a5 5 0 0 1 1.5-3.6q1.6-1.6 3.8-1.6a5 5 0 0 1 3.7 1.6a5 5 0 0 1 1.5 3.7q0 2.2-1.5 3.7a5 5 0 0 1-3.7 1.5z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml b/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml
new file mode 100644
index 000000000000..d7000d7f5a5c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright 2024 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.
+ -->
+<!-- Setting insetBottom to avoid bottom elevation of dialog being clipped off -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:insetBottom="@dimen/contextual_edu_dialog_elevation">
+ <shape>
+ <corners android:radius="28dp" />
+ <solid android:color="?androidprv:attr/materialColorTertiaryFixed" />
+ </shape>
+</inset> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/contextual_edu_swipe_back.xml b/packages/SystemUI/res/drawable/contextual_edu_swipe_back.xml
new file mode 100644
index 000000000000..8b0142c4638e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contextual_edu_swipe_back.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="28dp"
+ android:height="32dp"
+ android:viewportHeight="32"
+ android:viewportWidth="28">
+ <path
+ android:fillColor="#001E2D"
+ android:pathData="M27.3 9.8h-6.4v-1.8h4a17.4 17.4 0 0 0-5.1-3.1a15.2 15.2 0 0 0-5.8-1.1c-2 0-4 0.4-5.9 1.1a17.6 17.6 0 0 0-5.1 3.1h4v1.8h-6.4v-6.4h1.8l0 2.8a18.6 18.6 0 0 1 11.6-4.2a18.5 18.5 0 0 1 11.6 4.2v-2.8h1.8l0 6.4zm-13.6 20.2c-0.5 0-1-0.1-1.5-0.3s-0.9-0.5-1.3-0.9l-6.8-6.9l0.8-0.9a2.4 2.4 0 0 1 2.5-0.7l2.5 0.7v-11c0-0.3 0.1-0.6 0.3-0.9c0.3-0.3 0.6-0.4 0.9-0.4s0.6 0.1 0.8 0.4c0.2 0.2 0.4 0.5 0.4 0.9v9.4h1.6v-4.3c0-0.3 0.1-0.6 0.3-0.8s0.5-0.4 0.9-0.4s0.6 0.1 0.9 0.4c0.2 0.2 0.4 0.5 0.4 0.8v4.3h1.6v-3c0-0.3 0.1-0.6 0.3-0.8s0.5-0.4 0.9-0.4c0.3 0 0.6 0.1 0.9 0.4c0.3 0.2 0.4 0.5 0.4 0.8v3h1.6v-0.3c0-0.3 0.1-0.6 0.3-0.8s0.5-0.4 0.9-0.4s0.7 0.1 0.9 0.4c0.2 0.2 0.4 0.5 0.4 0.8v5.6c0 1.5-0.5 2.7-1.6 3.8a5.1 5.1 0 0 1-3.8 1.6h-5.6z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/contextual_edu_swipe_up.xml b/packages/SystemUI/res/drawable/contextual_edu_swipe_up.xml
new file mode 100644
index 000000000000..294b62658c22
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contextual_edu_swipe_up.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportHeight="32"
+ android:viewportWidth="32">
+ <group>
+ <clip-path android:pathData="M0,0h32v32H0z" />
+ <path
+ android:fillColor="#001E2D"
+ android:pathData="M21.8 27.1a3.5 3.5 0 0 1-3-0.1l-8.8-4.1l0.5-1.2c0.2-0.4 0.5-0.8 0.8-1c0.4-0.3 0.8-0.5 1.3-0.5l2.6-0.2l-3.8-10.4a1.1 1.1 0 0 1 0-0.9c0.2-0.3 0.4-0.5 0.7-0.6s0.6-0.1 0.9 0s0.5 0.4 0.6 0.7l3.2 8.9l1.5-0.6l-1.5-4.1a1.1 1.1 0 0 1 0-0.9c0.2-0.3 0.4-0.5 0.7-0.6s0.6-0.1 0.9 0s0.5 0.4 0.6 0.7l1.5 4.1l1.5-0.6l-1-2.8a1.1 1.1 0 0 1 0-0.9c0.2-0.3 0.4-0.5 0.7-0.6s0.7-0.1 0.9 0c0.3 0.1 0.5 0.4 0.6 0.7l1 2.8l1.6-0.6l-0.1-0.3a1.1 1.1 0 0 1 0-0.9c0.2-0.3 0.4-0.5 0.7-0.7c0.3-0.1 0.6-0.1 0.9 0.1c0.3 0.1 0.5 0.4 0.6 0.7l1.9 5.2c0.5 1.4 0.5 2.8-0.2 4.1a5.1 5.1 0 0 1-3 2.7l-5.3 1.9zm-13.8-9.4a15.5 15.5 0 0 1-3.4-9.8a17.8 17.8 0 0 1 0.4-3.8l-2.4 2.4l-1.3-1.2l4.5-4.5l4.5 4.5l-1.2 1.2l-2.3-2.3c-0.2 0.6-0.3 1.2-0.4 1.8a14.1 14.1 0 0 0 0.6 6.4a13.5 13.5 0 0 0 2.2 4l-1.3 1.3z" />
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/layout/contextual_edu_dialog.xml b/packages/SystemUI/res/layout/contextual_edu_dialog.xml
new file mode 100644
index 000000000000..ee42b2363dd5
--- /dev/null
+++ b/packages/SystemUI/res/layout/contextual_edu_dialog.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright 2024 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/contextual_edu_dialog_bg"
+ android:elevation="@dimen/contextual_edu_dialog_elevation"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:padding="12dp">
+
+ <ImageView
+ android:id="@+id/edu_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null"
+ android:importantForAccessibility="no"
+ android:paddingRight="16dp" />
+
+ <TextView
+ android:id="@+id/edu_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@color/transparent"
+ android:ellipsize="end"
+ android:fontFamily="google-sans-medium"
+ android:maxWidth="280dp"
+ android:textColor="?androidprv:attr/materialColorOnTertiaryFixed"
+ android:textSize="14sp"
+ android:textStyle="bold" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 7bd4ca8b940b..17ba2e5c10c4 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -63,10 +63,4 @@
<style name="ShortcutHelperTheme" parent="@style/ShortcutHelperThemeCommon">
<item name="android:windowLightNavigationBar">false</item>
</style>
-
- <style name="ContextualEduDialog" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
- <!-- To make the dialog wrap to content when the education text is short -->
- <item name="windowMinWidthMajor">0%</item>
- <item name="windowMinWidthMinor">0%</item>
- </style>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 629c94f9a044..1727a5fec0a2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -2048,5 +2048,6 @@
<dimen name="abc_slice_big_pic_min_height">64dp</dimen>
<dimen name="abc_slice_big_pic_max_height">64dp</dimen>
- <dimen name="contextual_edu_dialog_bottom_margin">70dp</dimen>
+ <dimen name="contextual_edu_dialog_bottom_margin">80dp</dimen>
+ <dimen name="contextual_edu_dialog_elevation">2dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 94b0b5f67934..e1f25f99cc98 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1721,10 +1721,4 @@
<style name="ShortcutHelperTheme" parent="@style/ShortcutHelperThemeCommon">
<item name="android:windowLightNavigationBar">true</item>
</style>
-
- <style name="ContextualEduDialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
- <!-- To make the dialog wrap to content when the education text is short -->
- <item name="windowMinWidthMajor">0%</item>
- <item name="windowMinWidthMinor">0%</item>
- </style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
index 5f421fd19550..ba96f4e56421 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
@@ -17,19 +17,30 @@
package com.android.systemui.communal.ui.binder
import android.content.Context
+import android.os.Bundle
import android.util.SizeF
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
+import androidx.compose.ui.unit.IntSize
import androidx.core.view.doOnLayout
+import com.android.app.tracing.coroutines.flow.flowOn
import com.android.app.tracing.coroutines.launch
+import com.android.systemui.Flags.communalWidgetResizing
+import com.android.systemui.common.ui.view.onLayoutChanged
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.util.WidgetViewFactory
import com.android.systemui.util.kotlin.DisposableHandles
+import com.android.systemui.util.kotlin.toDp
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
object CommunalAppWidgetHostViewBinder {
private const val TAG = "CommunalAppWidgetHostViewBinder"
@@ -37,9 +48,11 @@ object CommunalAppWidgetHostViewBinder {
fun bind(
context: Context,
applicationScope: CoroutineScope,
+ mainContext: CoroutineContext,
+ backgroundContext: CoroutineContext,
container: FrameLayout,
model: CommunalContentModel.WidgetContent.Widget,
- size: SizeF,
+ size: SizeF?,
factory: WidgetViewFactory,
): DisposableHandle {
val disposables = DisposableHandles()
@@ -49,6 +62,22 @@ object CommunalAppWidgetHostViewBinder {
val widget = factory.createWidget(context, model, size)
waitForLayout(container)
container.post { container.setView(widget) }
+ if (communalWidgetResizing()) {
+ // Update the app widget size in the background.
+ launch("$TAG#updateSize", backgroundContext) {
+ container.sizeFlow().flowOn(mainContext).distinctUntilChanged().collect {
+ (width, height) ->
+ widget.updateAppWidgetSize(
+ /* newOptions = */ Bundle(),
+ /* minWidth = */ width,
+ /* minHeight = */ height,
+ /* maxWidth = */ width,
+ /* maxHeight = */ height,
+ /* ignorePadding = */ true,
+ )
+ }
+ }
+ }
}
disposables += DisposableHandle { loadingJob.cancel() }
@@ -69,3 +98,13 @@ private fun ViewGroup.setView(view: View) {
(view.parent as? ViewGroup)?.removeView(view)
addView(view)
}
+
+private fun View.sizeAsDp(): IntSize = IntSize(width.toDp(context), height.toDp(context))
+
+private fun View.sizeFlow(): Flow<IntSize> = conflatedCallbackFlow {
+ if (isLaidOut && !isLayoutRequested) {
+ trySend(sizeAsDp())
+ }
+ val disposable = onLayoutChanged { trySend(sizeAsDp()) }
+ awaitClose { disposable.dispose() }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt
index 56b769e7bc13..2e12bad744f0 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/CommunalAppWidgetSection.kt
@@ -25,13 +25,17 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.systemui.Flags.communalWidgetResizing
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.ui.binder.CommunalAppWidgetHostViewBinder
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import com.android.systemui.communal.util.WidgetViewFactory
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.res.R
import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
@@ -39,6 +43,8 @@ class CommunalAppWidgetSection
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
+ @Main private val mainContext: CoroutineContext,
+ @UiBackground private val backgroundContext: CoroutineContext,
private val factory: WidgetViewFactory,
) {
@@ -76,10 +82,12 @@ constructor(
context = context,
container = this,
model = model,
- size = size,
+ size = if (!communalWidgetResizing()) size else null,
factory = factory,
applicationScope = applicationScope,
- )
+ mainContext = mainContext,
+ backgroundContext = backgroundContext,
+ ),
)
accessibilityDelegate = viewModel.widgetAccessibilityDelegate
diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
index cafa74faf1a1..07a7c7cba2fd 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
@@ -43,7 +43,7 @@ constructor(
suspend fun createWidget(
context: Context,
model: CommunalContentModel.WidgetContent.Widget,
- size: SizeF,
+ size: SizeF?,
): CommunalAppWidgetHostView =
withContext("$TAG#createWidget", uiBgContext) {
val view =
@@ -54,14 +54,16 @@ constructor(
// Instead of setting the view as the listener directly, we wrap the view in a delegate
// which ensures the callbacks always get called on the main thread.
appWidgetHost.setListener(model.appWidgetId, listenerFactory.create(view))
- view.updateAppWidgetSize(
- /* newOptions = */ Bundle(),
- /* minWidth = */ size.width.toInt(),
- /* minHeight = */ size.height.toInt(),
- /* maxWidth = */ size.width.toInt(),
- /* maxHeight = */ size.height.toInt(),
- /* ignorePadding = */ true,
- )
+ if (size != null) {
+ view.updateAppWidgetSize(
+ /* newOptions = */ Bundle(),
+ /* minWidth = */ size.width.toInt(),
+ /* minHeight = */ size.height.toInt(),
+ /* maxWidth = */ size.width.toInt(),
+ /* maxHeight = */ size.height.toInt(),
+ /* ignorePadding = */ true,
+ )
+ }
view
}
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt
index 287e85ca4358..ca92953dca4a 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduDialog.kt
@@ -16,32 +16,40 @@
package com.android.systemui.education.ui.view
-import android.app.AlertDialog
+import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.Gravity
+import android.view.Window
import android.view.WindowManager
-import android.widget.ToastPresenter
+import android.widget.ImageView
+import android.widget.TextView
import com.android.systemui.education.ui.viewmodel.ContextualEduToastViewModel
import com.android.systemui.res.R
class ContextualEduDialog(context: Context, private val model: ContextualEduToastViewModel) :
- AlertDialog(context, R.style.ContextualEduDialog) {
+ Dialog(context) {
override fun onCreate(savedInstanceState: Bundle?) {
setUpWindowProperties()
setWindowPosition()
// title is used for a11y announcement
window?.setTitle(context.getString(R.string.contextual_education_dialog_title))
- // TODO: b/369791926 - replace the below toast view with a custom dialog view
- val toastView = ToastPresenter.getTextToastView(context, model.message)
- setView(toastView)
+ setContentView(R.layout.contextual_edu_dialog)
+ setContent()
super.onCreate(savedInstanceState)
}
+ private fun setContent() {
+ findViewById<TextView>(R.id.edu_message)?.let { it.text = model.message }
+ findViewById<ImageView>(R.id.edu_icon)?.let { it.setImageResource(model.icon) }
+ }
+
private fun setUpWindowProperties() {
window?.apply {
+ requestFeature(Window.FEATURE_NO_TITLE)
setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG)
clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+ setBackgroundDrawableResource(android.R.color.transparent)
}
setCanceledOnTouchOutside(false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
index 632b250512cb..5a02cda8c3f5 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
@@ -21,8 +21,11 @@ sealed class ContextualEduContentViewModel(open val userId: Int)
data class ContextualEduNotificationViewModel(
val title: String,
val message: String,
- override val userId: Int
+ override val userId: Int,
) : ContextualEduContentViewModel(userId)
-data class ContextualEduToastViewModel(val message: String, override val userId: Int) :
- ContextualEduContentViewModel(userId)
+data class ContextualEduToastViewModel(
+ val message: String,
+ val icon: Int,
+ override val userId: Int,
+) : ContextualEduContentViewModel(userId)
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
index 55639697674f..7417a7098ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
@@ -71,7 +71,7 @@ constructor(
it.userId,
)
} else {
- ContextualEduToastViewModel(getEduContent(it), it.userId)
+ ContextualEduToastViewModel(getEduContent(it), getEduIcon(it), it.userId)
}
}
.timeout(timeoutMillis, emitAfterTimeout = null)
@@ -118,4 +118,13 @@ constructor(
return resources.getString(resourceId)
}
+
+ private fun getEduIcon(educationInfo: EducationInfo): Int {
+ return when (educationInfo.gestureType) {
+ BACK -> R.drawable.contextual_edu_swipe_back
+ HOME,
+ OVERVIEW -> R.drawable.contextual_edu_swipe_up
+ ALL_APPS -> R.drawable.contextual_edu_all_apps
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 5048a5dfdec0..b3463bdc2949 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -64,7 +64,6 @@ import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
-import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -191,7 +190,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
}
};
- private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
private final Context mContext;
private final UserTracker mUserTracker;
private final OverviewProxyService mOverviewProxyService;
@@ -1042,10 +1040,6 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
mIsTrackpadThreeFingerSwipe = isTrackpadThreeFingerSwipe(ev);
- // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
- // ACTION_DOWN, in that case we should just reuse the old instance.
- mVelocityTracker.clear();
-
// Verify if this is in within the touch region and we aren't in immersive mode, and
// either the bouncer is showing or the notification panel is hidden
mInputEventReceiver.setBatchingEnabled(false);
@@ -1194,28 +1188,9 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
private void dispatchToBackAnimation(MotionEvent event) {
if (mBackAnimation != null) {
- mVelocityTracker.addMovement(event);
-
- final float velocityX;
- final float velocityY;
- if (event.getAction() == MotionEvent.ACTION_UP) {
- // Compute the current velocity is expensive (see computeCurrentVelocity), so we
- // are only doing it when the user completes the gesture.
- int unitPixelPerSecond = 1000;
- int maxVelocity = mViewConfiguration.getScaledMaximumFlingVelocity();
- mVelocityTracker.computeCurrentVelocity(unitPixelPerSecond, maxVelocity);
- velocityX = mVelocityTracker.getXVelocity();
- velocityY = mVelocityTracker.getYVelocity();
- } else {
- velocityX = Float.NaN;
- velocityY = Float.NaN;
- }
-
mBackAnimation.onBackMotion(
/* touchX = */ event.getX(),
/* touchY = */ event.getY(),
- /* velocityX = */ velocityX,
- /* velocityY = */ velocityY,
/* keyAction = */ event.getActionMasked(),
/* swipeEdge = */ mIsOnLeftEdge ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 5003a6af5c4c..7e6dae9118e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -3218,7 +3218,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
@Override
- protected void resetAllContentAlphas() {
+ public void resetAllContentAlphas() {
mLogger.logResetAllContentAlphas(getEntry());
mPrivateLayout.setAlpha(1f);
mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
@@ -3873,7 +3873,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
pw.print(", mShowingPublicInitialized: " + mShowingPublicInitialized);
NotificationContentView showingLayout = getShowingLayout();
pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
+ pw.print(", childrenContainerShowing: "
+ + (!shouldShowPublic() && mIsSummaryWithChildren));
pw.print(", mShowNoBackground: " + mShowNoBackground);
+ pw.print(", clipBounds: " + getClipBounds());
+
pw.println();
if (NotificationContentView.INCLUDE_HEIGHTS_TO_DUMP) {
dumpHeights(pw);
@@ -3896,6 +3900,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
? 0 : mChildrenContainer.getTransientViewCount();
if (mIsSummaryWithChildren || transientViewCount > 0) {
pw.println(mChildrenContainer.debugString());
+ pw.println("Children Container Intrinsic Height: "
+ + mChildrenContainer.getIntrinsicHeight());
pw.println();
List<ExpandableNotificationRow> notificationChildren = getAttachedChildren();
pw.print("Children: " + notificationChildren.size() + " {");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index b1083888ca7f..cfca8307e703 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1704,6 +1704,7 @@ public class NotificationChildrenContainer extends ViewGroup
+ "visibility: " + getVisibility()
+ ", alpha: " + getAlpha()
+ ", translationY: " + getTranslationY()
+ + ", clipBounds: " + getClipBounds()
+ ", roundableState: " + getRoundableState().debugString() + "}";
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index b171e8768d57..8ae6b7920674 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -113,6 +113,7 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
+import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
import com.android.systemui.statusbar.notification.shared.NotificationHeadsUpCycling;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation;
@@ -4372,6 +4373,16 @@ public class NotificationStackScrollLayout
}
}
+ private void resetChildAlpha() {
+ for (int i = 0; i < getChildCount(); i++) {
+ ExpandableView child = getChildAtIndex(i);
+ if (child instanceof ExpandableNotificationRow row) {
+ if (row.isExpandAnimationRunning()) continue;
+ row.resetAllContentAlphas();
+ }
+ }
+ }
+
private void logTransientNotificationRowTraversalCleaned(
ExpandableNotificationRow transientView,
String reason
@@ -4415,6 +4426,9 @@ public class NotificationStackScrollLayout
if (SceneContainerFlag.isEnabled()) {
setHeadsUpAnimatingAway(false);
}
+ if (NotificationContentAlphaOptimization.isEnabled()) {
+ resetChildAlpha();
+ }
} else {
mGroupExpansionManager.collapseGroups();
mExpandHelper.cancelImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index 8206c21fce30..9cd52153eff6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -85,9 +85,8 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() {
`when`(telephonyManager.createForSubscriptionId(anyInt())).thenReturn(telephonyManager)
`when`(telephonyManager.supplyIccLockPin(anyString())).thenReturn(mock())
simPinView =
- LayoutInflater.from(context)
- .inflate(R.layout.keyguard_sim_pin_view, null)
- .requireViewById(R.id.keyguard_sim_pin_view) as KeyguardSimPinView
+ LayoutInflater.from(context).inflate(R.layout.keyguard_sim_pin_view, null)
+ as KeyguardSimPinView
val fakeFeatureFlags = FakeFeatureFlags()
val keyguardKeyboardInteractor = KeyguardKeyboardInteractor(FakeKeyboardRepository())
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java
index dd6d259d5a34..31884b6bfc57 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/coretest/RavenwoodMockitoTest.java
@@ -16,11 +16,19 @@
package com.android.ravenwoodtest.coretest;
import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
import org.junit.Test;
public class RavenwoodMockitoTest {
+ private static class MockClass {
+ void foo() {
+ throw new RuntimeException("Unsupported!!");
+ }
+ }
+
@Test
public void checkMockitoClasses() {
// DexMaker should not exist
@@ -32,4 +40,11 @@ public class RavenwoodMockitoTest {
ClassNotFoundException.class,
() -> Class.forName("org.mockito.Matchers"));
}
+
+ @Test
+ public void checkMockitoActuallyWorks() {
+ var mock = mock(MockClass.class);
+ doNothing().when(mock).foo();
+ mock.foo();
+ }
}
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
index 49f0b599762f..e67c730df069 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
@@ -127,7 +127,7 @@ class Ravenizer {
}
}
if (includeUnsupportedMockito(allClasses)) {
- log.w("Unsupported Mockito detected in $inJar}!")
+ log.w("Unsupported Mockito detected in $inJar!")
}
stats.totalProcessTime = log.vTime("$executableName processing $inJar") {
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index ee3bbcaf711d..034127c0420e 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -162,6 +162,13 @@ flag {
}
flag {
+ name: "magnification_enlarge_pointer"
+ namespace: "accessibility"
+ description: "When fullscreen magnification is enabled, pointer icon is enlarged"
+ bug: "355734856"
+}
+
+flag {
name: "manager_avoid_receiver_timeout"
namespace: "accessibility"
description: "Register receivers on background handler so they have more time to complete"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3c95b9a02557..74437cd3c2ef 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8274,7 +8274,16 @@ public class ActivityManagerService extends IActivityManager.Stub
setThreadScheduler(proc.getRenderThreadTid(),
SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
} else {
- setThreadPriority(proc.getRenderThreadTid(), THREAD_PRIORITY_TOP_APP_BOOST);
+ if (Flags.resetOnForkEnabled()) {
+ if (Process.getThreadScheduler(proc.getRenderThreadTid())
+ == Process.SCHED_OTHER) {
+ Process.setThreadScheduler(proc.getRenderThreadTid(),
+ Process.SCHED_OTHER | Process.SCHED_RESET_ON_FORK,
+ 0);
+ }
+ }
+ setThreadPriority(proc.getRenderThreadTid(),
+ THREAD_PRIORITY_TOP_APP_BOOST);
}
}
} else {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 796de1982fe5..4073ab848f81 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -459,12 +459,13 @@ public class OomAdjuster {
void setThreadPriority(int tid, int priority) {
if (Flags.resetOnForkEnabled()) {
- Process.setThreadScheduler(tid,
- Process.SCHED_OTHER | Process.SCHED_RESET_ON_FORK,
- priority);
- } else {
- Process.setThreadPriority(tid, priority);
+ if (Process.getThreadScheduler(tid) == Process.SCHED_OTHER) {
+ Process.setThreadScheduler(tid,
+ Process.SCHED_OTHER | Process.SCHED_RESET_ON_FORK,
+ 0);
+ }
}
+ Process.setThreadPriority(tid, priority);
}
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 88268cd19a38..a734e73d213b 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -253,7 +253,11 @@ public final class PlaybackActivityMonitor
updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid));
}
}
- sEventLogger.enqueue(new NewPlayerEvent(apc));
+ var packages = mContext.getPackageManager().getPackagesForUid(apc.getClientUid());
+ sEventLogger.enqueue(new NewPlayerEvent(
+ apc,
+ packages != null && packages.length > 0 ? packages[0] : null
+ ));
synchronized(mPlayerLock) {
mPlayers.put(newPiid, apc);
maybeMutePlayerAwaitingConnection(apc);
@@ -1402,14 +1406,16 @@ public final class PlaybackActivityMonitor
private final int mPlayerIId;
private final int mPlayerType;
private final int mClientUid;
+ private final String mClientPackageName;
private final int mClientPid;
private final AudioAttributes mPlayerAttr;
private final int mSessionId;
- NewPlayerEvent(AudioPlaybackConfiguration apc) {
+ NewPlayerEvent(AudioPlaybackConfiguration apc, String packageName) {
mPlayerIId = apc.getPlayerInterfaceId();
mPlayerType = apc.getPlayerType();
mClientUid = apc.getClientUid();
+ mClientPackageName = packageName;
mClientPid = apc.getClientPid();
mPlayerAttr = apc.getAudioAttributes();
mSessionId = apc.getSessionId();
@@ -1418,7 +1424,7 @@ public final class PlaybackActivityMonitor
@Override
public String eventToString() {
return new String("new player piid:" + mPlayerIId + " uid/pid:" + mClientUid + "/"
- + mClientPid + " type:"
+ + mClientPid + " package:" + mClientPackageName + " type:"
+ AudioPlaybackConfiguration.toLogFriendlyPlayerType(mPlayerType)
+ " attr:" + mPlayerAttr
+ " session:" + mSessionId);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 8f07bb37e2ff..42a62f098b6a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -546,7 +546,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
- if (flags.isBatteryStatsEnabledForAllDisplays()) {
+ if (flags.isBatteryStatsEnabledForAllDisplays()
+ && isDisplaySupportedForBatteryStats(displayDeviceInfo)) {
mBatteryStats = BatteryStatsService.getService();
} else if (mDisplayId == Display.DEFAULT_DISPLAY) {
mBatteryStats = BatteryStatsService.getService();
@@ -2772,6 +2773,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
}
+ private static boolean isDisplaySupportedForBatteryStats(DisplayDeviceInfo displayDeviceInfo) {
+ switch (displayDeviceInfo.type) {
+ case Display.TYPE_INTERNAL:
+ case Display.TYPE_EXTERNAL:
+ return true;
+ default:
+ return false;
+ }
+ }
+
private void dumpBrightnessEvents(PrintWriter pw) {
int size = mBrightnessEventRingBuffer.size();
if (size < 1) {
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index b78f8a7d8ee7..0e7d2b631833 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -509,6 +509,21 @@ final class Constants {
static final String PROPERTY_STRIP_AUDIO_TV_NO_SYSTEM_AUDIO =
"persist.sys.hdmi.property_strip_audio_tv_no_system_audio";
+ /**
+ * Property that decides whether CEC should be disabled on standby when the low energy mode
+ * option is used.
+ */
+ static final String PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE =
+ "persist.sys.hdmi.property_was_cec_disabled_on_standby_by_low_energy_mode";
+
+ /**
+ * Property that checks if CEC was disabled on standby by low energy mode. With the help of this
+ * property we avoid re-enabling CEC if the user explicitly disabled it, unrelated to the
+ * selected energy mode.
+ */
+ static final String PROPERTY_DISABLE_CEC_ON_STANDBY_IN_LOW_ENERGY_MODE =
+ "persist.sys.hdmi.property_disable_cec_on_standby_in_low_energy_mode";
+
static final int RECORDING_TYPE_DIGITAL_RF = 1;
static final int RECORDING_TYPE_ANALOGUE_RF = 2;
static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
@@ -644,6 +659,11 @@ final class Constants {
})
@interface FeatureFlag {}
+ /**
+ * Identifier key for Low energy mode.
+ */
+ static final String KEY_LOW_ENERGY_USE = "low_energy_use";
+
private Constants() {
/* cannot be instantiated */
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8e41d18f0953..81be0baefd7a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -22,6 +22,7 @@ import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_DISABLED;
import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_ENABLED;
+import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_DISABLED;
import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
import static android.hardware.hdmi.HdmiControlManager.POWER_CONTROL_MODE_NONE;
import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_DISABLED;
@@ -478,7 +479,8 @@ public class HdmiControlService extends SystemService {
@Nullable
private HdmiCecController mCecController;
- private HdmiCecPowerStatusController mPowerStatusController;
+ @VisibleForTesting
+ protected HdmiCecPowerStatusController mPowerStatusController;
@Nullable
private HdmiEarcController mEarcController;
@@ -3814,7 +3816,32 @@ public class HdmiControlService extends SystemService {
mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON,
false);
if (mCecController != null) {
- if (isCecControlEnabled()) {
+ if (isTvDevice() && getWasCecDisabledOnStandbyByLowEnergyMode()) {
+ Slog.w(TAG, "Re-enable CEC on wake-up since it was disabled due to low energy "
+ + " mode.");
+ getHdmiCecConfig().setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HDMI_CEC_CONTROL_ENABLED);
+ setWasCecDisabledOnStandbyByLowEnergyMode(false);
+ int controlStateChangedReason = -1;
+ switch (wakeUpAction) {
+ case WAKE_UP_SCREEN_ON:
+ controlStateChangedReason =
+ HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
+ break;
+ case WAKE_UP_BOOT_UP:
+ controlStateChangedReason =
+ HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START;
+ break;
+ default:
+ Slog.e(TAG, "wakeUpAction " + wakeUpAction + " not defined.");
+ return;
+
+ }
+ // Since CEC is going to be initialized by the setting value update, we must invoke
+ // the vendor command listeners here with the reason TV woke up.
+ invokeVendorCommandListenersOnControlStateChanged(true,
+ controlStateChangedReason);
+ } else if (isCecControlEnabled()) {
int startReason = -1;
switch (wakeUpAction) {
case WAKE_UP_SCREEN_ON:
@@ -3988,6 +4015,14 @@ public class HdmiControlService extends SystemService {
if (isAudioSystemDevice() || !isPowerStandby()) {
return;
}
+ if (isTvDevice() && getDisableCecOnStandbyByLowEnergyMode()
+ && mPowerManager.isLowPowerStandbyEnabled()) {
+ Slog.w(TAG, "Disable CEC on standby due to low power energy mode.");
+ setWasCecDisabledOnStandbyByLowEnergyMode(true);
+ getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HDMI_CEC_CONTROL_DISABLED);
+ }
mCecController.enableSystemCecControl(false);
mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED);
}
@@ -5148,4 +5183,34 @@ public class HdmiControlService extends SystemService {
protected boolean isHdmiControlEnhancedBehaviorFlagEnabled() {
return hdmiControlEnhancedBehavior();
}
+
+ /**
+ * Reads the property value that decides whether CEC should be disabled on standby when the low
+ * energy mode option is used.
+ */
+ @VisibleForTesting
+ protected boolean getDisableCecOnStandbyByLowEnergyMode() {
+ return SystemProperties.getBoolean(
+ Constants.PROPERTY_DISABLE_CEC_ON_STANDBY_IN_LOW_ENERGY_MODE, false);
+ }
+
+ /**
+ * Reads the property that checks if CEC was disabled on standby by low energy mode.
+ */
+ @VisibleForTesting
+ protected boolean getWasCecDisabledOnStandbyByLowEnergyMode() {
+ return SystemProperties.getBoolean(
+ Constants.PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE, false);
+ }
+
+ /**
+ * Sets the truth value of the property that checks if CEC was disabled on standby by low energy
+ * mode.
+ */
+ @VisibleForTesting
+ protected void setWasCecDisabledOnStandbyByLowEnergyMode(boolean value) {
+ writeStringSystemProperty(
+ Constants.PROPERTY_WAS_CEC_DISABLED_ON_STANDBY_BY_LOW_ENERGY_MODE,
+ String.valueOf(value));
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java b/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java
index 7530b3b239b4..5292cbbb9336 100644
--- a/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java
+++ b/services/core/java/com/android/server/hdmi/PowerManagerWrapper.java
@@ -16,6 +16,8 @@
package com.android.server.hdmi;
+import static com.android.server.hdmi.Constants.KEY_LOW_ENERGY_USE;
+
import android.content.Context;
import android.os.PowerManager;
@@ -47,6 +49,12 @@ public class PowerManagerWrapper {
return new DefaultWakeLockWrapper(mPowerManager.newWakeLock(levelAndFlags, tag));
}
+ boolean isLowPowerStandbyEnabled() {
+ PowerManager.LowPowerStandbyPolicy lowPowerStandbyPolicy
+ = mPowerManager.getLowPowerStandbyPolicy();
+ return lowPowerStandbyPolicy.getIdentifier().equals(KEY_LOW_ENERGY_USE);
+ }
+
/**
* "Default" wrapper for {@link PowerManager.WakeLock}, as opposed to a "Fake" wrapper for
* testing - see {@link FakePowerManagerWrapper.FakeWakeLockWrapper}.
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 5d71439e8f46..458b46dab54c 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -592,7 +592,7 @@ public abstract class ApexManager {
return apexSessionInfo;
} catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re);
- throw new RuntimeException(re);
+ return null;
}
}
@@ -607,7 +607,7 @@ public abstract class ApexManager {
return result;
} catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re);
- throw new RuntimeException(re);
+ return new SparseArray<>(0);
}
}
@@ -619,7 +619,9 @@ public abstract class ApexManager {
return apexInfoList;
} catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re);
- throw new RuntimeException(re);
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "apexd verification failed : " + re.getMessage());
} catch (Exception e) {
throw new PackageManagerException(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
@@ -633,7 +635,7 @@ public abstract class ApexManager {
return waitForApexService().getStagedApexInfos(params);
} catch (RemoteException re) {
Slog.w(TAG, "Unable to contact apexservice" + re.getMessage());
- throw new RuntimeException(re);
+ return new ApexInfo[0];
} catch (Exception e) {
Slog.w(TAG, "Failed to collect staged apex infos" + e.getMessage());
return new ApexInfo[0];
@@ -646,7 +648,9 @@ public abstract class ApexManager {
waitForApexService().markStagedSessionReady(sessionId);
} catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re);
- throw new RuntimeException(re);
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Failed to mark apexd session as ready : " + re.getMessage());
} catch (Exception e) {
throw new PackageManagerException(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index c581622914fa..897ee4312d22 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1102,6 +1102,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final boolean isUpdateOwnershipEnforcementEnabled =
mPm.isUpdateOwnershipEnforcementAvailable()
&& existingUpdateOwnerPackageName != null;
+
+ if (Build.IS_USERDEBUG) {
+ Log.d("updateowner", "PackageInstallerSession computeUserActionRequirement"
+ + " isUpdateOwnershipEnforcementEnabled= " + isUpdateOwnershipEnforcementEnabled
+ + ", mPm.isUpdateOwnershipEnforcementAvailable= "
+ + mPm.isUpdateOwnershipEnforcementAvailable()
+ + ", existingUpdateOwnerPackageName=" + existingUpdateOwnerPackageName
+ + ", isUpdateOwner= " + isUpdateOwner + ", getInstallerPackageName()= "
+ + getInstallerPackageName() + ", isInstallerShell= " + isInstallerShell
+ + ", mInstallerUid=" + mInstallerUid + ", packageName = " + packageName);
+ }
// For an installation that un-archives an app, if the installer doesn't have the
// INSTALL_PACKAGES permission, the user should have already been prompted to confirm the
// un-archive request. There's no need for another confirmation during the installation.
@@ -1115,6 +1126,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|| isInstallUnarchive;
if (noUserActionNecessary) {
+ if (Build.IS_USERDEBUG) {
+ Log.d("updateowner", "PackageInstallerSession computeUserActionRequirement"
+ + " noUserActionNecessary userActionNotTypicallyNeededResponse");
+ }
return userActionNotTypicallyNeededResponse;
}
@@ -1124,15 +1139,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
&& !isInstallerShell
// We don't enforce the update ownership for the managed user and profile.
&& !isFromManagedUserOrProfile) {
+ if (Build.IS_USERDEBUG) {
+ Log.d("updateowner", "PackageInstallerSession computeUserActionRequirement"
+ + "USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER");
+ }
return USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER;
}
if (isPermissionGranted) {
+ if (Build.IS_USERDEBUG) {
+ Log.d("updateowner", "PackageInstallerSession computeUserActionRequirement"
+ + " permission userActionNotTypicallyNeededResponse");
+ }
return userActionNotTypicallyNeededResponse;
}
if (snapshot.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid,
userId)) {
+ if (Build.IS_USERDEBUG) {
+ Log.d("updateowner", "PackageInstallerSession computeUserActionRequirement"
+ + " disable USER_ACTION_REQUIRED");
+ }
// show the installer to account for device policy or unknown sources use cases
return USER_ACTION_REQUIRED;
}
@@ -1141,9 +1168,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
&& isUpdateWithoutUserActionPermissionGranted
&& ((isUpdateOwnershipEnforcementEnabled ? isUpdateOwner
: isInstallerOfRecord) || isSelfUpdate)) {
+ if (Build.IS_USERDEBUG) {
+ Log.d("updateowner", "PackageInstallerSession computeUserActionRequirement"
+ + " USER_ACTION_PENDING_APK_PARSING");
+ }
return USER_ACTION_PENDING_APK_PARSING;
}
+ if (Build.IS_USERDEBUG) {
+ Log.d("updateowner", "PackageInstallerSession computeUserActionRequirement"
+ + " USER_ACTION_REQUIRED");
+ }
return USER_ACTION_REQUIRED;
}
@@ -2714,6 +2749,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@UserActionRequirement int userActionRequirement = USER_ACTION_NOT_NEEDED;
// TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
userActionRequirement = session.computeUserActionRequirement();
+ if (Build.IS_USERDEBUG) {
+ Log.d("updateowner", "PackageInstallerSession checkUserActionRequirement"
+ + " userActionRequirement= " + userActionRequirement
+ + ", session.packageName= " + session.getPackageName());
+ }
session.updateUserActionRequirement(userActionRequirement);
if (userActionRequirement == USER_ACTION_REQUIRED
|| userActionRequirement == USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 611e0d86202a..c8cf938099f4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -340,7 +340,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
static final boolean DEBUG_UPGRADE = false;
static final boolean DEBUG_DOMAIN_VERIFICATION = false;
static final boolean DEBUG_BACKUP = false;
- public static final boolean DEBUG_INSTALL = false;
+ public static final boolean DEBUG_INSTALL = Build.IS_USERDEBUG;
public static final boolean DEBUG_REMOVE = false;
static final boolean DEBUG_PACKAGE_INFO = false;
static final boolean DEBUG_INTENT_MATCHING = false;
diff --git a/services/core/java/com/android/server/uri/UriPermission.java b/services/core/java/com/android/server/uri/UriPermission.java
index 0d1f36794f49..0ff23eab472a 100644
--- a/services/core/java/com/android/server/uri/UriPermission.java
+++ b/services/core/java/com/android/server/uri/UriPermission.java
@@ -25,6 +25,8 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import com.google.android.collect.Sets;
import java.io.PrintWriter;
@@ -82,7 +84,9 @@ final class UriPermission {
static final long INVALID_TIME = Long.MIN_VALUE;
+ @GuardedBy("this")
private ArraySet<UriPermissionOwner> mReadOwners;
+ @GuardedBy("this")
private ArraySet<UriPermissionOwner> mWriteOwners;
private String stringName;
@@ -204,14 +208,16 @@ final class UriPermission {
persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
}
globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
- if (mReadOwners != null && includingOwners) {
- ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
- for (UriPermissionOwner r : mReadOwners) {
- if (r != null) {
- r.removeReadPermission(this);
+ synchronized (this) {
+ if (mReadOwners != null && includingOwners) {
+ ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ for (UriPermissionOwner r : mReadOwners) {
+ if (r != null) {
+ r.removeReadPermission(this);
+ }
}
+ mReadOwners = null;
}
- mReadOwners = null;
}
}
if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
@@ -220,14 +226,16 @@ final class UriPermission {
persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
}
globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- if (mWriteOwners != null && includingOwners) {
- ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- for (UriPermissionOwner r : mWriteOwners) {
- if (r != null) {
- r.removeWritePermission(this);
+ synchronized (this) {
+ if (mWriteOwners != null && includingOwners) {
+ ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ for (UriPermissionOwner r : mWriteOwners) {
+ if (r != null) {
+ r.removeWritePermission(this);
+ }
}
+ mWriteOwners = null;
}
- mWriteOwners = null;
}
}
@@ -256,7 +264,7 @@ final class UriPermission {
}
}
- private void addReadOwner(UriPermissionOwner owner) {
+ private synchronized void addReadOwner(UriPermissionOwner owner) {
if (mReadOwners == null) {
mReadOwners = Sets.newArraySet();
ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
@@ -270,7 +278,7 @@ final class UriPermission {
/**
* Remove given read owner, updating {@Link #modeFlags} as needed.
*/
- void removeReadOwner(UriPermissionOwner owner) {
+ synchronized void removeReadOwner(UriPermissionOwner owner) {
if (mReadOwners == null || !mReadOwners.remove(owner)) {
Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
return;
@@ -282,7 +290,7 @@ final class UriPermission {
}
}
- private void addWriteOwner(UriPermissionOwner owner) {
+ private synchronized void addWriteOwner(UriPermissionOwner owner) {
if (mWriteOwners == null) {
mWriteOwners = Sets.newArraySet();
ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
@@ -296,7 +304,7 @@ final class UriPermission {
/**
* Remove given write owner, updating {@Link #modeFlags} as needed.
*/
- void removeWriteOwner(UriPermissionOwner owner) {
+ synchronized void removeWriteOwner(UriPermissionOwner owner) {
if (mWriteOwners == null || !mWriteOwners.remove(owner)) {
Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
return;
@@ -339,20 +347,22 @@ final class UriPermission {
}
pw.println();
- if (mReadOwners != null) {
- pw.print(prefix);
- pw.println("readOwners:");
- for (UriPermissionOwner owner : mReadOwners) {
+ synchronized (this) {
+ if (mReadOwners != null) {
pw.print(prefix);
- pw.println(" * " + owner);
+ pw.println("readOwners:");
+ for (UriPermissionOwner owner : mReadOwners) {
+ pw.print(prefix);
+ pw.println(" * " + owner);
+ }
}
- }
- if (mWriteOwners != null) {
- pw.print(prefix);
- pw.println("writeOwners:");
- for (UriPermissionOwner owner : mWriteOwners) {
+ if (mWriteOwners != null) {
pw.print(prefix);
- pw.println(" * " + owner);
+ pw.println("writeOwners:");
+ for (UriPermissionOwner owner : mWriteOwners) {
+ pw.print(prefix);
+ pw.println(" * " + owner);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0b36c7eb5fdf..31f4d081d913 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -880,8 +880,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
})
@interface SplashScreenBehavior { }
- // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
- boolean mIsExiting;
// Force an app transition to be ran in the case the visibility of the app did not change.
// We use this for the case of moving a Root Task to the back with multiple activities, and the
// top activity enters PIP; the bottom activity's visibility stays the same, but we need to
@@ -1227,10 +1225,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn);
pw.println(")");
}
- if (mStartingData != null || firstWindowDrawn || mIsExiting) {
+ if (mStartingData != null || firstWindowDrawn) {
pw.print(prefix); pw.print("startingData="); pw.print(mStartingData);
- pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
- pw.print(" mIsExiting="); pw.println(mIsExiting);
+ pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn);
}
if (mStartingWindow != null || mStartingData != null || mStartingSurface != null
|| startingMoved || mVisibleSetFromTransferredStartingWindow) {
@@ -4370,21 +4367,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
super.removeImmediately();
}
- @Override
- void removeIfPossible() {
- mIsExiting = false;
- removeAllWindowsIfPossible();
- removeImmediately();
- }
-
- @Override
- boolean handleCompleteDeferredRemoval() {
- if (mIsExiting) {
- removeIfPossible();
- }
- return super.handleCompleteDeferredRemoval();
- }
-
void onRemovedFromDisplay() {
if (mRemovingFromDisplay) {
return;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 188b368c47c5..1659f7bc6eed 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1753,7 +1753,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
}
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
static boolean containsChangeFor(WindowContainer wc, ArrayList<ChangeInfo> list) {
for (int i = list.size() - 1; i >= 0; --i) {
if (list.get(i).mContainer == wc) return true;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index b7fe32713100..87bdfa4f5d75 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -471,6 +471,16 @@ class TransitionController {
return false;
}
+ /** Returns {@code true} if the `wc` is a target of a playing transition. */
+ boolean isPlayingTarget(@NonNull WindowContainer<?> wc) {
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ if (Transition.containsChangeFor(wc, mPlayingTransitions.get(i).mTargets)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/** Returns {@code true} if the finishing transition contains `wc`. */
boolean inFinishingTransition(WindowContainer<?> wc) {
return mFinishingTransition != null && mFinishingTransition.isInTransition(wc);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ebf645d84f95..f4ad0307d24b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2109,7 +2109,7 @@ public class WindowManagerService extends IWindowManager.Stub
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Removing %s from %s", win, token);
// Window will already be removed from token before this post clean-up method is called.
if (token.isEmpty() && !token.mPersistOnEmpty) {
- token.removeImmediately();
+ token.removeIfPossible();
}
if (win.mActivityRecord != null) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 7e7ca12cd44e..5bde8b5a507c 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -90,6 +90,9 @@ class WindowToken extends WindowContainer<WindowState> {
// Is key dispatching paused for this token?
boolean paused = false;
+ /** Whether this container should be removed when it no longer animates. */
+ boolean mIsExiting;
+
/** The owner has {@link android.Manifest.permission#MANAGE_APP_TOKENS} */
final boolean mOwnerCanManageAppTokens;
@@ -276,6 +279,28 @@ class WindowToken extends WindowContainer<WindowState> {
}
}
+ @Override
+ void removeIfPossible() {
+ if (mTransitionController.isPlayingTarget(this)) {
+ // Defer removing this container until the transition is finished. So the removal can
+ // execute after the finish transaction (see Transition#buildFinishTransaction) which
+ // may reparent it to original parent.
+ mIsExiting = true;
+ return;
+ }
+ mIsExiting = false;
+ removeAllWindowsIfPossible();
+ removeImmediately();
+ }
+
+ @Override
+ boolean handleCompleteDeferredRemoval() {
+ if (mIsExiting) {
+ removeIfPossible();
+ }
+ return super.handleCompleteDeferredRemoval();
+ }
+
/**
* @return The scale for applications running in compatibility mode. Multiply the size in the
* application by this scale will be the size in the screen.
@@ -725,6 +750,9 @@ class WindowToken extends WindowContainer<WindowState> {
pw.print("fixedRotationConfig=");
pw.println(mFixedRotationTransformState.mRotatedOverrideConfiguration);
}
+ if (mIsExiting) {
+ pw.print(prefix); pw.println("isExiting=true");
+ }
}
@Override
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index c70bf8abaef6..01b2d3e34bdc 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -35,6 +35,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.description;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -2278,29 +2279,44 @@ public final class DisplayPowerControllerTest {
throws Exception {
when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(false);
- verifyNoteScreenState(Display.DEFAULT_DISPLAY, /* expectNote= */ true);
+ verifyNoteScreenState(
+ Display.DEFAULT_DISPLAY, Display.TYPE_INTERNAL, /* expectNote= */ true);
}
@Test
public void testBatteryStatNotes_enabledOnDefaultDisplayWhenEnabledOnOthers() throws Exception {
when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
- verifyNoteScreenState(Display.DEFAULT_DISPLAY, /* expectNote= */ true);
+ verifyNoteScreenState(
+ Display.DEFAULT_DISPLAY, Display.TYPE_INTERNAL, /* expectNote= */ true);
}
@Test
- public void testBatteryStatNotes_flagGuardedOnNonDefaultDisplays() throws Exception {
+ public void testBatteryStatNotes_flagOff_disabledForNonDefaultDisplays() throws Exception {
when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(false);
- verifyNoteScreenState(/* displayId= */ 2, /* expectNote= */ false);
+ verifyNoteScreenState(/* displayId= */ 2, Display.TYPE_INTERNAL, /* expectNote= */ false);
+ }
+ @Test
+ public void testBatteryStatNotes_enabledOnlyOnInternalOrExternalDisplays() throws Exception {
when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
- verifyNoteScreenState(/* displayId= */ 2, /* expectNote= */ true);
+ for (int displayType = 0; displayType < Display.TYPE_MAX; displayType++) {
+ boolean expectNote =
+ (displayType == Display.TYPE_INTERNAL)
+ || (displayType == Display.TYPE_EXTERNAL);
+ verifyNoteScreenState(/* displayId= */ 2, displayType, expectNote);
+ }
}
- private void verifyNoteScreenState(int displayId, boolean expectNote) throws Exception {
- mHolder = createDisplayPowerController(displayId, UNIQUE_ID);
+ private void verifyNoteScreenState(int displayId, int displayDeviceType, boolean expectNote)
+ throws Exception {
+ clearInvocations(mMockBatteryStats);
+ DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+ deviceInfo.type = displayDeviceType;
+ deviceInfo.uniqueId = UNIQUE_ID;
+ mHolder = createDisplayPowerController(displayId, deviceInfo);
DisplayPowerRequest dpr = new DisplayPowerRequest();
dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
@@ -2308,14 +2324,22 @@ public final class DisplayPowerControllerTest {
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
+ final String baseErrorMessage =
+ String.format("[display id=%d type=%d]", displayId, displayDeviceType);
+ final String errorMessage;
if (expectNote) {
- verify(mMockBatteryStats)
+ errorMessage = "Expected battery stats: " + baseErrorMessage;
+ verify(mMockBatteryStats, description(errorMessage))
.noteScreenState(
displayId, Display.STATE_ON, Display.STATE_REASON_DEFAULT_POLICY);
- verify(mMockBatteryStats).noteScreenBrightness(eq(displayId), anyInt());
+ verify(mMockBatteryStats, description(errorMessage))
+ .noteScreenBrightness(eq(displayId), anyInt());
} else {
- verify(mMockBatteryStats, never()).noteScreenState(anyInt(), anyInt(), anyInt());
- verify(mMockBatteryStats, never()).noteScreenBrightness(anyInt(), anyInt());
+ errorMessage = "Expected no battery stats: " + baseErrorMessage;
+ verify(mMockBatteryStats, never().description(errorMessage))
+ .noteScreenState(anyInt(), anyInt(), anyInt());
+ verify(mMockBatteryStats, never().description(errorMessage))
+ .noteScreenBrightness(anyInt(), anyInt());
}
}
@@ -2350,17 +2374,16 @@ public final class DisplayPowerControllerTest {
private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
boolean isEnabled) {
-
- setUpDisplay(displayId, uniqueId, logicalDisplayMock, displayDeviceMock,
+ DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+ deviceInfo.uniqueId = uniqueId;
+ setUpDisplay(displayId, deviceInfo, logicalDisplayMock, displayDeviceMock,
displayDeviceConfigMock, isEnabled, "display_name");
}
- private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock,
- DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock,
- boolean isEnabled, String displayName) {
+ private void setUpDisplay(int displayId, DisplayDeviceInfo deviceInfo,
+ LogicalDisplay logicalDisplayMock, DisplayDevice displayDeviceMock,
+ DisplayDeviceConfig displayDeviceConfigMock, boolean isEnabled, String displayName) {
DisplayInfo info = new DisplayInfo();
- DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
- deviceInfo.uniqueId = uniqueId;
when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock);
@@ -2368,7 +2391,7 @@ public final class DisplayPowerControllerTest {
when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled);
when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false);
when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
- when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId);
+ when(displayDeviceMock.getUniqueId()).thenReturn(deviceInfo.uniqueId);
when(displayDeviceMock.getNameLocked()).thenReturn(displayName);
when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock);
when(displayDeviceConfigMock.getProximitySensor()).thenReturn(
@@ -2415,6 +2438,12 @@ public final class DisplayPowerControllerTest {
hysteresisLevels);
}
+ private DisplayPowerControllerHolder createDisplayPowerController(
+ int displayId, DisplayDeviceInfo info) {
+ return createDisplayPowerController(
+ displayId, info, /* isEnabled= */ true, /* isAutoBrightnessAvailable= */ true);
+ }
+
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
String uniqueId) {
return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true);
@@ -2428,6 +2457,14 @@ public final class DisplayPowerControllerTest {
private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
String uniqueId, boolean isEnabled, boolean isAutoBrightnessAvailable) {
+ DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+ deviceInfo.uniqueId = uniqueId;
+ return createDisplayPowerController(
+ displayId, deviceInfo, isEnabled, isAutoBrightnessAvailable);
+ }
+
+ private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
+ DisplayDeviceInfo deviceInfo, boolean isEnabled, boolean isAutoBrightnessAvailable) {
final DisplayPowerState displayPowerState = mock(DisplayPowerState.class);
final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class);
final AutomaticBrightnessController automaticBrightnessController =
@@ -2469,7 +2506,7 @@ public final class DisplayPowerControllerTest {
when(config.getScreenBrightnessHysteresis()).thenReturn(hysteresisLevels);
when(config.getScreenBrightnessIdleHysteresis()).thenReturn(hysteresisLevels);
- setUpDisplay(displayId, uniqueId, display, device, config, isEnabled);
+ setUpDisplay(displayId, deviceInfo, display, device, config, isEnabled, "display_name");
when(config.isAutoBrightnessAvailable()).thenReturn(isAutoBrightnessAvailable);
final DisplayPowerController dpc = new DisplayPowerController(
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index d08cdc718a82..769f071e3ddc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -265,19 +265,19 @@ public class ApexManagerTest {
}
@Test
- public void testSubmitStagedSession_throwRunTimeException() throws RemoteException {
+ public void testSubmitStagedSession_throwPackageManagerExceptionOnRemoteException()
+ throws RemoteException {
doThrow(RemoteException.class).when(mApexService).submitStagedSession(any(), any());
- assertThrows(RuntimeException.class,
+ assertThrows(PackageManagerException.class,
() -> mApexManager.submitStagedSession(testParamsWithChildren()));
}
@Test
- public void testGetStagedApexInfos_throwRunTimeException() throws RemoteException {
+ public void testGetStagedApexInfos_returnsEmptyOnRemoteException() throws RemoteException {
doThrow(RemoteException.class).when(mApexService).getStagedApexInfos(any());
- assertThrows(RuntimeException.class,
- () -> mApexManager.getStagedApexInfos(testParamsWithChildren()));
+ assertThat(mApexManager.getStagedApexInfos(testParamsWithChildren())).hasLength(0);
}
@Test
@@ -298,10 +298,11 @@ public class ApexManagerTest {
}
@Test
- public void testMarkStagedSessionReady_throwRunTimeException() throws RemoteException {
+ public void testMarkStagedSessionReady_throwPackageManagerExceptionOnRemoteException()
+ throws RemoteException {
doThrow(RemoteException.class).when(mApexService).markStagedSessionReady(anyInt());
- assertThrows(RuntimeException.class,
+ assertThrows(PackageManagerException.class,
() -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
index c305fd92cfbb..dc8c1b9c8a10 100644
--- a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
@@ -290,6 +290,9 @@ public class VolumeHelperTest {
// --------------- Volume Stream APIs ---------------
@Test
public void setStreamVolume_callsASSetStreamVolumeIndex() throws Exception {
+ assumeFalse("Skipping setStreamVolume_callsASSetStreamVolumeIndex on automotive",
+ mIsAutomotive);
+
int newIndex = circularNoMinMaxIncrementVolume(STREAM_MUSIC);
mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
@@ -313,6 +316,9 @@ public class VolumeHelperTest {
@Test
public void adjustStreamVolume_callsASSetStreamVolumeIndex() throws Exception {
+ assumeFalse("Skipping adjustStreamVolume_callsASSetStreamVolumeIndex on automotive",
+ mIsAutomotive);
+
mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
mAudioService.adjustStreamVolume(STREAM_MUSIC, ADJUST_LOWER, /*flags=*/0,
mContext.getOpPackageName());
@@ -324,6 +330,9 @@ public class VolumeHelperTest {
@Test
public void handleVolumeKey_callsASSetStreamVolumeIndex() throws Exception {
+ assumeFalse("Skipping handleVolumeKey_callsASSetStreamVolumeIndex on automotive",
+ mIsAutomotive);
+
final KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
@@ -339,6 +348,9 @@ public class VolumeHelperTest {
@Test
public void setVolumeGroupVolumeIndex_callsASSetVolumeIndexForAttributes() throws Exception {
+ assumeFalse(
+ "Skipping setVolumeGroupVolumeIndex_callsASSetVolumeIndexForAttributes on "
+ + "automotive", mIsAutomotive);
assumeNotNull(mAudioMusicVolumeGroup);
mAudioService.setDeviceForStream(STREAM_MUSIC, DEVICE_OUT_USB_DEVICE);
@@ -347,8 +359,8 @@ public class VolumeHelperTest {
mContext.getOpPackageName(), /*attributionTag*/null);
mTestLooper.dispatchAll();
- verify(mSpyAudioSystem).setVolumeIndexForAttributes(
- any(), anyInt(), eq(DEVICE_OUT_USB_DEVICE));
+ verify(mSpyAudioSystem).setVolumeIndexForAttributes(any(), anyInt(),
+ eq(DEVICE_OUT_USB_DEVICE));
}
@Test
@@ -366,6 +378,7 @@ public class VolumeHelperTest {
@Test
public void check_getVolumeGroupVolumeIndex() throws Exception {
+ assumeFalse("Skipping check_getVolumeGroupVolumeIndex on automotive", mIsAutomotive);
assumeNotNull(mAudioMusicVolumeGroup);
int newIndex = circularNoMinMaxIncrementVolume(STREAM_MUSIC);
@@ -374,10 +387,9 @@ public class VolumeHelperTest {
newIndex, /*flags=*/0, mContext.getOpPackageName(), /*attributionTag*/null);
mTestLooper.dispatchAll();
- assertEquals(mAudioService.getVolumeGroupVolumeIndex(mAudioMusicVolumeGroup.getId()),
- newIndex);
- assertEquals(mAudioService.getStreamVolume(STREAM_MUSIC),
- newIndex);
+ assertEquals(newIndex,
+ mAudioService.getVolumeGroupVolumeIndex(mAudioMusicVolumeGroup.getId()));
+ assertEquals(newIndex, mAudioService.getStreamVolume(STREAM_MUSIC));
}
@Test
@@ -432,6 +444,7 @@ public class VolumeHelperTest {
@Test
public void flagAbsVolume_onBtDevice_changesVolume() throws Exception {
+ assumeFalse("Skipping flagAbsVolume_onBtDevice_changesVolume on automotive", mIsAutomotive);
mAudioService.setDeviceForStream(STREAM_NOTIFICATION, DEVICE_OUT_BLE_SPEAKER);
int newIndex = circularNoMinMaxIncrementVolume(STREAM_NOTIFICATION);
@@ -494,7 +507,7 @@ public class VolumeHelperTest {
mContext.getOpPackageName());
mTestLooper.dispatchAll();
- assertEquals(mAudioService.getRingerModeInternal(), RINGER_MODE_VIBRATE);
+ assertEquals(RINGER_MODE_VIBRATE, mAudioService.getRingerModeInternal());
}
// --------------------- Permission tests ---------------------
@@ -538,6 +551,7 @@ public class VolumeHelperTest {
// ----------------- AudioDeviceVolumeManager -----------------
@Test
public void setDeviceVolume_checkIndex() {
+ assumeFalse("Skipping setDeviceVolume_checkIndex on automotive", mIsAutomotive);
final int minIndex = mAm.getStreamMinVolume(STREAM_MUSIC);
final int maxIndex = mAm.getStreamMaxVolume(STREAM_MUSIC);
final int midIndex = (minIndex + maxIndex) / 2;
@@ -553,21 +567,17 @@ public class VolumeHelperTest {
mAudioService.setDeviceVolume(volMin, usbDevice, mContext.getOpPackageName());
mTestLooper.dispatchAll();
- if (!mIsAutomotive) {
- // there is a min/max index mismatch in automotive
- assertEquals(mAudioService.getDeviceVolume(volMin, usbDevice,
- mContext.getOpPackageName()), volMin);
- }
+ // there is a min/max index mismatch in automotive
+ assertEquals(volMin, mAudioService.getDeviceVolume(volMin, usbDevice,
+ mContext.getOpPackageName()));
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
eq(STREAM_MUSIC), anyInt(), eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
mAudioService.setDeviceVolume(volMid, usbDevice, mContext.getOpPackageName());
mTestLooper.dispatchAll();
- if (!mIsAutomotive) {
- // there is a min/max index mismatch in automotive
- assertEquals(mAudioService.getDeviceVolume(volMid, usbDevice,
- mContext.getOpPackageName()), volMid);
- }
+ // there is a min/max index mismatch in automotive
+ assertEquals(volMid, mAudioService.getDeviceVolume(volMid, usbDevice,
+ mContext.getOpPackageName()));
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
eq(STREAM_MUSIC), anyInt(), eq(AudioSystem.DEVICE_OUT_USB_DEVICE));
}
@@ -603,9 +613,8 @@ public class VolumeHelperTest {
mAudioService.setDeviceVolume(volCur, bleDevice, mContext.getOpPackageName());
mTestLooper.dispatchAll();
- assertEquals(
- mAudioService.getDeviceVolume(volCur, bleDevice, mContext.getOpPackageName()),
- volCur);
+ assertEquals(volCur,
+ mAudioService.getDeviceVolume(volCur, bleDevice, mContext.getOpPackageName()));
// Stream volume changes
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
STREAM_MUSIC, targetIndex,
@@ -618,9 +627,8 @@ public class VolumeHelperTest {
mAudioService.setDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName());
mTestLooper.dispatchAll();
- assertEquals(
- mAudioService.getDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName()),
- volIndex4);
+ assertEquals(volIndex4,
+ mAudioService.getDeviceVolume(volIndex4, bleDevice, mContext.getOpPackageName()));
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
STREAM_MUSIC, maxIndex,
AudioSystem.DEVICE_OUT_BLE_HEADSET);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java
index 04f921f495a2..629f9683a547 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakePowerManagerWrapper.java
@@ -26,6 +26,7 @@ final class FakePowerManagerWrapper extends PowerManagerWrapper {
private boolean mInteractive;
private WakeLockWrapper mWakeLock;
private boolean mWasWakeLockInstanceCreated = false;
+ private boolean mIsLowPowerStandbyEnabled = false;
FakePowerManagerWrapper(@NonNull Context context) {
@@ -60,6 +61,15 @@ final class FakePowerManagerWrapper extends PowerManagerWrapper {
}
@Override
+ boolean isLowPowerStandbyEnabled() {
+ return mIsLowPowerStandbyEnabled;
+ }
+
+ void setIsLowPowerStandbyEnabled(boolean isLowPowerStandbyEnabled) {
+ mIsLowPowerStandbyEnabled = isLowPowerStandbyEnabled;
+ }
+
+ @Override
WakeLockWrapper newWakeLock(int levelAndFlags, String tag) {
if (mWakeLock == null) {
mWakeLock = new FakeWakeLockWrapper();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 2d957401e6bd..935c8b8720fb 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -70,6 +70,7 @@ import org.junit.runners.JUnit4;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
@SmallTest
@@ -113,6 +114,10 @@ public class HdmiCecLocalDeviceTvTest {
private boolean mWokenUp;
private boolean mEarcBlocksArc;
private List<DeviceEventListener> mDeviceEventListeners = new ArrayList<>();
+ private List<VendorCommandListener> mVendorCommandListeners = new ArrayList<>();
+ private boolean mDisableCecOnStandbyByLowEnergyMode;
+ private boolean mWasCecDisabledOnStandbyByLowEnergyMode;
+ private boolean mUseHdmiCecPowerStatusController;
private class DeviceEventListener {
private HdmiDeviceInfo mDevice;
@@ -132,6 +137,30 @@ public class HdmiCecLocalDeviceTvTest {
}
}
+ private class VendorCommandListener {
+ private boolean mEnabled;
+ private int mReason;
+
+ VendorCommandListener(boolean enabled, int reason) {
+ this.mEnabled = enabled;
+ this.mReason = reason;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof VendorCommandListener)) {
+ return false;
+ }
+ VendorCommandListener other = (VendorCommandListener) obj;
+ return other.mReason == mReason && other.mEnabled == mEnabled;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mEnabled, mReason);
+ }
+ }
+
private FakeAudioFramework mAudioFramework;
private AudioManagerWrapper mAudioManager;
@@ -169,6 +198,9 @@ public class HdmiCecLocalDeviceTvTest {
@Override
boolean isPowerStandby() {
+ if (mUseHdmiCecPowerStatusController) {
+ return mPowerStatusController.isPowerStatusStandby();
+ }
return false;
}
@@ -188,6 +220,13 @@ public class HdmiCecLocalDeviceTvTest {
}
@Override
+ boolean invokeVendorCommandListenersOnControlStateChanged(
+ boolean enabled, int reason) {
+ mVendorCommandListeners.add(new VendorCommandListener(enabled, reason));
+ return true;
+ }
+
+ @Override
protected boolean earcBlocksArcConnection() {
return mEarcBlocksArc;
}
@@ -196,6 +235,21 @@ public class HdmiCecLocalDeviceTvTest {
protected void sendBroadcastAsUser(@RequiresPermission Intent intent) {
// do nothing
}
+
+ @Override
+ protected boolean getDisableCecOnStandbyByLowEnergyMode() {
+ return mDisableCecOnStandbyByLowEnergyMode;
+ }
+
+ @Override
+ protected boolean getWasCecDisabledOnStandbyByLowEnergyMode() {
+ return mWasCecDisabledOnStandbyByLowEnergyMode;
+ }
+
+ @Override
+ protected void setWasCecDisabledOnStandbyByLowEnergyMode(boolean value) {
+ mWasCecDisabledOnStandbyByLowEnergyMode = value;
+ }
};
mHdmiControlService.setIoLooper(mMyLooper);
@@ -241,6 +295,9 @@ public class HdmiCecLocalDeviceTvTest {
mHdmiControlService.getHdmiCecConfig().setIntValue(
sad, HdmiControlManager.QUERY_SAD_DISABLED);
}
+ mWasCecDisabledOnStandbyByLowEnergyMode = false;
+ mDisableCecOnStandbyByLowEnergyMode = false;
+ mUseHdmiCecPowerStatusController = false;
mNativeWrapper.clearResultMessages();
}
@@ -2238,6 +2295,92 @@ public class HdmiCecLocalDeviceTvTest {
assertThat(mHdmiCecLocalDeviceTv.getActions(SystemAudioActionFromTv.class)).hasSize(1);
}
+ @Test
+ public void lowEnergyMode_disableCecOnStandby_reEnableOnWakeup() {
+ mDisableCecOnStandbyByLowEnergyMode = true;
+ mUseHdmiCecPowerStatusController = true;
+ mPowerManager.setIsLowPowerStandbyEnabled(true);
+
+ assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ assertTrue(mWasCecDisabledOnStandbyByLowEnergyMode);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ assertFalse(mWasCecDisabledOnStandbyByLowEnergyMode);
+ }
+
+ @Test
+ public void lowEnergyMode_disableCecBeforeStandby_cecStaysDisabledOnWakeup() {
+ mDisableCecOnStandbyByLowEnergyMode = true;
+ mUseHdmiCecPowerStatusController = true;
+ mPowerManager.setIsLowPowerStandbyEnabled(true);
+
+ assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ assertFalse(mWasCecDisabledOnStandbyByLowEnergyMode);
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ }
+
+ @Test
+ public void lowEnergyMode_onWakeUp_reEnableCec_invokeVendorCommandListeners() {
+ mDisableCecOnStandbyByLowEnergyMode = true;
+ mUseHdmiCecPowerStatusController = true;
+ mPowerManager.setIsLowPowerStandbyEnabled(true);
+ VendorCommandListener vendorCommandListenerInvocationWakeup = new VendorCommandListener(
+ true, HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP);
+ VendorCommandListener vendorCommandListenerInvocationSettingChange =
+ new VendorCommandListener(true,
+ HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP);
+
+ assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ mHdmiControlService.onStandby(STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED),
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ assertTrue(mWasCecDisabledOnStandbyByLowEnergyMode);
+ mVendorCommandListeners.clear();
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.onWakeUp(WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ assertThat(mVendorCommandListeners.size()).isEqualTo(2);
+ assertTrue(mVendorCommandListeners.contains(vendorCommandListenerInvocationWakeup));
+ assertTrue(mVendorCommandListeners.contains(vendorCommandListenerInvocationSettingChange));
+ }
+
protected static class MockTvDevice extends HdmiCecLocalDeviceTv {
MockTvDevice(HdmiControlService service) {
super(service);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index 714eb4b3c093..35328a0e1dc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -23,6 +23,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
@@ -157,7 +158,16 @@ public class WindowTokenTests extends WindowTestsBase {
// Verify that the other token window is still around.
assertEquals(1, token.getWindowsCount());
+ final TransitionController transitionController = token.mTransitionController;
+ spyOn(transitionController);
+ doReturn(true).when(transitionController).isPlayingTarget(token);
window2.removeImmediately();
+ assertTrue(token.mIsExiting);
+ assertNotNull("Defer removal for playing transition", token.getParent());
+
+ doReturn(false).when(transitionController).isPlayingTarget(token);
+ token.handleCompleteDeferredRemoval();
+ assertFalse(token.mIsExiting);
// Verify that the token is no-longer attached to its parent
assertNull(token.getParent());
// Verify that the token windows are no longer attached to it.