summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl1
-rw-r--r--core/java/android/content/pm/PackageInstaller.java12
-rw-r--r--core/java/android/nfc/INfcTag.aidl3
-rw-r--r--core/java/android/nfc/Tag.java29
-rw-r--r--core/java/android/view/ViewRootImpl.java6
-rw-r--r--core/res/res/values-en-rCA/strings.xml2
-rw-r--r--core/res/res/values-in/strings.xml2
-rw-r--r--core/res/res/values-mk/strings.xml2
-rw-r--r--data/etc/car/com.android.carsystemui.xml1
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt15
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java11
-rw-r--r--services/core/java/com/android/server/slice/SliceManagerService.java2
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java71
-rw-r--r--services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java2
-rw-r--r--services/core/java/com/android/server/wm/MirrorActiveUids.java55
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java7
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java25
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java6
35 files changed, 393 insertions, 145 deletions
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index f72288c670d9..9a7a949e3cd2 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -55,4 +55,5 @@ interface IPackageInstallerSession {
int getParentSessionId();
boolean isStaged();
+ int getInstallFlags();
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3f8aedb31ea9..4030708d6a53 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1432,6 +1432,18 @@ public class PackageInstaller {
}
/**
+ * @return Session's {@link SessionParams#installFlags}.
+ * @hide
+ */
+ public int getInstallFlags() {
+ try {
+ return mSession.getInstallFlags();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @return the session ID of the multi-package session that this belongs to or
* {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
*/
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index 539fd4adb0a0..e1ccc4fb740b 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -45,4 +45,7 @@ interface INfcTag
boolean canMakeReadOnly(int ndefType);
int getMaxTransceiveLength(int technology);
boolean getExtendedLengthApdusSupported();
+
+ void setTagUpToDate(long cookie);
+ boolean isTagUpToDate(long cookie);
}
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 398ec63a931b..731d1ba78299 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -34,6 +34,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.SystemClock;
import java.io.IOException;
import java.util.Arrays;
@@ -121,6 +122,7 @@ public final class Tag implements Parcelable {
final INfcTag mTagService; // interface to NFC service, will be null if mock tag
int mConnectedTechnology;
+ long mCookie;
/**
* Hidden constructor to be used by NFC service and internal classes.
@@ -140,6 +142,17 @@ public final class Tag implements Parcelable {
mTagService = tagService;
mConnectedTechnology = -1;
+ mCookie = SystemClock.elapsedRealtime();
+
+ if (tagService == null) {
+ return;
+ }
+
+ try {
+ tagService.setTagUpToDate(mCookie);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
}
/**
@@ -361,6 +374,22 @@ public final class Tag implements Parcelable {
/** @hide */
@UnsupportedAppUsage
public INfcTag getTagService() {
+ if (mTagService == null) {
+ return null;
+ }
+
+ try {
+ if (!mTagService.isTagUpToDate(mCookie)) {
+ String id_str = "";
+ for (int i = 0; i < mId.length; i++) {
+ id_str = id_str + String.format("%02X ", mId[i]);
+ }
+ String msg = "Permission Denial: Tag ( ID: " + id_str + ") is out of date";
+ throw new SecurityException(msg);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
return mTagService;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f1eb783726db..0b19f4f44653 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3390,6 +3390,12 @@ public final class ViewRootImpl implements ViewParent,
mReportNextDraw = false;
pendingDrawFinished();
}
+
+ // Make sure the consumer is not waiting if the view root was just made invisible.
+ if (mBLASTDrawConsumer != null) {
+ mBLASTDrawConsumer.accept(null);
+ mBLASTDrawConsumer = null;
+ }
}
}
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 037359946393..fcfa7d751a91 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1344,7 +1344,7 @@
<string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Cancel"</string>
<string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Remember my choice"</string>
<string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"You can change this later in Settings &gt; Apps"</string>
- <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Always Allow*"</string>
+ <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Always allow"</string>
<string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"Never Allow"</string>
<string name="sim_removed_title" msgid="5387212933992546283">"SIM card removed"</string>
<string name="sim_removed_message" msgid="9051174064474904617">"The mobile network will be unavailable until you restart with a valid SIM card inserted."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 4638307bab6f..51396e3c4694 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2009,7 +2009,7 @@
<string name="demo_restarting_message" msgid="1160053183701746766">"Mereset perangkat..."</string>
<string name="suspended_widget_accessibility" msgid="6331451091851326101">"<xliff:g id="LABEL">%1$s</xliff:g> dinonaktifkan"</string>
<string name="conference_call" msgid="5731633152336490471">"Konferensi Telepon"</string>
- <string name="tooltip_popup_title" msgid="7863719020269945722">"Keterangan alat"</string>
+ <string name="tooltip_popup_title" msgid="7863719020269945722">"Tooltip"</string>
<string name="app_category_game" msgid="4534216074910244790">"Game"</string>
<string name="app_category_audio" msgid="8296029904794676222">"Musik &amp; Audio"</string>
<string name="app_category_video" msgid="2590183854839565814">"Film &amp; Video"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 3602d2ddcb0b..b436409bcb59 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -389,7 +389,7 @@
<string name="permlab_systemAlertWindow" msgid="5757218350944719065">"Апликацијава може да се појави врз други апликации"</string>
<string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"Апликацијава може да се појави врз други апликации или делови од екранот. Тоа може да го попречи нормалното користење на апликацијата и да го смени начинот на кој се појавуваат другите апликации."</string>
<string name="permlab_runInBackground" msgid="541863968571682785">"извршување во заднина"</string>
- <string name="permdesc_runInBackground" msgid="4344539472115495141">"Апликацијава може да се извршува во заднина. Тоа може побрзо да ја троши батеријата."</string>
+ <string name="permdesc_runInBackground" msgid="4344539472115495141">"Апликацијава може да работи во заднина. Тоа може побрзо да ја троши батеријата."</string>
<string name="permlab_useDataInBackground" msgid="783415807623038947">"користење мобилен интернет во заднина"</string>
<string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Апликацијава може да користи мобилен интернет во заднина. Тоа може да го зголеми користењето мобилен интернет."</string>
<string name="permlab_persistentActivity" msgid="464970041740567970">"направи апликацијата постојано да биде активна"</string>
diff --git a/data/etc/car/com.android.carsystemui.xml b/data/etc/car/com.android.carsystemui.xml
index a267d5650782..6c9103cb0f4f 100644
--- a/data/etc/car/com.android.carsystemui.xml
+++ b/data/etc/car/com.android.carsystemui.xml
@@ -24,5 +24,6 @@
<permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
<permission name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY"/>
<permission name="android.car.permission.MONITOR_CAR_EVS_STATUS"/>
+ <permission name="android.car.permission.CONTROL_CAR_APP_LAUNCH"/>
</privapp-permissions>
</permissions>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 2c494c01fa4b..24edc1ce555c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -693,7 +693,7 @@
<string name="instant_apps_message_with_help" msgid="1816952263531203932">"Sovellus avattiin ilman asennusta. Katso lisätietoja napauttamalla."</string>
<string name="app_info" msgid="5153758994129963243">"Sovelluksen tiedot"</string>
<string name="go_to_web" msgid="636673528981366511">"Siirry selaimeen"</string>
- <string name="mobile_data" msgid="4564407557775397216">"Mobiilitiedonsiirto"</string>
+ <string name="mobile_data" msgid="4564407557775397216">"Mobiilidata"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi on pois päältä"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e1afd3fe6a30..4a7d7089d712 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -78,6 +78,18 @@
<!-- Checkbox label for USB device dialogs with warning text for USB device dialogs. [CHAR LIMIT=200]-->
<string name="usb_device_permission_prompt_warn">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device.</string>
+ <!-- USB audio device permission dialog title. [CHAR LIMIT=200]-->
+ <string name="usb_audio_device_permission_prompt_title">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?</string>
+
+ <!-- USB audio device confirm dialog title. [CHAR LIMIT=200]-->
+ <string name="usb_audio_device_confirm_prompt_title">Open <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to handle <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?</string>
+
+ <!-- Checkbox label for USB audio device dialogs with warning text for USB audio device dialogs. [CHAR LIMIT=NONE]-->
+ <string name="usb_audio_device_prompt_warn">This app has not been granted record permission but could capture audio through this USB device. Using <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> with this device might prevent hearing calls, notifications and alarms.</string>
+
+ <!-- Prompt for the USB audio device permission dialog [CHAR LIMIT=NONE] -->
+ <string name="usb_audio_device_prompt">Using <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> with this device might prevent hearing calls, notifications and alarms.</string>
+
<!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] -->
<string name="usb_accessory_permission_prompt">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_accessory" example="USB Dock">%2$s</xliff:g>?</string>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e9f288d51317..9b52746800a8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -112,6 +112,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -324,6 +325,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
// the properties of the keyguard
private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final Lazy<NotificationShadeWindowController> mNotificationShadeWindowControllerLazy;
/**
* Last SIM state reported by the telephony system.
@@ -846,7 +848,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
KeyguardStateController keyguardStateController,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- Lazy<NotificationShadeDepthController> notificationShadeDepthController) {
+ Lazy<NotificationShadeDepthController> notificationShadeDepthController,
+ Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy) {
super(context);
mFalsingCollector = falsingCollector;
mLockPatternUtils = lockPatternUtils;
@@ -862,6 +865,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mKeyguardDisplayManager = keyguardDisplayManager;
dumpManager.registerDumpable(getClass().getName(), this);
mDeviceConfig = deviceConfig;
+ mNotificationShadeWindowControllerLazy = notificationShadeWindowControllerLazy;
mShowHomeOverLockscreen = mDeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
@@ -1889,10 +1893,13 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
Trace.beginSection(
"KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
- handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration,
- params.mApps, params.mWallpapers, params.mNonApps,
- params.mFinishedCallback);
- mFalsingCollector.onSuccessfulUnlock();
+ mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams(
+ () -> {
+ handleStartKeyguardExitAnimation(params.startTime,
+ params.fadeoutDuration, params.mApps, params.mWallpapers,
+ params.mNonApps, params.mFinishedCallback);
+ mFalsingCollector.onSuccessfulUnlock();
+ });
Trace.endSection();
break;
case CANCEL_KEYGUARD_EXIT_ANIM:
@@ -2190,10 +2197,12 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mKeyguardGoingAwayRunnable.run();
} else {
// TODO(bc-unlock): Fill parameters
- handleStartKeyguardExitAnimation(
- SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
- mHideAnimation.getDuration(), null /* apps */, null /* wallpapers */,
- null /* nonApps */, null /* finishedCallback */);
+ mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams(() -> {
+ handleStartKeyguardExitAnimation(
+ SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
+ mHideAnimation.getDuration(), null /* apps */, null /* wallpapers */,
+ null /* nonApps */, null /* finishedCallback */);
+ });
}
}
Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index cae9feeb62eb..88dcf6d35075 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -42,6 +42,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
@@ -97,7 +98,8 @@ public class KeyguardModule {
KeyguardStateController keyguardStateController,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- Lazy<NotificationShadeDepthController> notificationShadeDepthController) {
+ Lazy<NotificationShadeDepthController> notificationShadeDepthController,
+ Lazy<NotificationShadeWindowController> notificationShadeWindowController) {
return new KeyguardViewMediator(
context,
falsingCollector,
@@ -120,7 +122,8 @@ public class KeyguardModule {
keyguardStateController,
keyguardUnlockAnimationController,
unlockedScreenOffAnimationController,
- notificationShadeDepthController
+ notificationShadeDepthController,
+ notificationShadeWindowController
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 6ea79af8b9ad..65ff5583e7d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
@@ -188,6 +189,14 @@ public interface NotificationShadeWindowController extends RemoteInputController
default void setLightRevealScrimOpaque(boolean opaque) {}
/**
+ * Defer any application of window {@link WindowManager.LayoutParams} until {@code scope} is
+ * fully applied.
+ */
+ default void batchApplyWindowLayoutParams(@NonNull Runnable scope) {
+ scope.run();
+ }
+
+ /**
* Custom listener to pipe data back to plugins about whether or not the status bar would be
* collapsed if not for the plugin.
* TODO: Find cleaner way to do this.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 33c4109b3426..3ba66bff66bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -145,6 +145,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.RemoteInputController;
@@ -664,7 +665,9 @@ public class NotificationPanelViewController extends PanelViewController {
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
- StatusBarStateController statusBarStateController, DozeLog dozeLog,
+ StatusBarStateController statusBarStateController,
+ NotificationShadeWindowController notificationShadeWindowController,
+ DozeLog dozeLog,
DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper,
LatencyTracker latencyTracker, PowerManager powerManager,
AccessibilityManager accessibilityManager, @DisplayId int displayId,
@@ -716,6 +719,7 @@ public class NotificationPanelViewController extends PanelViewController {
dozeLog,
keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController,
+ notificationShadeWindowController,
vibratorHelper,
statusBarKeyguardViewManager,
latencyTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 030a8951943d..8c76a1bf4f83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -107,6 +107,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
private final SysuiColorExtractor mColorExtractor;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private float mFaceAuthDisplayBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
+ /**
+ * Layout params would be aggregated and dispatched all at once if this is > 0.
+ *
+ * @see #batchApplyWindowLayoutParams(Runnable)
+ */
+ private int mDeferWindowLayoutParams;
@Inject
public NotificationShadeWindowControllerImpl(Context context, WindowManager windowManager,
@@ -433,6 +439,20 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
}
}
+ private void applyWindowLayoutParams() {
+ if (mDeferWindowLayoutParams == 0 && mLp != null && mLp.copyFrom(mLpChanged) != 0) {
+ mWindowManager.updateViewLayout(mNotificationShadeView, mLp);
+ }
+ }
+
+ @Override
+ public void batchApplyWindowLayoutParams(Runnable scope) {
+ mDeferWindowLayoutParams++;
+ scope.run();
+ mDeferWindowLayoutParams--;
+ applyWindowLayoutParams();
+ }
+
private void apply(State state) {
applyKeyguardFlags(state);
applyFocusableFlag(state);
@@ -447,9 +467,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
applyHasTopUi(state);
applyNotTouchable(state);
applyStatusBarColorSpaceAgnosticFlag(state);
- if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
- mWindowManager.updateViewLayout(mNotificationShadeView, mLp);
- }
+ applyWindowLayoutParams();
+
if (mHasTopUi != mHasTopUiChanged) {
whitelistIpcs(() -> {
try {
@@ -722,6 +741,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
pw.println(TAG + ":");
pw.println(" mKeyguardMaxRefreshRate=" + mKeyguardMaxRefreshRate);
pw.println(" mKeyguardPreferredRefreshRate=" + mKeyguardPreferredRefreshRate);
+ pw.println(" mDeferWindowLayoutParams=" + mDeferWindowLayoutParams);
pw.println(mCurrentState);
if (mNotificationShadeView != null && mNotificationShadeView.getViewRootImpl() != null) {
mNotificationShadeView.getViewRootImpl().dump(" ", pw);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 2bf16fc9e52c..040820e90790 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -54,6 +54,7 @@ import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
@@ -177,6 +178,7 @@ public abstract class PanelViewController {
private boolean mExpandLatencyTracking;
private final PanelView mView;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final NotificationShadeWindowController mNotificationShadeWindowController;
protected final Resources mResources;
protected final KeyguardStateController mKeyguardStateController;
protected final SysuiStatusBarStateController mStatusBarStateController;
@@ -215,6 +217,7 @@ public abstract class PanelViewController {
DozeLog dozeLog,
KeyguardStateController keyguardStateController,
SysuiStatusBarStateController statusBarStateController,
+ NotificationShadeWindowController notificationShadeWindowController,
VibratorHelper vibratorHelper,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
LatencyTracker latencyTracker,
@@ -247,6 +250,7 @@ public abstract class PanelViewController {
mResources = mView.getResources();
mKeyguardStateController = keyguardStateController;
mStatusBarStateController = statusBarStateController;
+ mNotificationShadeWindowController = notificationShadeWindowController;
mFlingAnimationUtils = flingAnimationUtilsBuilder
.reset()
.setMaxLengthSeconds(0.6f)
@@ -743,34 +747,36 @@ public abstract class PanelViewController {
if (isNaN(h)) {
Log.wtf(TAG, "ExpandedHeight set to NaN");
}
- if (mExpandLatencyTracking && h != 0f) {
- DejankUtils.postAfterTraversal(
- () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
- mExpandLatencyTracking = false;
- }
- float maxPanelHeight = getMaxPanelHeight();
- if (mHeightAnimator == null) {
- if (mTracking) {
- float overExpansionPixels = Math.max(0, h - maxPanelHeight);
- setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
+ mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
+ if (mExpandLatencyTracking && h != 0f) {
+ DejankUtils.postAfterTraversal(
+ () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
+ mExpandLatencyTracking = false;
+ }
+ float maxPanelHeight = getMaxPanelHeight();
+ if (mHeightAnimator == null) {
+ if (mTracking) {
+ float overExpansionPixels = Math.max(0, h - maxPanelHeight);
+ setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
+ }
+ mExpandedHeight = Math.min(h, maxPanelHeight);
+ } else {
+ mExpandedHeight = h;
}
- mExpandedHeight = Math.min(h, maxPanelHeight);
- } else {
- mExpandedHeight = h;
- }
- // If we are closing the panel and we are almost there due to a slow decelerating
- // interpolator, abort the animation.
- if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) {
- mExpandedHeight = 0f;
- if (mHeightAnimator != null) {
- mHeightAnimator.end();
+ // If we are closing the panel and we are almost there due to a slow decelerating
+ // interpolator, abort the animation.
+ if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) {
+ mExpandedHeight = 0f;
+ if (mHeightAnimator != null) {
+ mHeightAnimator.end();
+ }
}
- }
- mExpandedFraction = Math.min(1f,
- maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
- onHeightUpdated(mExpandedHeight);
- updatePanelExpansionAndVisibility();
+ mExpandedFraction = Math.min(1f,
+ maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+ onHeightUpdated(mExpandedHeight);
+ updatePanelExpansionAndVisibility();
+ });
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 071c8c9117ec..0eefc9404825 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2937,9 +2937,8 @@ public class StatusBar extends SystemUI implements
// turned off fully.
boolean keyguardForDozing = mDozeServiceHost.getDozingRequested()
&& (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
- boolean isWakingAndOccluded = isOccluded() && isWaking();
boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
- || keyguardForDozing) && !wakeAndUnlocking && !isWakingAndOccluded;
+ || keyguardForDozing) && !wakeAndUnlocking;
if (keyguardForDozing) {
updatePanelExpansionForKeyguard();
}
@@ -3560,26 +3559,29 @@ public class StatusBar extends SystemUI implements
public void onStartedWakingUp() {
String tag = "StatusBar#onStartedWakingUp";
DejankUtils.startDetectingBlockingIpcs(tag);
- mDeviceInteractive = true;
- mWakeUpCoordinator.setWakingUp(true);
- if (!mKeyguardBypassController.getBypassEnabled()) {
- mHeadsUpManager.releaseAllImmediately();
- }
- updateVisibleToUser();
- updateIsKeyguard();
- mDozeServiceHost.stopDozing();
- // This is intentionally below the stopDozing call above, since it avoids that we're
- // unnecessarily animating the wakeUp transition. Animations should only be enabled
- // once we fully woke up.
- updateRevealEffect(true /* wakingUp */);
- updateNotificationPanelTouchState();
-
- // If we are waking up during the screen off animation, we should undo making the
- // expanded visible (we did that so the LightRevealScrim would be visible).
- if (mUnlockedScreenOffAnimationController.isScreenOffLightRevealAnimationPlaying()) {
- makeExpandedInvisible();
- }
+ mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
+ mDeviceInteractive = true;
+ mWakeUpCoordinator.setWakingUp(true);
+ if (!mKeyguardBypassController.getBypassEnabled()) {
+ mHeadsUpManager.releaseAllImmediately();
+ }
+ updateVisibleToUser();
+ updateIsKeyguard();
+ mDozeServiceHost.stopDozing();
+ // This is intentionally below the stopDozing call above, since it avoids that we're
+ // unnecessarily animating the wakeUp transition. Animations should only be enabled
+ // once we fully woke up.
+ updateRevealEffect(true /* wakingUp */);
+ updateNotificationPanelTouchState();
+
+ // If we are waking up during the screen off animation, we should undo making the
+ // expanded visible (we did that so the LightRevealScrim would be visible).
+ if (mUnlockedScreenOffAnimationController
+ .isScreenOffLightRevealAnimationPlaying()) {
+ makeExpandedInvisible();
+ }
+ });
DejankUtils.stopDetectingBlockingIpcs(tag);
}
@@ -3717,10 +3719,6 @@ public class StatusBar extends SystemUI implements
== WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
}
- boolean isWaking() {
- return mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_WAKING;
- }
-
public void notifyBiometricAuthModeChanged() {
mDozeServiceHost.updateDozing();
updateScrimController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 12258136c011..67985b95dda4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -21,7 +21,7 @@ import android.app.IActivityManager
import android.app.IUidObserver
import android.app.Notification
import android.app.Notification.CallStyle.CALL_TYPE_ONGOING
-import android.content.Intent
+import android.app.PendingIntent
import android.util.Log
import android.view.View
import androidx.annotation.VisibleForTesting
@@ -98,7 +98,7 @@ class OngoingCallController @Inject constructor(
val newOngoingCallInfo = CallNotificationInfo(
entry.sbn.key,
entry.sbn.notification.`when`,
- entry.sbn.notification.contentIntent?.intent,
+ entry.sbn.notification.contentIntent,
entry.sbn.uid,
entry.sbn.notification.extras.getInt(
Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING,
@@ -230,7 +230,6 @@ class OngoingCallController @Inject constructor(
logger.logChipClicked()
activityStarter.postStartActivityDismissingKeyguard(
intent,
- 0,
ActivityLaunchAnimator.Controller.fromView(
backgroundView,
InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP)
@@ -351,7 +350,7 @@ class OngoingCallController @Inject constructor(
private data class CallNotificationInfo(
val key: String,
val callStartTime: Long,
- val intent: Intent?,
+ val intent: PendingIntent?,
val uid: Int,
/** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */
val isOngoing: Boolean,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 6d8645e44fb0..086cb1ab68fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -51,6 +51,7 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -64,9 +65,6 @@ import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
-import java.util.Optional;
-import java.util.function.Function;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -75,6 +73,11 @@ import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+import java.util.function.Function;
+
+import dagger.Lazy;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -103,6 +106,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private @Mock UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private @Mock IKeyguardDrawnCallback mKeyguardDrawnCallback;
+ private @Mock Lazy<NotificationShadeWindowController> mNotificationShadeWindowControllerLazy;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -144,7 +148,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mKeyguardStateController,
() -> mKeyguardUnlockAnimationController,
mUnlockedScreenOffAnimationController,
- () -> mNotificationShadeDepthController);
+ () -> mNotificationShadeDepthController,
+ mNotificationShadeWindowControllerLazy);
mViewMediator.start();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 13989d3f0ebe..5eaa60a6f157 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -23,7 +23,6 @@ import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
-import static com.android.systemui.statusbar.notification.ViewGroupFadeHelper.reset;
import static com.google.common.truth.Truth.assertThat;
@@ -107,6 +106,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
@@ -305,6 +305,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private NotificationsQSContainerController mNotificationsQSContainerController;
@Mock
+ private NotificationShadeWindowController mNotificationShadeWindowController;
+ @Mock
private FeatureFlags mFeatureFlags;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
@@ -402,8 +404,10 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
.thenReturn(mKeyguardBottomArea);
when(mNotificationRemoteInputManager.isRemoteInputActive()).thenReturn(false);
-
- reset(mView);
+ doAnswer(invocation -> {
+ ((Runnable) invocation.getArgument(0)).run();
+ return null;
+ }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
@@ -412,8 +416,9 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
mNotificationLockscreenUserManager, mNotificationEntryManager,
- mKeyguardStateController, mStatusBarStateController, mDozeLog,
- mDozeParameters, mCommandQueue, mVibratorHelper,
+ mKeyguardStateController, mStatusBarStateController,
+ mNotificationShadeWindowController,
+ mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
mMetricsLogger, mActivityManager, mConfigurationController,
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
index 90b8a74d88be..cb468108880a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
@@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -225,4 +226,17 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
assertThat((mLayoutParameters.getValue().flags & FLAG_NOT_FOCUSABLE) != 0).isTrue();
assertThat((mLayoutParameters.getValue().flags & FLAG_ALT_FOCUSABLE_IM) == 0).isTrue();
}
+
+ @Test
+ public void batchApplyWindowLayoutParams_doesNotDispatchEvents() {
+ mNotificationShadeWindowController.setForceDozeBrightness(true);
+ verify(mWindowManager).updateViewLayout(any(), any());
+
+ clearInvocations(mWindowManager);
+ mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
+ mNotificationShadeWindowController.setForceDozeBrightness(false);
+ verify(mWindowManager, never()).updateViewLayout(any(), any());
+ });
+ verify(mWindowManager).updateViewLayout(any(), any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 20575ae504ad..2709e436a663 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -351,6 +351,10 @@ public class StatusBarTest extends SysuiTestCase {
when(mStatusBarComponentFactory.create()).thenReturn(mStatusBarComponent);
when(mStatusBarComponent.getNotificationShadeWindowViewController()).thenReturn(
mNotificationShadeWindowViewController);
+ doAnswer(invocation -> {
+ ((Runnable) invocation.getArgument(0)).run();
+ return null;
+ }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
mShadeController = new ShadeControllerImpl(mCommandQueue,
mStatusBarStateController, mNotificationShadeWindowController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index b385b7d62cff..45c6be936eb9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -22,7 +22,6 @@ import android.app.IUidObserver
import android.app.Notification
import android.app.PendingIntent
import android.app.Person
-import android.content.Intent
import android.service.notification.NotificationListenerService.REASON_USER_STOPPED
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -429,6 +428,19 @@ class OngoingCallControllerTest : SysuiTestCase() {
.isEqualTo(OngoingCallLogger.OngoingCallEvents.ONGOING_CALL_CLICKED.id)
}
+ /** Regression test for b/212467440. */
+ @Test
+ fun chipClicked_activityStarterTriggeredWithUnmodifiedIntent() {
+ val notifEntry = createOngoingCallNotifEntry()
+ val pendingIntent = notifEntry.sbn.notification.contentIntent
+ notifCollectionListener.onEntryUpdated(notifEntry)
+
+ chipView.performClick()
+
+ // Ensure that the sysui didn't modify the notification's intent -- see b/212467440.
+ verify(mockActivityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any())
+ }
+
@Test
fun notifyChipVisibilityChanged_visibleEventLogged() {
controller.notifyChipVisibilityChanged(true)
@@ -570,7 +582,6 @@ class OngoingCallControllerTest : SysuiTestCase() {
notificationEntryBuilder.modifyNotification(context).setContentIntent(null)
} else {
val contentIntent = mock(PendingIntent::class.java)
- `when`(contentIntent.intent).thenReturn(mock(Intent::class.java))
notificationEntryBuilder.modifyNotification(context).setContentIntent(contentIntent)
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 330d2ddc0a94..ed7448140581 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13804,14 +13804,26 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- if (!Build.IS_DEBUGGABLE) {
- int match = mContext.getPackageManager().checkSignatures(
- ii.targetPackage, ii.packageName);
- if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
+ int match = mContext.getPackageManager().checkSignatures(
+ ii.targetPackage, ii.packageName);
+ if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
+ if (Build.IS_DEBUGGABLE) {
+ String message = "Instrumentation test " + ii.packageName
+ + " doesn't have a signature matching the target "
+ + ii.targetPackage
+ + ", which would not be allowed on the production Android builds";
+ if (callingUid != Process.ROOT_UID) {
+ Slog.e(TAG, message
+ + ". THIS WILL BE DISALLOWED ON FUTURE ANDROID VERSIONS"
+ + " unless from a rooted ADB shell.");
+ } else {
+ Slog.w(TAG, message);
+ }
+ } else {
String msg = "Permission Denial: starting instrumentation "
+ className + " from pid="
+ Binder.getCallingPid()
- + ", uid=" + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ " not allowed because package " + ii.packageName
+ " does not have a signature matching the target "
+ ii.targetPackage;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d0e445749698..3ddcf17d0a47 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -126,6 +126,7 @@ import android.system.StructStat;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.MathUtils;
import android.util.Slog;
@@ -3097,6 +3098,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
inheritFileLocked(mResolvedBaseFile);
+ } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ EventLog.writeEvent(0x534e4554, "219044664");
+
+ // Installing base.apk. Make sure the app is restarted.
+ params.setDontKillApp(false);
}
// Inherit splits if not overridden.
@@ -3743,6 +3749,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@Override
+ public int getInstallFlags() {
+ return params.installFlags;
+ }
+
+ @Override
public DataLoaderParamsParcel getDataLoaderParams() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index ee0e5ba916b9..e3dcfd0c89c0 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -247,6 +247,8 @@ public class SliceManagerService extends ISliceManager.Stub {
if (autoGrantPermissions != null && callingPkg != null) {
// Need to own the Uri to call in with permissions to grant.
enforceOwner(callingPkg, uri, userId);
+ // b/208232850: Needs to verify caller before granting slice access
+ verifyCaller(callingPkg);
for (String perm : autoGrantPermissions) {
if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6fda72e1267b..eddb5e977fa2 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -59,8 +59,8 @@ import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.BitmapRegionDecoder;
import android.graphics.Color;
+import android.graphics.ImageDecoder;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.display.DisplayManager;
@@ -193,6 +193,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
+ private static final String RECORD_FILE = "decode_record";
+ private static final String RECORD_LOCK_FILE = "decode_lock_record";
// All the various per-user state files we need to be aware of
private static final String[] sPerUserFiles = new String[] {
@@ -674,8 +676,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
if (DEBUG) {
- // This is just a quick estimation, may be smaller than it is.
- long estimateSize = options.outWidth * options.outHeight * 4;
+ long estimateSize = (long) options.outWidth * options.outHeight * 4;
Slog.v(TAG, "Null crop of new wallpaper, estimate size="
+ estimateSize + ", success=" + success);
}
@@ -684,9 +685,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
FileOutputStream f = null;
BufferedOutputStream bos = null;
try {
- BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
- wallpaper.wallpaperFile.getAbsolutePath(), false);
-
// This actually downsamples only by powers of two, but that's okay; we do
// a proper scaling blit later. This is to minimize transient RAM use.
// We calculate the largest power-of-two under the actual ratio rather than
@@ -740,8 +738,24 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize());
}
- Bitmap cropped = decoder.decodeRegion(cropHint, options);
- decoder.recycle();
+ //Create a record file and will delete if ImageDecoder work well.
+ final String recordName =
+ (wallpaper.wallpaperFile.getName().equals(WALLPAPER)
+ ? RECORD_FILE : RECORD_LOCK_FILE);
+ final File record = new File(getWallpaperDir(wallpaper.userId), recordName);
+ record.createNewFile();
+ Slog.v(TAG, "record path =" + record.getPath()
+ + ", record name =" + record.getName());
+
+ final ImageDecoder.Source srcData =
+ ImageDecoder.createSource(wallpaper.wallpaperFile);
+ final int sampleSize = scale;
+ Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> {
+ decoder.setTargetSampleSize(sampleSize);
+ decoder.setCrop(estimateCrop);
+ });
+
+ record.delete();
if (cropped == null) {
Slog.e(TAG, "Could not decode new wallpaper");
@@ -1779,6 +1793,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ errorCheck(newUserId);
switchUser(newUserId, reply);
}
}, TAG);
@@ -1816,6 +1831,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
@Override
public void onBootPhase(int phase) {
+ // If someone set too large jpg file as wallpaper, system_server may be killed by lmk in
+ // generateCrop(), so we create a file in generateCrop() before ImageDecoder starts working
+ // and delete this file after ImageDecoder finishing. If the specific file exists, that
+ // means ImageDecoder can't handle the original wallpaper file, in order to avoid
+ // system_server restart again and again and rescue party will trigger factory reset,
+ // so we reset default wallpaper in case system_server is trapped into a restart loop.
+ errorCheck(UserHandle.USER_SYSTEM);
+
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
systemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
@@ -1823,6 +1846,38 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
+ private static final HashMap<Integer, String> sWallpaperType = new HashMap<Integer, String>() {
+ {
+ put(FLAG_SYSTEM, RECORD_FILE);
+ put(FLAG_LOCK, RECORD_LOCK_FILE);
+ }
+ };
+
+ private void errorCheck(int userID) {
+ sWallpaperType.forEach((type, filename) -> {
+ final File record = new File(getWallpaperDir(userID), filename);
+ if (record.exists()) {
+ Slog.w(TAG, "User:" + userID + ", wallpaper tyep = " + type
+ + ", wallpaper fail detect!! reset to default wallpaper");
+ clearWallpaperData(userID, type);
+ record.delete();
+ }
+ });
+ }
+
+ private void clearWallpaperData(int userID, int wallpaperType) {
+ final WallpaperData wallpaper = new WallpaperData(userID, getWallpaperDir(userID),
+ (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER,
+ (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP);
+ if (wallpaper.sourceExists()) {
+ wallpaper.wallpaperFile.delete();
+ }
+ if (wallpaper.cropExists()) {
+ wallpaper.cropFile.delete();
+ }
+
+ }
+
@Override
public void onUnlockUser(final int userId) {
TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index badb1f5a0a12..4708d0026931 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -97,7 +97,7 @@ class EnsureActivitiesVisibleHelper {
// activities are actually behind other fullscreen activities, but still required
// to be visible (such as performing Recents animation).
final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind
- && mTaskFragment.isTopActivityFocusable()
+ && mTaskFragment.canBeResumed(starting)
&& (starting == null || !starting.isDescendantOf(mTaskFragment));
ArrayList<TaskFragment> adjacentTaskFragments = null;
diff --git a/services/core/java/com/android/server/wm/MirrorActiveUids.java b/services/core/java/com/android/server/wm/MirrorActiveUids.java
index 4e7f1d4cca18..b9aa9599babe 100644
--- a/services/core/java/com/android/server/wm/MirrorActiveUids.java
+++ b/services/core/java/com/android/server/wm/MirrorActiveUids.java
@@ -19,7 +19,7 @@ package com.android.server.wm;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import android.app.ActivityManager.ProcessState;
-import android.util.SparseArray;
+import android.util.SparseIntArray;
import java.io.PrintWriter;
@@ -29,15 +29,14 @@ import java.io.PrintWriter;
* adjustment) or getting state from window manager (background start check).
*/
class MirrorActiveUids {
- private final SparseArray<UidRecord> mUidStates = new SparseArray<>();
+ /** Uid -> process state. */
+ private final SparseIntArray mUidStates = new SparseIntArray();
+
+ /** Uid -> number of non-app visible windows belong to the uid. */
+ private final SparseIntArray mNumNonAppVisibleWindowMap = new SparseIntArray();
synchronized void onUidActive(int uid, int procState) {
- UidRecord r = mUidStates.get(uid);
- if (r == null) {
- r = new UidRecord();
- mUidStates.put(uid, r);
- }
- r.mProcState = procState;
+ mUidStates.put(uid, procState);
}
synchronized void onUidInactive(int uid) {
@@ -45,22 +44,28 @@ class MirrorActiveUids {
}
synchronized void onUidProcStateChanged(int uid, int procState) {
- final UidRecord r = mUidStates.get(uid);
- if (r != null) {
- r.mProcState = procState;
+ final int index = mUidStates.indexOfKey(uid);
+ if (index >= 0) {
+ mUidStates.setValueAt(index, procState);
}
}
synchronized @ProcessState int getUidState(int uid) {
- final UidRecord r = mUidStates.get(uid);
- return r != null ? r.mProcState : PROCESS_STATE_NONEXISTENT;
+ return mUidStates.get(uid, PROCESS_STATE_NONEXISTENT);
}
/** Called when the surface of non-application (exclude toast) window is shown or hidden. */
synchronized void onNonAppSurfaceVisibilityChanged(int uid, boolean visible) {
- final UidRecord r = mUidStates.get(uid);
- if (r != null) {
- r.mNumNonAppVisibleWindow += visible ? 1 : -1;
+ final int index = mNumNonAppVisibleWindowMap.indexOfKey(uid);
+ if (index >= 0) {
+ final int num = mNumNonAppVisibleWindowMap.valueAt(index) + (visible ? 1 : -1);
+ if (num > 0) {
+ mNumNonAppVisibleWindowMap.setValueAt(index, num);
+ } else {
+ mNumNonAppVisibleWindowMap.removeAt(index);
+ }
+ } else if (visible) {
+ mNumNonAppVisibleWindowMap.append(uid, 1);
}
}
@@ -70,23 +75,15 @@ class MirrorActiveUids {
* {@link VisibleActivityProcessTracker}.
*/
synchronized boolean hasNonAppVisibleWindow(int uid) {
- final UidRecord r = mUidStates.get(uid);
- return r != null && r.mNumNonAppVisibleWindow > 0;
+ return mNumNonAppVisibleWindowMap.get(uid) > 0;
}
synchronized void dump(PrintWriter pw, String prefix) {
- pw.print(prefix + "NumNonAppVisibleWindowByUid:[");
- for (int i = mUidStates.size() - 1; i >= 0; i--) {
- final UidRecord r = mUidStates.valueAt(i);
- if (r.mNumNonAppVisibleWindow > 0) {
- pw.print(" " + mUidStates.keyAt(i) + ":" + r.mNumNonAppVisibleWindow);
- }
+ pw.print(prefix + "NumNonAppVisibleWindowUidMap:[");
+ for (int i = mNumNonAppVisibleWindowMap.size() - 1; i >= 0; i--) {
+ pw.print(" " + mNumNonAppVisibleWindowMap.keyAt(i) + ":"
+ + mNumNonAppVisibleWindowMap.valueAt(i));
}
pw.println("]");
}
-
- private static final class UidRecord {
- @ProcessState int mProcState;
- int mNumNonAppVisibleWindow;
- }
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index fbc8f73b53b0..9cd37b305dc6 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1979,7 +1979,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
try {
if (mTaskSupervisor.realStartActivityLocked(r, app,
- top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) {
+ top == r && r.getTask().canBeResumed(r) /*andResume*/,
+ true /*checkConfig*/)) {
mTmpBoolean = true;
}
} catch (RemoteException e) {
@@ -3623,11 +3624,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return new ArrayList<>();
}
} else {
+ final RecentTasks recentTasks = mWindowManager.mAtmService.getRecentTasks();
+ final int recentsComponentUid = recentTasks != null
+ ? recentTasks.getRecentsComponentUid()
+ : -1;
final ArrayList<ActivityRecord> activities = new ArrayList<>();
- forAllRootTasks(rootTask -> {
- if (!dumpVisibleRootTasksOnly || rootTask.shouldBeVisible(null)) {
- activities.addAll(rootTask.getDumpActivitiesLocked(name));
+ forAllLeafTasks(task -> {
+ final boolean isRecents = (task.effectiveUid == recentsComponentUid);
+ if (!dumpVisibleRootTasksOnly || task.shouldBeVisible(null) || isRecents) {
+ activities.addAll(task.getDumpActivitiesLocked(name));
}
+ return false;
});
return activities;
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5af9147cd56f..c63780c3dd57 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -70,6 +70,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug;
@@ -3563,7 +3564,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
private void setTaskBackgroundColor(@ColorInt int backgroundColor) {
TaskDisplayArea taskDisplayArea = getTaskDisplayArea();
- if (taskDisplayArea != null) {
+ if (taskDisplayArea != null && backgroundColor != Color.TRANSPARENT) {
taskDisplayArea.setBackgroundColor(backgroundColor);
// Atomic counter to make sure the clearColor callback is only called one.
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index a94fd074ff2e..2d8410bd12d2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -513,9 +513,14 @@ public class WindowManagerShellCommand extends ShellCommand {
try (ZipOutputStream out = new ZipOutputStream(getRawOutputStream())) {
ArrayList<Pair<String, ByteTransferPipe>> requestList = new ArrayList<>();
synchronized (mInternal.mGlobalLock) {
+ final RecentTasks recentTasks = mInternal.mAtmService.getRecentTasks();
+ final int recentsComponentUid = recentTasks != null
+ ? recentTasks.getRecentsComponentUid()
+ : -1;
// Request dump from all windows parallelly before writing to disk.
mInternal.mRoot.forAllWindows(w -> {
- if (w.isVisible()) {
+ final boolean isRecents = (w.mSession.mUid == recentsComponentUid);
+ if (w.isVisible() || isRecents) {
ByteTransferPipe pipe = null;
try {
pipe = new ByteTransferPipe();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b89d116f4fe4..0fbcfd3a3ba1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8465,20 +8465,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
admin.getPackageName(), userId, "set-device-owner");
Slogf.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
+ }
- if (setProfileOwnerOnCurrentUserIfNecessary
- && mInjector.userManagerIsHeadlessSystemUserMode()) {
- int currentForegroundUser = getCurrentForegroundUserId();
- Slogf.i(LOG_TAG, "setDeviceOwner(): setting " + admin
- + " as profile owner on user " + currentForegroundUser);
- // Sets profile owner on current foreground user since
- // the human user will complete the DO setup workflow from there.
- manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
- /* managedUser= */ currentForegroundUser, /* adminExtras= */ null,
- /* showDisclaimer= */ false);
+ if (setProfileOwnerOnCurrentUserIfNecessary
+ && mInjector.userManagerIsHeadlessSystemUserMode()) {
+ int currentForegroundUser;
+ synchronized (getLockObject()) {
+ currentForegroundUser = getCurrentForegroundUserId();
}
- return true;
+ Slogf.i(LOG_TAG, "setDeviceOwner(): setting " + admin
+ + " as profile owner on user " + currentForegroundUser);
+ // Sets profile owner on current foreground user since
+ // the human user will complete the DO setup workflow from there.
+ manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
+ /* managedUser= */ currentForegroundUser, /* adminExtras= */ null,
+ /* showDisclaimer= */ false);
}
+ return true;
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e6ad68aafaec..7d501356d469 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -800,7 +800,6 @@ public class WindowStateTests extends WindowTestsBase {
@Test
public void testHasActiveVisibleWindow() {
final int uid = ActivityBuilder.DEFAULT_FAKE_UID;
- mAtm.mActiveUids.onUidActive(uid, 0 /* any proc state */);
final WindowState app = createWindow(null, TYPE_APPLICATION, "app", uid);
app.mActivityRecord.setVisible(false);
@@ -828,6 +827,11 @@ public class WindowStateTests extends WindowTestsBase {
// Make the application overlay window visible. It should be a valid active visible window.
overlay.onSurfaceShownChanged(true);
assertTrue(mAtm.hasActiveVisibleWindow(uid));
+
+ // The number of windows should be independent of the existence of uid state.
+ mAtm.mActiveUids.onUidInactive(uid);
+ mAtm.mActiveUids.onUidActive(uid, 0 /* any proc state */);
+ assertTrue(mAtm.mActiveUids.hasNonAppVisibleWindow(uid));
}
@UseTestDisplay(addWindows = W_ACTIVITY)