summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rwxr-xr-xapi/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--core/java/android/app/ActivityThread.java60
-rw-r--r--core/java/android/app/ContentProviderHolder.java9
-rw-r--r--core/java/android/app/IActivityManager.aidl2
-rw-r--r--core/java/android/app/IApplicationThread.aidl3
-rw-r--r--core/java/android/app/Notification.java52
-rw-r--r--core/java/android/app/usage/UsageEvents.java2
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java7
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java6
-rw-r--r--media/java/android/media/MediaTranscodeManager.java32
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java11
-rw-r--r--non-updatable-api/current.txt2
-rw-r--r--non-updatable-api/system-current.txt1
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java540
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java331
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java20
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java49
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java89
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java23
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java6
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java45
-rw-r--r--services/core/java/com/android/server/am/ContentProviderRecord.java47
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java10
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java76
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java15
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java39
-rw-r--r--services/core/java/com/android/server/slice/SliceManagerService.java179
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java7
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java22
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java4
-rw-r--r--services/core/java/com/android/server/wm/Task.java19
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java20
-rw-r--r--services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java76
-rw-r--r--services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java36
-rw-r--r--telephony/java/android/telephony/SmsManager.java14
66 files changed, 1678 insertions, 747 deletions
diff --git a/api/current.txt b/api/current.txt
index 17fbb55d2f91..69700f3b0a60 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5596,6 +5596,7 @@ package android.app {
method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
method public int getSemanticAction();
+ method public boolean isAuthenticationRequired();
method public boolean isContextual();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR;
@@ -5625,6 +5626,7 @@ package android.app {
method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
method @NonNull public android.os.Bundle getExtras();
method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
+ method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean);
method @NonNull public android.app.Notification.Action.Builder setContextual(boolean);
method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index b011e9af40a0..721523c95ecb 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -301,6 +301,7 @@ package android {
field public static final int config_helpIntentNameKey = 17039390; // 0x104001e
field public static final int config_helpPackageNameKey = 17039387; // 0x104001b
field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
+ field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
field public static final int config_systemGallery = 17039399; // 0x1040027
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 963ef7c540c7..3332525a6647 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -42,6 +42,7 @@ package android {
public static final class R.string {
field public static final int config_defaultAssistant = 17039393; // 0x1040021
field public static final int config_defaultDialer = 17039395; // 0x1040023
+ field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
field public static final int config_systemGallery = 17039399; // 0x1040027
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7cec717f96e0..d67b98620f37 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -424,9 +424,14 @@ public final class ActivityThread extends ClientTransactionHandler {
final String authority;
final int userId;
+ @GuardedBy("mLock")
+ ContentProviderHolder mHolder; // Temp holder to be used between notifier and waiter
+ Object mLock; // The lock to be used to get notified when the provider is ready
+
public ProviderKey(String authority, int userId) {
this.authority = authority;
this.userId = userId;
+ this.mLock = new Object();
}
@Override
@@ -440,7 +445,11 @@ public final class ActivityThread extends ClientTransactionHandler {
@Override
public int hashCode() {
- return ((authority != null) ? authority.hashCode() : 0) ^ userId;
+ return hashCode(authority, userId);
+ }
+
+ public static int hashCode(final String auth, final int userIdent) {
+ return ((auth != null) ? auth.hashCode() : 0) ^ userIdent;
}
}
@@ -461,9 +470,8 @@ public final class ActivityThread extends ClientTransactionHandler {
// Mitigation for b/74523247: Used to serialize calls to AM.getContentProvider().
// Note we never removes items from this map but that's okay because there are only so many
// users and so many authorities.
- // TODO Remove it once we move CPR.wait() from AMS to the client side.
- @GuardedBy("mGetProviderLocks")
- final ArrayMap<ProviderKey, Object> mGetProviderLocks = new ArrayMap<>();
+ @GuardedBy("mGetProviderKeys")
+ final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>();
final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
= new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
@@ -1756,6 +1764,16 @@ public final class ActivityThread extends ClientTransactionHandler {
ActivityThread.this, activityToken, actionId, arguments,
cancellationSignal, resultCallback));
}
+
+ @Override
+ public void notifyContentProviderPublishStatus(@NonNull ContentProviderHolder holder,
+ @NonNull String auth, int userId, boolean published) {
+ final ProviderKey key = getGetProviderKey(auth, userId);
+ synchronized (key.mLock) {
+ key.mHolder = holder;
+ key.mLock.notifyAll();
+ }
+ }
}
private @NonNull SafeCancellationTransport createSafeCancellationTransport(
@@ -6807,13 +6825,33 @@ public final class ActivityThread extends ClientTransactionHandler {
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
ContentProviderHolder holder = null;
+ final ProviderKey key = getGetProviderKey(auth, userId);
try {
- synchronized (getGetProviderLock(auth, userId)) {
+ synchronized (key) {
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
+ // If the returned holder is non-null but its provider is null and it's not
+ // local, we'll need to wait for the publishing of the provider.
+ if (holder != null && holder.provider == null && !holder.mLocal) {
+ synchronized (key.mLock) {
+ key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
+ holder = key.mHolder;
+ }
+ if (holder != null && holder.provider == null) {
+ // probably timed out
+ holder = null;
+ }
+ }
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
+ } catch (InterruptedException e) {
+ holder = null;
+ } finally {
+ // Clear the holder from the key since the key itself is never cleared.
+ synchronized (key.mLock) {
+ key.mHolder = null;
+ }
}
if (holder == null) {
if (UserManager.get(c).isUserUnlocked(userId)) {
@@ -6831,13 +6869,13 @@ public final class ActivityThread extends ClientTransactionHandler {
return holder.provider;
}
- private Object getGetProviderLock(String auth, int userId) {
- final ProviderKey key = new ProviderKey(auth, userId);
- synchronized (mGetProviderLocks) {
- Object lock = mGetProviderLocks.get(key);
+ private ProviderKey getGetProviderKey(String auth, int userId) {
+ final int key = ProviderKey.hashCode(auth, userId);
+ synchronized (mGetProviderKeys) {
+ ProviderKey lock = mGetProviderKeys.get(key);
if (lock == null) {
- lock = key;
- mGetProviderLocks.put(key, lock);
+ lock = new ProviderKey(auth, userId);
+ mGetProviderKeys.put(key, lock);
}
return lock;
}
diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java
index 3d745831ce1c..e330a30de7b0 100644
--- a/core/java/android/app/ContentProviderHolder.java
+++ b/core/java/android/app/ContentProviderHolder.java
@@ -39,6 +39,11 @@ public class ContentProviderHolder implements Parcelable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean noReleaseNeeded;
+ /**
+ * Whether the provider here is a local provider or not.
+ */
+ public boolean mLocal;
+
@UnsupportedAppUsage
public ContentProviderHolder(ProviderInfo _info) {
info = _info;
@@ -59,6 +64,7 @@ public class ContentProviderHolder implements Parcelable {
}
dest.writeStrongBinder(connection);
dest.writeInt(noReleaseNeeded ? 1 : 0);
+ dest.writeInt(mLocal ? 1 : 0);
}
public static final @android.annotation.NonNull Parcelable.Creator<ContentProviderHolder> CREATOR
@@ -81,5 +87,6 @@ public class ContentProviderHolder implements Parcelable {
source.readStrongBinder());
connection = source.readStrongBinder();
noReleaseNeeded = source.readInt() != 0;
+ mLocal = source.readInt() != 0;
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 93dfc79109a6..f37ca61ba69f 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -461,7 +461,7 @@ interface IActivityManager {
@UnsupportedAppUsage
Rect getTaskBounds(int taskId);
@UnsupportedAppUsage
- boolean setProcessMemoryTrimLevel(in String process, int uid, int level);
+ boolean setProcessMemoryTrimLevel(in String process, int userId, int level);
// Start of L transactions
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 24da50481df3..dc9918ade9c2 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -16,6 +16,7 @@
package android.app;
+import android.app.ContentProviderHolder;
import android.app.IInstrumentationWatcher;
import android.app.IUiAutomationConnection;
import android.app.ProfilerInfo;
@@ -147,4 +148,6 @@ oneway interface IApplicationThread {
void performDirectAction(IBinder activityToken, String actionId,
in Bundle arguments, in RemoteCallback cancellationCallback,
in RemoteCallback resultCallback);
+ void notifyContentProviderPublishStatus(in ContentProviderHolder holder, String auth,
+ int userId, boolean published);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 68e65612971c..6f3e89229e4c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1492,6 +1492,7 @@ public class Notification implements Parcelable
private boolean mAllowGeneratedReplies = true;
private final @SemanticAction int mSemanticAction;
private final boolean mIsContextual;
+ private boolean mAuthenticationRequired;
/**
* Small icon representing the action.
@@ -1528,6 +1529,7 @@ public class Notification implements Parcelable
mAllowGeneratedReplies = in.readInt() == 1;
mSemanticAction = in.readInt();
mIsContextual = in.readInt() == 1;
+ mAuthenticationRequired = in.readInt() == 1;
}
/**
@@ -1536,13 +1538,14 @@ public class Notification implements Parcelable
@Deprecated
public Action(int icon, CharSequence title, PendingIntent intent) {
this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true,
- SEMANTIC_ACTION_NONE, false /* isContextual */);
+ SEMANTIC_ACTION_NONE, false /* isContextual */, false /* requireAuth */);
}
/** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */
private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
- @SemanticAction int semanticAction, boolean isContextual) {
+ @SemanticAction int semanticAction, boolean isContextual,
+ boolean requireAuth) {
this.mIcon = icon;
if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
this.icon = icon.getResId();
@@ -1554,6 +1557,7 @@ public class Notification implements Parcelable
this.mAllowGeneratedReplies = allowGeneratedReplies;
this.mSemanticAction = semanticAction;
this.mIsContextual = isContextual;
+ this.mAuthenticationRequired = requireAuth;
}
/**
@@ -1624,6 +1628,17 @@ public class Notification implements Parcelable
}
/**
+ * Returns whether the OS should only send this action's {@link PendingIntent} on an
+ * unlocked device.
+ *
+ * If the device is locked when the action is invoked, the OS should show the keyguard and
+ * require successful authentication before invoking the intent.
+ */
+ public boolean isAuthenticationRequired() {
+ return mAuthenticationRequired;
+ }
+
+ /**
* Builder class for {@link Action} objects.
*/
public static final class Builder {
@@ -1635,6 +1650,7 @@ public class Notification implements Parcelable
@Nullable private ArrayList<RemoteInput> mRemoteInputs;
private @SemanticAction int mSemanticAction;
private boolean mIsContextual;
+ private boolean mAuthenticationRequired;
/**
* Construct a new builder for {@link Action} object.
@@ -1654,7 +1670,7 @@ public class Notification implements Parcelable
* @param intent the {@link PendingIntent} to fire when users trigger this action
*/
public Builder(Icon icon, CharSequence title, PendingIntent intent) {
- this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE);
+ this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, false);
}
/**
@@ -1665,23 +1681,25 @@ public class Notification implements Parcelable
public Builder(Action action) {
this(action.getIcon(), action.title, action.actionIntent,
new Bundle(action.mExtras), action.getRemoteInputs(),
- action.getAllowGeneratedReplies(), action.getSemanticAction());
+ action.getAllowGeneratedReplies(), action.getSemanticAction(),
+ action.isAuthenticationRequired());
}
private Builder(@Nullable Icon icon, @Nullable CharSequence title,
@Nullable PendingIntent intent, @NonNull Bundle extras,
@Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
- @SemanticAction int semanticAction) {
+ @SemanticAction int semanticAction, boolean authRequired) {
mIcon = icon;
mTitle = title;
mIntent = intent;
mExtras = extras;
if (remoteInputs != null) {
- mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length);
+ mRemoteInputs = new ArrayList<>(remoteInputs.length);
Collections.addAll(mRemoteInputs, remoteInputs);
}
mAllowGeneratedReplies = allowGeneratedReplies;
mSemanticAction = semanticAction;
+ mAuthenticationRequired = authRequired;
}
/**
@@ -1776,6 +1794,21 @@ public class Notification implements Parcelable
}
/**
+ * Sets whether the OS should only send this action's {@link PendingIntent} on an
+ * unlocked device.
+ *
+ * If this is true and the device is locked when the action is invoked, the OS will
+ * show the keyguard and require successful authentication before invoking the intent.
+ * If this is false and the device is locked, the OS will decide whether authentication
+ * should be required.
+ */
+ @NonNull
+ public Builder setAuthenticationRequired(boolean authenticationRequired) {
+ mAuthenticationRequired = authenticationRequired;
+ return this;
+ }
+
+ /**
* Throws an NPE if we are building a contextual action missing one of the fields
* necessary to display the action.
*/
@@ -1827,7 +1860,8 @@ public class Notification implements Parcelable
RemoteInput[] textInputsArr = textInputs.isEmpty()
? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
- mAllowGeneratedReplies, mSemanticAction, mIsContextual);
+ mAllowGeneratedReplies, mSemanticAction, mIsContextual,
+ mAuthenticationRequired);
}
}
@@ -1841,7 +1875,8 @@ public class Notification implements Parcelable
getRemoteInputs(),
getAllowGeneratedReplies(),
getSemanticAction(),
- isContextual());
+ isContextual(),
+ isAuthenticationRequired());
}
@Override
@@ -1870,6 +1905,7 @@ public class Notification implements Parcelable
out.writeInt(mAllowGeneratedReplies ? 1 : 0);
out.writeInt(mSemanticAction);
out.writeInt(mIsContextual ? 1 : 0);
+ out.writeInt(mAuthenticationRequired ? 1 : 0);
}
public static final @android.annotation.NonNull Parcelable.Creator<Action> CREATOR =
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 3522b1b8aff5..0e6a0637d801 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -199,7 +199,7 @@ public final class UsageEvents implements Parcelable {
public static final int NOTIFICATION_INTERRUPTION = 12;
/**
- * A Slice was pinned by the default launcher or the default assistant.
+ * A Slice was pinned by the default assistant.
* @hide
*/
@SystemApi
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index 9bf05135c4c5..a23fc4b57b45 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -291,7 +291,7 @@ public class ScreenshotHelper {
};
Message msg = Message.obtain(null, screenshotType, screenshotRequest);
- final ServiceConnection myConn = mScreenshotConnection;
+
Handler h = new Handler(handler.getLooper()) {
@Override
public void handleMessage(Message msg) {
@@ -304,8 +304,8 @@ public class ScreenshotHelper {
break;
case SCREENSHOT_MSG_PROCESS_COMPLETE:
synchronized (mScreenshotLock) {
- if (myConn != null && mScreenshotConnection == myConn) {
- mContext.unbindService(myConn);
+ if (mScreenshotConnection != null) {
+ mContext.unbindService(mScreenshotConnection);
mScreenshotConnection = null;
mScreenshotService = null;
}
@@ -368,6 +368,7 @@ public class ScreenshotHelper {
}
} else {
Messenger messenger = new Messenger(mScreenshotService);
+
try {
messenger.send(msg);
} catch (RemoteException e) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fe290f3e97e8..edb972730f69 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1342,7 +1342,7 @@
android:priority="800" />
<!-- Allows an application to access data from sensors that the user uses to
- measure what is happening inside his/her body, such as heart rate.
+ measure what is happening inside their body, such as heart rate.
<p>Protection level: dangerous -->
<permission android:name="android.permission.BODY_SENSORS"
android:permissionGroup="android.permission-group.UNDEFINED"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8913e8b18750..f99be880cbe3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1823,6 +1823,8 @@
<string name="config_defaultCallScreening" translatable="false"></string>
<!-- The name of the package that will hold the system gallery role. -->
<string name="config_systemGallery" translatable="false">com.android.gallery3d</string>
+ <!-- The name of the package that will hold the system cluster service role. -->
+ <string name="config_systemAutomotiveCluster" translatable="false"></string>
<!-- The name of the package that will be allowed to change its components' label/icon. -->
<string name="config_overrideComponentUiPackage" translatable="false"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 303fde6705c2..1e2d554a088b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3069,7 +3069,8 @@
</public-group>
<public-group type="string" first-id="0x01040028">
- <!-- string definitions go here -->
+ <!-- @hide @SystemApi @TestApi -->
+ <public name="config_systemAutomotiveCluster" />
</public-group>
<public-group type="id" first-id="0x01020055">
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index e0d702e98595..2bf9848304ad 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -24,6 +24,7 @@ import static android.app.servertransaction.TestUtils.resultInfoList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.app.ContentProviderHolder;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.app.IUiAutomationConnection;
@@ -665,5 +666,10 @@ public class TransactionParcelTests {
public void performDirectAction(IBinder activityToken, String actionId, Bundle arguments,
RemoteCallback cancellationCallback, RemoteCallback resultCallback) {
}
+
+ @Override
+ public void notifyContentProviderPublishStatus(ContentProviderHolder holder, String auth,
+ int userId, boolean published) {
+ }
}
}
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
index 5d4404036102..e1bff03f6833 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -244,7 +244,7 @@ public final class MediaTranscodeManager {
}
// Updates the job progress.
- job.setJobProgress(newProgress);
+ job.updateProgress(newProgress);
// Notifies client the progress update.
if (job.mProgressUpdateExecutor != null && job.mProgressUpdateListener != null) {
@@ -254,6 +254,21 @@ public final class MediaTranscodeManager {
}
}
+ private void updateStatus(int jobId, int status) {
+ synchronized (mPendingTranscodingJobs) {
+ final TranscodingJob job = mPendingTranscodingJobs.get(jobId);
+
+ if (job == null) {
+ // This should not happen in reality.
+ Log.e(TAG, "Job " + jobId + " is not in PendingJobs");
+ return;
+ }
+
+ // Updates the job status.
+ job.updateStatus(status);
+ }
+ }
+
// Just forwards all the events to the event handler.
private ITranscodingClientCallback mTranscodingClientCallback =
new ITranscodingClientCallback.Stub() {
@@ -285,17 +300,17 @@ public final class MediaTranscodeManager {
@Override
public void onTranscodingStarted(int jobId) throws RemoteException {
-
+ updateStatus(jobId, TranscodingJob.STATUS_RUNNING);
}
@Override
public void onTranscodingPaused(int jobId) throws RemoteException {
-
+ updateStatus(jobId, TranscodingJob.STATUS_PAUSED);
}
@Override
public void onTranscodingResumed(int jobId) throws RemoteException {
-
+ updateStatus(jobId, TranscodingJob.STATUS_RUNNING);
}
@Override
@@ -683,11 +698,14 @@ public final class MediaTranscodeManager {
public static final int STATUS_RUNNING = 2;
/** The job is finished. */
public static final int STATUS_FINISHED = 3;
+ /** The job is paused. */
+ public static final int STATUS_PAUSED = 4;
@IntDef(prefix = { "STATUS_" }, value = {
STATUS_PENDING,
STATUS_RUNNING,
STATUS_FINISHED,
+ STATUS_PAUSED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Status {}
@@ -843,9 +861,13 @@ public final class MediaTranscodeManager {
return mResult;
}
- private synchronized void setJobProgress(int newProgress) {
+ private synchronized void updateProgress(int newProgress) {
mProgress = newProgress;
}
+
+ private synchronized void updateStatus(int newStatus) {
+ mStatus = newStatus;
+ }
}
/**
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
index 8e4153078174..8fe10888cab6 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
@@ -33,6 +33,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
@@ -238,6 +239,7 @@ public class MediaTranscodeManagerTest
Log.d(TAG, "Starting: testMediaTranscodeManager");
Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+ final CountDownLatch statusLatch = new CountDownLatch(1);
// Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4
// The full path of this file is:
@@ -276,12 +278,21 @@ public class MediaTranscodeManagerTest
public void onProgressUpdate(int newProgress) {
assertTrue("Invalid proress update", newProgress > mPreviousProgress);
assertTrue("Invalid proress update", newProgress <= 100);
+ if (newProgress > 0) {
+ statusLatch.countDown();
+ }
mPreviousProgress = newProgress;
progressUpdateCount.getAndIncrement();
Log.i(TAG, "Get progress update " + newProgress);
}
});
+ try {
+ statusLatch.await();
+ // The transcoding should not be finished yet as the clip is long.
+ assertTrue("Invalid status", job.getStatus() == TranscodingJob.STATUS_RUNNING);
+ } catch (InterruptedException e) { }
+
Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to cancel.");
boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index e06cf945ddaa..51e7287bfd72 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -5596,6 +5596,7 @@ package android.app {
method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
method public int getSemanticAction();
+ method public boolean isAuthenticationRequired();
method public boolean isContextual();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR;
@@ -5625,6 +5626,7 @@ package android.app {
method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
method @NonNull public android.os.Bundle getExtras();
method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
+ method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean);
method @NonNull public android.app.Notification.Action.Builder setContextual(boolean);
method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int);
}
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 0906a060c40f..cf792b6abbd2 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -301,6 +301,7 @@ package android {
field public static final int config_helpIntentNameKey = 17039390; // 0x104001e
field public static final int config_helpPackageNameKey = 17039387; // 0x104001b
field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
+ field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
field public static final int config_systemGallery = 17039399; // 0x1040027
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
new file mode 100644
index 000000000000..1de740a083c2
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 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.systemui.shared.system;
+
+import android.annotation.UserIdInt;
+import android.content.Context;
+
+public class ContextUtils {
+
+ /** Get the user associated with this context */
+ public static @UserIdInt int getUserId(Context context) {
+ return context.getUserId();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
index 7e5b42653210..93a8df41c673 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
@@ -25,7 +25,9 @@ public class AppOpItem {
private int mUid;
private String mPackageName;
private long mTimeStarted;
- private String mState;
+ private StringBuilder mState;
+ // This is only used for items with mCode == AppOpsManager.OP_RECORD_AUDIO
+ private boolean mSilenced;
public AppOpItem(int code, int uid, String packageName, long timeStarted) {
this.mCode = code;
@@ -36,9 +38,8 @@ public class AppOpItem {
.append("AppOpItem(")
.append("Op code=").append(code).append(", ")
.append("UID=").append(uid).append(", ")
- .append("Package name=").append(packageName)
- .append(")")
- .toString();
+ .append("Package name=").append(packageName).append(", ")
+ .append("Paused=");
}
public int getCode() {
@@ -57,8 +58,16 @@ public class AppOpItem {
return mTimeStarted;
}
+ public void setSilenced(boolean silenced) {
+ mSilenced = silenced;
+ }
+
+ public boolean isSilenced() {
+ return mSilenced;
+ }
+
@Override
public String toString() {
- return mState;
+ return mState.append(mSilenced).append(")").toString();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 6512624f5064..8187a2235c0a 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -19,6 +19,8 @@ package com.android.systemui.appops;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.media.AudioRecordingConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -63,6 +65,7 @@ public class AppOpsControllerImpl implements AppOpsController,
private static final boolean DEBUG = false;
private final AppOpsManager mAppOps;
+ private final AudioManager mAudioManager;
private H mBGHandler;
private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>();
@@ -73,6 +76,9 @@ public class AppOpsControllerImpl implements AppOpsController,
private final List<AppOpItem> mActiveItems = new ArrayList<>();
@GuardedBy("mNotedItems")
private final List<AppOpItem> mNotedItems = new ArrayList<>();
+ @GuardedBy("mActiveItems")
+ private final SparseArray<ArrayList<AudioRecordingConfiguration>> mRecordingsByUid =
+ new SparseArray<>();
protected static final int[] OPS = new int[] {
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
@@ -88,7 +94,8 @@ public class AppOpsControllerImpl implements AppOpsController,
Context context,
@Background Looper bgLooper,
DumpManager dumpManager,
- PermissionFlagsCache cache
+ PermissionFlagsCache cache,
+ AudioManager audioManager
) {
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mFlagsCache = cache;
@@ -97,6 +104,7 @@ public class AppOpsControllerImpl implements AppOpsController,
for (int i = 0; i < numOps; i++) {
mCallbacksByCode.put(OPS[i], new ArraySet<>());
}
+ mAudioManager = audioManager;
dumpManager.registerDumpable(TAG, this);
}
@@ -111,12 +119,19 @@ public class AppOpsControllerImpl implements AppOpsController,
if (listening) {
mAppOps.startWatchingActive(OPS, this);
mAppOps.startWatchingNoted(OPS, this);
+ mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler);
+ mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
+ mAudioManager.getActiveRecordingConfigurations()));
+
} else {
mAppOps.stopWatchingActive(this);
mAppOps.stopWatchingNoted(this);
+ mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback);
+
mBGHandler.removeCallbacksAndMessages(null); // null removes all
synchronized (mActiveItems) {
mActiveItems.clear();
+ mRecordingsByUid.clear();
}
synchronized (mNotedItems) {
mNotedItems.clear();
@@ -189,9 +204,12 @@ public class AppOpsControllerImpl implements AppOpsController,
AppOpItem item = getAppOpItemLocked(mActiveItems, code, uid, packageName);
if (item == null && active) {
item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
+ if (code == AppOpsManager.OP_RECORD_AUDIO) {
+ item.setSilenced(isAnyRecordingPausedLocked(uid));
+ }
mActiveItems.add(item);
if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
- return true;
+ return !item.isSilenced();
} else if (item != null && !active) {
mActiveItems.remove(item);
if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
@@ -215,7 +233,7 @@ public class AppOpsControllerImpl implements AppOpsController,
active = getAppOpItemLocked(mActiveItems, code, uid, packageName) != null;
}
if (!active) {
- notifySuscribers(code, uid, packageName, false);
+ notifySuscribersWorker(code, uid, packageName, false);
}
}
@@ -324,7 +342,7 @@ public class AppOpsControllerImpl implements AppOpsController,
AppOpItem item = mActiveItems.get(i);
if ((userId == UserHandle.USER_ALL
|| UserHandle.getUserId(item.getUid()) == userId)
- && isUserVisible(item)) {
+ && isUserVisible(item) && !item.isSilenced()) {
list.add(item);
}
}
@@ -343,6 +361,10 @@ public class AppOpsControllerImpl implements AppOpsController,
return list;
}
+ private void notifySuscribers(int code, int uid, String packageName, boolean active) {
+ mBGHandler.post(() -> notifySuscribersWorker(code, uid, packageName, active));
+ }
+
@Override
public void onOpActiveChanged(int code, int uid, String packageName, boolean active) {
if (DEBUG) {
@@ -360,7 +382,7 @@ public class AppOpsControllerImpl implements AppOpsController,
// If active is false, we only send the update if the op is not actively noted (prevent
// early removal)
if (!alsoNoted) {
- mBGHandler.post(() -> notifySuscribers(code, uid, packageName, active));
+ notifySuscribers(code, uid, packageName, active);
}
}
@@ -378,11 +400,11 @@ public class AppOpsControllerImpl implements AppOpsController,
alsoActive = getAppOpItemLocked(mActiveItems, code, uid, packageName) != null;
}
if (!alsoActive) {
- mBGHandler.post(() -> notifySuscribers(code, uid, packageName, true));
+ notifySuscribers(code, uid, packageName, true);
}
}
- private void notifySuscribers(int code, int uid, String packageName, boolean active) {
+ private void notifySuscribersWorker(int code, int uid, String packageName, boolean active) {
if (mCallbacksByCode.contains(code) && isUserVisible(code, uid, packageName)) {
if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName);
for (Callback cb: mCallbacksByCode.get(code)) {
@@ -408,6 +430,61 @@ public class AppOpsControllerImpl implements AppOpsController,
}
+ private boolean isAnyRecordingPausedLocked(int uid) {
+ List<AudioRecordingConfiguration> configs = mRecordingsByUid.get(uid);
+ if (configs == null) return false;
+ int configsNum = configs.size();
+ for (int i = 0; i < configsNum; i++) {
+ AudioRecordingConfiguration config = configs.get(i);
+ if (config.isClientSilenced()) return true;
+ }
+ return false;
+ }
+
+ private void updateRecordingPausedStatus() {
+ synchronized (mActiveItems) {
+ int size = mActiveItems.size();
+ for (int i = 0; i < size; i++) {
+ AppOpItem item = mActiveItems.get(i);
+ if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) {
+ boolean paused = isAnyRecordingPausedLocked(item.getUid());
+ if (item.isSilenced() != paused) {
+ item.setSilenced(paused);
+ notifySuscribers(
+ item.getCode(),
+ item.getUid(),
+ item.getPackageName(),
+ !item.isSilenced()
+ );
+ }
+ }
+ }
+ }
+ }
+
+ private AudioManager.AudioRecordingCallback mAudioRecordingCallback =
+ new AudioManager.AudioRecordingCallback() {
+ @Override
+ public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
+ synchronized (mActiveItems) {
+ mRecordingsByUid.clear();
+ final int recordingsCount = configs.size();
+ for (int i = 0; i < recordingsCount; i++) {
+ AudioRecordingConfiguration recording = configs.get(i);
+
+ ArrayList<AudioRecordingConfiguration> recordings = mRecordingsByUid.get(
+ recording.getClientUid());
+ if (recordings == null) {
+ recordings = new ArrayList<>();
+ mRecordingsByUid.put(recording.getClientUid(), recordings);
+ }
+ recordings.add(recording);
+ }
+ }
+ updateRecordingPausedStatus();
+ }
+ };
+
protected class H extends Handler {
H(Looper looper) {
super(looper);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 8a51c8515852..e77e499223aa 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -44,6 +44,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.MediaNotificationProcessor
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.util.Assert
@@ -97,6 +98,7 @@ class MediaDataManager(
dumpManager: DumpManager,
mediaTimeoutListener: MediaTimeoutListener,
mediaResumeListener: MediaResumeListener,
+ private val activityStarter: ActivityStarter,
private var useMediaResumption: Boolean,
private val useQsMediaPlayer: Boolean
) : Dumpable {
@@ -113,10 +115,11 @@ class MediaDataManager(
dumpManager: DumpManager,
broadcastDispatcher: BroadcastDispatcher,
mediaTimeoutListener: MediaTimeoutListener,
- mediaResumeListener: MediaResumeListener
+ mediaResumeListener: MediaResumeListener,
+ activityStarter: ActivityStarter
) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory,
broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener,
- Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context))
+ activityStarter, Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context))
private val appChangeReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -403,10 +406,13 @@ class MediaDataManager(
}
val runnable = if (action.actionIntent != null) {
Runnable {
- try {
- action.actionIntent.send()
- } catch (e: PendingIntent.CanceledException) {
- Log.d(TAG, "Intent canceled", e)
+ if (action.isAuthenticationRequired()) {
+ activityStarter.dismissKeyguardThenExecute ({
+ var result = sendPendingIntent(action.actionIntent)
+ result
+ }, {}, true)
+ } else {
+ sendPendingIntent(action.actionIntent)
}
}
} else {
@@ -449,6 +455,15 @@ class MediaDataManager(
return null
}
+ private fun sendPendingIntent(intent: PendingIntent): Boolean {
+ return try {
+ intent.send()
+ true
+ } catch (e: PendingIntent.CanceledException) {
+ Log.d(TAG, "Intent canceled", e)
+ false
+ }
+ }
/**
* Load a bitmap from a URI
* @param uri the uri to load
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 01670285c0f4..f1c8b0cf0e42 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -186,20 +186,23 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
private class PipManagerPinnedStackListener extends PinnedStackListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
- if (mState == STATE_PIP) {
- if (mImeVisible != imeVisible) {
- if (imeVisible) {
- // Save the IME height adjustment, and offset to not occlude the IME
- mPipBounds.offset(0, -imeHeight);
- mImeHeightAdjustment = imeHeight;
- } else {
- // Apply the inverse adjustment when the IME is hidden
- mPipBounds.offset(0, mImeHeightAdjustment);
+ mHandler.post(() -> {
+ mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+ if (mState == STATE_PIP) {
+ if (mImeVisible != imeVisible) {
+ if (imeVisible) {
+ // Save the IME height adjustment, and offset to not occlude the IME
+ mPipBounds.offset(0, -imeHeight);
+ mImeHeightAdjustment = imeHeight;
+ } else {
+ // Apply the inverse adjustment when the IME is hidden
+ mPipBounds.offset(0, mImeHeightAdjustment);
+ }
+ mImeVisible = imeVisible;
+ resizePinnedStack(STATE_PIP);
}
- mImeVisible = imeVisible;
- resizePinnedStack(STATE_PIP);
}
- }
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 6b023c07b1a6..95867957f648 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -161,7 +161,9 @@ public class NotificationRemoteInputManager implements Dumpable {
ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
- return mCallback.handleRemoteViewClick(view, pendingIntent, () -> {
+ Notification.Action action = getActionFromView(view, entry, pendingIntent);
+ return mCallback.handleRemoteViewClick(view, pendingIntent,
+ action == null ? false : action.isAuthenticationRequired(), () -> {
Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view);
options.second.setLaunchWindowingMode(
WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
@@ -170,47 +172,56 @@ public class NotificationRemoteInputManager implements Dumpable {
});
}
- private void logActionClick(
- View view,
- NotificationEntry entry,
- PendingIntent actionIntent) {
+ private @Nullable Notification.Action getActionFromView(View view,
+ NotificationEntry entry, PendingIntent actionIntent) {
Integer actionIndex = (Integer)
view.getTag(com.android.internal.R.id.notification_action_index_tag);
if (actionIndex == null) {
- // Custom action button, not logging.
- return;
+ return null;
}
- ViewParent parent = view.getParent();
if (entry == null) {
Log.w(TAG, "Couldn't determine notification for click.");
- return;
- }
- StatusBarNotification statusBarNotification = entry.getSbn();
- String key = statusBarNotification.getKey();
- int buttonIndex = -1;
- // If this is a default template, determine the index of the button.
- if (view.getId() == com.android.internal.R.id.action0 &&
- parent != null && parent instanceof ViewGroup) {
- ViewGroup actionGroup = (ViewGroup) parent;
- buttonIndex = actionGroup.indexOfChild(view);
+ return null;
}
- final int count = mEntryManager.getActiveNotificationsCount();
- final int rank = mEntryManager
- .getActiveNotificationUnfiltered(key).getRanking().getRank();
// Notification may be updated before this function is executed, and thus play safe
// here and verify that the action object is still the one that where the click happens.
+ StatusBarNotification statusBarNotification = entry.getSbn();
Notification.Action[] actions = statusBarNotification.getNotification().actions;
if (actions == null || actionIndex >= actions.length) {
Log.w(TAG, "statusBarNotification.getNotification().actions is null or invalid");
- return;
+ return null ;
}
final Notification.Action action =
statusBarNotification.getNotification().actions[actionIndex];
if (!Objects.equals(action.actionIntent, actionIntent)) {
Log.w(TAG, "actionIntent does not match");
+ return null;
+ }
+ return action;
+ }
+
+ private void logActionClick(
+ View view,
+ NotificationEntry entry,
+ PendingIntent actionIntent) {
+ Notification.Action action = getActionFromView(view, entry, actionIntent);
+ if (action == null) {
return;
}
+ ViewParent parent = view.getParent();
+ String key = entry.getSbn().getKey();
+ int buttonIndex = -1;
+ // If this is a default template, determine the index of the button.
+ if (view.getId() == com.android.internal.R.id.action0 &&
+ parent != null && parent instanceof ViewGroup) {
+ ViewGroup actionGroup = (ViewGroup) parent;
+ buttonIndex = actionGroup.indexOfChild(view);
+ }
+ final int count = mEntryManager.getActiveNotificationsCount();
+ final int rank = mEntryManager
+ .getActiveNotificationUnfiltered(key).getRanking().getRank();
+
NotificationVisibility.NotificationLocation location =
NotificationLogger.getNotificationLocation(
mEntryManager.getActiveNotificationUnfiltered(key));
@@ -813,11 +824,12 @@ public class NotificationRemoteInputManager implements Dumpable {
*
* @param view
* @param pendingIntent
+ * @param appRequestedAuth
* @param defaultHandler
* @return true iff the click was handled
*/
boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
- ClickHandler defaultHandler);
+ boolean appRequestedAuth, ClickHandler defaultHandler);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 36f8bcdc9123..8f3033edecbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -44,7 +44,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
@@ -69,7 +69,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
private float mHiddenShelfIconSize;
private int mStatusBarHeight;
private AmbientState mAmbientState;
- private NotificationStackScrollLayout mHostLayout;
+ private NotificationStackScrollLayoutController mHostLayoutController;
private int mMaxLayoutHeight;
private int mPaddingBetweenElements;
private int mNotGoneIndex;
@@ -114,9 +114,10 @@ public class NotificationShelf extends ActivatableNotificationView implements
initDimens();
}
- public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) {
+ public void bind(AmbientState ambientState,
+ NotificationStackScrollLayoutController hostLayoutController) {
mAmbientState = ambientState;
- mHostLayout = hostLayout;
+ mHostLayoutController = hostLayoutController;
}
private void initDimens() {
@@ -248,8 +249,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
float firstElementRoundness = 0.0f;
ActivatableNotificationView previousAnv = null;
- for (int i = 0; i < mHostLayout.getChildCount(); i++) {
- ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
+ for (int i = 0; i < mHostLayoutController.getChildCount(); i++) {
+ ExpandableView child = (ExpandableView) mHostLayoutController.getChildAt(i);
if (!child.needsClippingToShelf() || child.getVisibility() == GONE) {
continue;
@@ -354,8 +355,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
mShelfIcons.setSpeedBumpIndex(mAmbientState.getSpeedBumpIndex());
mShelfIcons.calculateIconTranslations();
mShelfIcons.applyIconStates();
- for (int i = 0; i < mHostLayout.getChildCount(); i++) {
- View child = mHostLayout.getChildAt(i);
+ for (int i = 0; i < mHostLayoutController.getChildCount(); i++) {
+ View child = mHostLayoutController.getChildAt(i);
if (!(child instanceof ExpandableNotificationRow)
|| child.getVisibility() == GONE) {
continue;
@@ -378,8 +379,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
* swipes quickly.
*/
private void clipTransientViews() {
- for (int i = 0; i < mHostLayout.getTransientViewCount(); i++) {
- View transientView = mHostLayout.getTransientView(i);
+ for (int i = 0; i < mHostLayoutController.getTransientViewCount(); i++) {
+ View transientView = mHostLayoutController.getTransientView(i);
if (transientView instanceof ExpandableView) {
ExpandableView transientExpandableView = (ExpandableView) transientView;
updateNotificationClipHeight(transientExpandableView, getTranslationY(), -1);
@@ -618,7 +619,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
// We need to persist this, since after the expansion, the behavior should still be the
// same.
float position = mAmbientState.getIntrinsicPadding()
- + mHostLayout.getPositionInLinearLayout(view);
+ + mHostLayoutController.getPositionInLinearLayout(view);
int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight();
if (position < maxShelfStart && position + view.getIntrinsicHeight() >= maxShelfStart
&& view.getTranslationY() < position) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
index 9f8f8447d72c..77abcfa848ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java
@@ -21,7 +21,7 @@ import android.view.View;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
import com.android.systemui.statusbar.notification.stack.AmbientState;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.phone.StatusBarNotificationPresenter;
@@ -90,8 +90,8 @@ public class NotificationShelfController {
}
public void bind(AmbientState ambientState,
- NotificationStackScrollLayout notificationStackScrollLayout) {
- mView.bind(ambientState, notificationStackScrollLayout);
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
+ mView.bind(ambientState, notificationStackScrollLayoutController);
mAmbientState = ambientState;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 7b2585324b9f..ff13c4e90bba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -36,7 +36,7 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.ShadeController
@@ -93,7 +93,7 @@ constructor(
private set
private val mTouchSlop: Float
private lateinit var expansionCallback: ExpansionCallback
- private lateinit var stackScroller: NotificationStackScrollLayout
+ private lateinit var stackScrollerController: NotificationStackScrollLayoutController
private val mTemp2 = IntArray(2)
private var mDraggedFarEnough: Boolean = false
private var mStartingChild: ExpandableView? = null
@@ -315,23 +315,23 @@ constructor(
private fun findView(x: Float, y: Float): ExpandableView? {
var totalX = x
var totalY = y
- stackScroller.getLocationOnScreen(mTemp2)
+ stackScrollerController.getLocationOnScreen(mTemp2)
totalX += mTemp2[0].toFloat()
totalY += mTemp2[1].toFloat()
- val childAtRawPosition = stackScroller.getChildAtRawPosition(totalX, totalY)
+ val childAtRawPosition = stackScrollerController.getChildAtRawPosition(totalX, totalY)
return if (childAtRawPosition != null && childAtRawPosition.isContentExpandable) {
childAtRawPosition
} else null
}
fun setUp(
- stackScroller: NotificationStackScrollLayout,
+ stackScrollerController: NotificationStackScrollLayoutController,
expansionCallback: ExpansionCallback,
shadeController: ShadeController
) {
this.expansionCallback = expansionCallback
this.shadeController = shadeController
- this.stackScroller = stackScroller
+ this.stackScrollerController = stackScrollerController
}
fun setPulsing(pulsing: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index f982cf05de97..0469176255c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -22,7 +22,7 @@ import com.android.systemui.Interpolators
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.collection.NotificationEntry
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.KeyguardBypassController
@@ -33,6 +33,7 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import javax.inject.Inject
import javax.inject.Singleton
+import kotlin.math.min
@Singleton
class NotificationWakeUpCoordinator @Inject constructor(
@@ -53,7 +54,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
return coordinator.mLinearVisibilityAmount
}
}
- private lateinit var mStackScroller: NotificationStackScrollLayout
+ private lateinit var mStackScrollerController: NotificationStackScrollLayoutController
private var mVisibilityInterpolator = Interpolators.FAST_OUT_SLOW_IN_REVERSE
private var mLinearDozeAmount: Float = 0.0f
@@ -79,7 +80,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
if (mNotificationsVisible && !mNotificationsVisibleForExpansion &&
!bypassController.bypassEnabled) {
// We're waking up while pulsing, let's make sure the animation looks nice
- mStackScroller.wakeUpFromPulse()
+ mStackScrollerController.wakeUpFromPulse()
}
if (bypassController.bypassEnabled && !mNotificationsVisible) {
// Let's make sure our huns become visible once we are waking up in case
@@ -156,10 +157,10 @@ class NotificationWakeUpCoordinator @Inject constructor(
})
}
- fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
- mStackScroller = stackScroller
- pulseExpanding = stackScroller.isPulseExpanding
- stackScroller.setOnPulseHeightChangedListener {
+ fun setStackScroller(stackScrollerController: NotificationStackScrollLayoutController) {
+ mStackScrollerController = stackScrollerController
+ pulseExpanding = stackScrollerController.isPulseExpanding
+ stackScrollerController.setOnPulseHeightChangedListener {
val nowExpanding = isPulseExpanding()
val changed = nowExpanding != pulseExpanding
pulseExpanding = nowExpanding
@@ -169,7 +170,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
}
}
- fun isPulseExpanding(): Boolean = mStackScroller.isPulseExpanding
+ fun isPulseExpanding(): Boolean = mStackScrollerController.isPulseExpanding
/**
* @param visible should notifications be visible
@@ -249,7 +250,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
val changed = linear != mLinearDozeAmount
mLinearDozeAmount = linear
mDozeAmount = eased
- mStackScroller.setDozeAmount(mDozeAmount)
+ mStackScrollerController.setDozeAmount(mDozeAmount)
updateHideAmount()
if (changed && linear == 0.0f) {
setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
@@ -330,18 +331,18 @@ class NotificationWakeUpCoordinator @Inject constructor(
}
fun getWakeUpHeight(): Float {
- return mStackScroller.wakeUpHeight
+ return mStackScrollerController.wakeUpHeight
}
private fun updateHideAmount() {
- val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
- val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount)
- mStackScroller.setHideAmount(linearAmount, amount)
+ val linearAmount = min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
+ val amount = min(1.0f - mVisibilityAmount, mDozeAmount)
+ mStackScrollerController.setHideAmount(linearAmount, amount)
notificationsFullyHidden = linearAmount == 1.0f
}
private fun notifyAnimationStart(awake: Boolean) {
- mStackScroller.notifyHideAnimationStart(!awake)
+ mStackScrollerController.notifyHideAnimationStart(!awake)
}
override fun onDozingChanged(isDozing: Boolean) {
@@ -355,7 +356,7 @@ class NotificationWakeUpCoordinator @Inject constructor(
* from a pulse and determines how much the notifications are expanded.
*/
fun setPulseHeight(height: Float): Float {
- val overflow = mStackScroller.setPulseHeight(height)
+ val overflow = mStackScrollerController.setPulseHeight(height)
// no overflow for the bypass experience
return if (bypassController.bypassEnabled) 0.0f else overflow
}
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 57c1a16a259d..2ff67abd6377 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
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.stack;
import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
import static com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.ANCHOR_SCROLLING;
@@ -210,7 +209,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private final Paint mBackgroundPaint = new Paint();
private final boolean mShouldDrawNotificationBackground;
private boolean mHighPriorityBeforeSpeedBump;
- private final boolean mAllowLongPress;
private boolean mDismissRtl;
private float mExpandedHeight;
@@ -539,6 +537,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private int mGapHeight;
private int mWaterfallTopInset;
+ private NotificationStackScrollLayoutController mController;
private SysuiColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
(colorExtractor, which) -> {
@@ -550,7 +549,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public NotificationStackScrollLayout(
@Named(VIEW_CONTEXT) Context context,
AttributeSet attrs,
- @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
NotificationRoundnessManager notificationRoundnessManager,
DynamicPrivacyController dynamicPrivacyController,
SysuiStatusBarStateController statusBarStateController,
@@ -573,8 +571,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
super(context, attrs, 0, 0);
Resources res = getResources();
- mAllowLongPress = allowLongPress;
-
mRoundnessManager = notificationRoundnessManager;
mLockscreenUserManager = notificationLockscreenUserManager;
@@ -715,9 +711,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
inflateEmptyShadeView();
inflateFooterView();
mVisualStabilityManager.setVisibilityLocationProvider(this::isInVisibleLocation);
- if (mAllowLongPress) {
- setLongPressListener(mNotificationGutsManager::openGuts);
- }
}
/**
@@ -5430,7 +5423,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
addView(mShelf, index);
mAmbientState.setShelf(mShelf);
mStateAnimator.setShelf(mShelf);
- notificationShelfController.bind(mAmbientState, this);
+ notificationShelfController.bind(mAmbientState, mController);
if (ANCHOR_SCROLLING) {
mScrollAnchorView = mShelf;
}
@@ -5904,6 +5897,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return MathUtils.smoothStep(0, totalDistance, dragDownAmount);
}
+ public void setController(
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
+ mController = notificationStackScrollLayoutController;
+ }
+
+ public NotificationStackScrollLayoutController getController() {
+ return mController;
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
new file mode 100644
index 000000000000..8150593e69fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2020 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.systemui.statusbar.notification.stack;
+
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+
+import android.graphics.PointF;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+
+import com.android.systemui.statusbar.NotificationShelfController;
+import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
+import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+
+import java.util.function.BiConsumer;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Controller for {@link NotificationStackScrollLayout}.
+ */
+@StatusBarComponent.StatusBarScope
+public class NotificationStackScrollLayoutController {
+ private final boolean mAllowLongPress;
+ private final NotificationGutsManager mNotificationGutsManager;
+ private NotificationStackScrollLayout mView;
+
+ @Inject
+ public NotificationStackScrollLayoutController(
+ @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
+ NotificationGutsManager notificationGutsManager) {
+ mAllowLongPress = allowLongPress;
+ mNotificationGutsManager = notificationGutsManager;
+ }
+
+ public void attach(NotificationStackScrollLayout view) {
+ mView = view;
+ mView.setController(this);
+
+ if (mAllowLongPress) {
+ mView.setLongPressListener(mNotificationGutsManager::openGuts);
+ }
+ }
+
+ public void addOnExpandedHeightChangedListener(BiConsumer<Float, Float> listener) {
+ mView.addOnExpandedHeightChangedListener(listener);
+ }
+
+ public void removeOnExpandedHeightChangedListener(BiConsumer<Float, Float> listener) {
+ mView.removeOnExpandedHeightChangedListener(listener);
+ }
+
+ public void addOnLayoutChangeListener(View.OnLayoutChangeListener listener) {
+ mView.addOnLayoutChangeListener(listener);
+ }
+
+ public void removeOnLayoutChangeListener(View.OnLayoutChangeListener listener) {
+ mView.removeOnLayoutChangeListener(listener);
+ }
+
+ public void setHeadsUpAppearanceController(HeadsUpAppearanceController controller) {
+ mView.setHeadsUpAppearanceController(controller);
+ }
+
+ public void requestLayout() {
+ mView.requestLayout();
+ }
+
+ public Display getDisplay() {
+ return mView.getDisplay();
+ }
+
+ public WindowInsets getRootWindowInsets() {
+ return mView.getRootWindowInsets();
+ }
+
+ public int getRight() {
+ return mView.getRight();
+ }
+
+ public boolean isLayoutRtl() {
+ return mView.isLayoutRtl();
+ }
+
+ public float getLeft() {
+ return mView.getLeft();
+ }
+
+ public float getTranslationX() {
+ return mView.getTranslationX();
+ }
+
+ public void setOnHeightChangedListener(
+ ExpandableView.OnHeightChangedListener listener) {
+ mView.setOnHeightChangedListener(listener);
+ }
+
+ public void setOverscrollTopChangedListener(
+ NotificationStackScrollLayout.OnOverscrollTopChangedListener listener) {
+ mView.setOverscrollTopChangedListener(listener);
+ }
+
+ public void setOnEmptySpaceClickListener(
+ NotificationStackScrollLayout.OnEmptySpaceClickListener listener) {
+ mView.setOnEmptySpaceClickListener(listener);
+ }
+
+ public void setTrackingHeadsUp(ExpandableNotificationRow expandableNotificationRow) {
+ mView.setTrackingHeadsUp(expandableNotificationRow);
+ }
+
+ public void wakeUpFromPulse() {
+ mView.wakeUpFromPulse();
+ }
+
+ public boolean isPulseExpanding() {
+ return mView.isPulseExpanding();
+ }
+
+ public void setOnPulseHeightChangedListener(Runnable listener) {
+ mView.setOnPulseHeightChangedListener(listener);
+ }
+
+ public void setDozeAmount(float amount) {
+ mView.setDozeAmount(amount);
+ }
+
+ public float getWakeUpHeight() {
+ return mView.getWakeUpHeight();
+ }
+
+ public void setHideAmount(float linearAmount, float amount) {
+ mView.setHideAmount(linearAmount, amount);
+ }
+
+ public void notifyHideAnimationStart(boolean hide) {
+ mView.notifyHideAnimationStart(hide);
+ }
+
+ public float setPulseHeight(float height) {
+ return mView.setPulseHeight(height);
+ }
+
+ public void getLocationOnScreen(int[] outLocation) {
+ mView.getLocationOnScreen(outLocation);
+ }
+
+ public ExpandableView getChildAtRawPosition(float x, float y) {
+ return mView.getChildAtRawPosition(x, y);
+ }
+
+ public FrameLayout.LayoutParams getLayoutParams() {
+ return (FrameLayout.LayoutParams) mView.getLayoutParams();
+ }
+
+ public void setLayoutParams(FrameLayout.LayoutParams lp) {
+ mView.setLayoutParams(lp);
+ }
+
+ public void setIsFullWidth(boolean isFullWidth) {
+ mView.setIsFullWidth(isFullWidth);
+ }
+
+ public boolean isAddOrRemoveAnimationPending() {
+ return mView.isAddOrRemoveAnimationPending();
+ }
+
+ public int getVisibleNotificationCount() {
+ return mView.getVisibleNotificationCount();
+ }
+
+ public int getIntrinsicContentHeight() {
+ return mView.getIntrinsicContentHeight();
+ }
+
+ public void setIntrinsicPadding(int intrinsicPadding) {
+ mView.setIntrinsicPadding(intrinsicPadding);
+ }
+
+ public int getHeight() {
+ return mView.getHeight();
+ }
+
+ public int getChildCount() {
+ return mView.getChildCount();
+ }
+
+ public ExpandableView getChildAt(int i) {
+ return (ExpandableView) mView.getChildAt(i);
+ }
+
+ public void goToFullShade(long delay) {
+ mView.goToFullShade(delay);
+ }
+
+ public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
+ boolean cancelAnimators) {
+ mView.setOverScrollAmount(amount, onTop, animate, cancelAnimators);
+ }
+
+ public void setOverScrollAmount(float amount, boolean onTop, boolean animate) {
+ mView.setOverScrollAmount(amount, onTop, animate);
+ }
+
+ public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
+ mView.setOverScrolledPixels(numPixels, onTop, animate);
+ }
+
+ public void resetScrollPosition() {
+ mView.resetScrollPosition();
+ }
+
+ public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
+ mView.setShouldShowShelfOnly(shouldShowShelfOnly);
+ }
+
+ public void cancelLongPress() {
+ mView.cancelLongPress();
+ }
+
+ public float getX() {
+ return mView.getX();
+ }
+
+ public boolean isBelowLastNotification(float x, float y) {
+ return mView.isBelowLastNotification(x, y);
+ }
+
+ public float getWidth() {
+ return mView.getWidth();
+ }
+
+ public float getOpeningHeight() {
+ return mView.getOpeningHeight();
+ }
+
+ public float getBottomMostNotificationBottom() {
+ return mView.getBottomMostNotificationBottom();
+ }
+
+ public void checkSnoozeLeavebehind() {
+ mView.checkSnoozeLeavebehind();
+ }
+
+ public void setQsExpanded(boolean expanded) {
+ mView.setQsExpanded(expanded);
+ }
+
+ public void setScrollingEnabled(boolean enabled) {
+ mView.setScrollingEnabled(enabled);
+ }
+
+ public void setQsExpansionFraction(float expansionFraction) {
+ mView.setQsExpansionFraction(expansionFraction);
+ }
+
+ public float calculateAppearFractionBypass() {
+ return mView.calculateAppearFractionBypass();
+ }
+
+ public void updateTopPadding(float qsHeight, boolean animate) {
+ mView.updateTopPadding(qsHeight, animate);
+ }
+
+ public void resetCheckSnoozeLeavebehind() {
+ mView.resetCheckSnoozeLeavebehind();
+ }
+
+ public boolean isScrolledToBottom() {
+ return mView.isScrolledToBottom();
+ }
+
+ public int getNotGoneChildCount() {
+ return mView.getNotGoneChildCount();
+ }
+
+ public float getIntrinsicPadding() {
+ return mView.getIntrinsicPadding();
+ }
+
+ public float getLayoutMinHeight() {
+ return mView.getLayoutMinHeight();
+ }
+
+ public int getEmptyBottomMargin() {
+ return mView.getEmptyBottomMargin();
+ }
+
+ public float getTopPaddingOverflow() {
+ return mView.getTopPaddingOverflow();
+ }
+
+ public int getTopPadding() {
+ return mView.getTopPadding();
+ }
+
+ public float getEmptyShadeViewHeight() {
+ return mView.getEmptyShadeViewHeight();
+ }
+
+ public void setAlpha(float alpha) {
+ mView.setAlpha(alpha);
+ }
+
+ public float getCurrentOverScrollAmount(boolean top) {
+ return mView.getCurrentOverScrollAmount(top);
+ }
+
+ public float getCurrentOverScrolledPixels(boolean top) {
+ return mView.getCurrentOverScrolledPixels(top);
+ }
+
+ public float calculateAppearFraction(float height) {
+ return mView.calculateAppearFraction(height);
+ }
+
+ public void onExpansionStarted() {
+ mView.onExpansionStarted();
+ }
+
+ public void onExpansionStopped() {
+ mView.onExpansionStopped();
+ }
+
+ public void onPanelTrackingStarted() {
+ mView.onPanelTrackingStarted();
+ }
+
+ public void onPanelTrackingStopped() {
+ mView.onPanelTrackingStopped();
+ }
+
+ public void setHeadsUpBoundaries(int height, int bottomBarHeight) {
+ mView.setHeadsUpBoundaries(height, bottomBarHeight);
+ }
+
+ public void setUnlockHintRunning(boolean running) {
+ mView.setUnlockHintRunning(running);
+ }
+
+ public float getPeekHeight() {
+ return mView.getPeekHeight();
+ }
+
+ public boolean isFooterViewNotGone() {
+ return mView.isFooterViewNotGone();
+ }
+
+ public boolean isFooterViewContentVisible() {
+ return mView.isFooterViewContentVisible();
+ }
+
+ public int getFooterViewHeightWithPadding() {
+ return mView.getFooterViewHeightWithPadding();
+ }
+
+ public void updateEmptyShadeView(boolean visible) {
+ mView.updateEmptyShadeView(visible);
+ }
+
+ public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+ mView.setHeadsUpAnimatingAway(headsUpAnimatingAway);
+ }
+
+ public HeadsUpTouchHelper.Callback getHeadsUpCallback() {
+ return mView.getHeadsUpCallback();
+ }
+
+ public void forceNoOverlappingRendering(boolean force) {
+ mView.forceNoOverlappingRendering(force);
+ }
+
+ public void setTranslationX(float translation) {
+ mView.setTranslationX(translation);
+ }
+
+ public void setExpandingVelocity(float velocity) {
+ mView.setExpandingVelocity(velocity);
+ }
+
+ public void setExpandedHeight(float expandedHeight) {
+ mView.setExpandedHeight(expandedHeight);
+ }
+
+ public void setQsContainer(ViewGroup view) {
+ mView.setQsContainer(view);
+ }
+
+ public void setAnimationsEnabled(boolean enabled) {
+ mView.setAnimationsEnabled(enabled);
+ }
+
+ public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation) {
+ mView.setDozing(dozing, animate, wakeUpTouchLocation);
+ }
+
+ public void setPulsing(boolean pulsing, boolean animatePulse) {
+ mView.setPulsing(pulsing, animatePulse);
+ }
+
+ public boolean hasActiveClearableNotifications(
+ @NotificationStackScrollLayout.SelectedRows int selection) {
+ return mView.hasActiveClearableNotifications(selection);
+ }
+
+ public RemoteInputController.Delegate createDelegate() {
+ return mView.createDelegate();
+ }
+
+ public void updateSectionBoundaries(String reason) {
+ mView.updateSectionBoundaries(reason);
+ }
+
+ public void updateSpeedBumpIndex() {
+ mView.updateSpeedBumpIndex();
+ }
+
+ public void updateFooter() {
+ mView.updateFooter();
+ }
+
+ public void updateIconAreaViews() {
+ mView.updateIconAreaViews();
+ }
+
+ public void onUpdateRowStates() {
+ mView.onUpdateRowStates();
+ }
+
+ public boolean hasPulsingNotifications() {
+ return mView.hasPulsingNotifications();
+ }
+
+ public ActivatableNotificationView getActivatedChild() {
+ return mView.getActivatedChild();
+ }
+
+ public void setActivatedChild(ActivatableNotificationView view) {
+ mView.setActivatedChild(view);
+ }
+
+ public void runAfterAnimationFinished(Runnable r) {
+ mView.runAfterAnimationFinished(r);
+ }
+
+ public void setNotificationPanelController(
+ NotificationPanelViewController notificationPanelViewController) {
+ mView.setNotificationPanelController(notificationPanelViewController);
+ }
+
+ public void setIconAreaController(NotificationIconAreaController controller) {
+ mView.setIconAreaController(controller);
+ }
+
+ public void setStatusBar(StatusBar statusBar) {
+ mView.setStatusBar(statusBar);
+ }
+
+ public void setGroupManager(NotificationGroupManager groupManager) {
+ mView.setGroupManager(groupManager);
+ }
+
+ public void setShelfController(NotificationShelfController notificationShelfController) {
+ mView.setShelfController(notificationShelfController);
+ }
+
+ public void setScrimController(ScrimController scrimController) {
+ mView.setScrimController(scrimController);
+ }
+
+ public ExpandableView getFirstChildNotGone() {
+ return mView.getFirstChildNotGone();
+ }
+
+ public void setInHeadsUpPinnedMode(boolean inPinnedMode) {
+ mView.setInHeadsUpPinnedMode(inPinnedMode);
+ }
+
+ public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
+ mView.generateHeadsUpAnimation(entry, isHeadsUp);
+ }
+
+ public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
+ mView.generateHeadsUpAnimation(row, isHeadsUp);
+ }
+
+ public void setMaxTopPadding(int padding) {
+ mView.setMaxTopPadding(padding);
+ }
+
+ public int getTransientViewCount() {
+ return mView.getTransientViewCount();
+ }
+
+ public View getTransientView(int i) {
+ return mView.getTransientView(i);
+ }
+
+ public int getPositionInLinearLayout(ExpandableView row) {
+ return mView.getPositionInLinearLayout(row);
+ }
+
+ public NotificationStackScrollLayout getView() {
+ return mView;
+ }
+
+ public float calculateGapHeight(ExpandableView previousView, ExpandableView child, int count) {
+ return mView.calculateGapHeight(previousView, child, count);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 51c02c9f93ab..8cdaa63994e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -36,7 +36,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -52,7 +52,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
public static final int CONTENT_FADE_DELAY = 100;
private final NotificationIconAreaController mNotificationIconAreaController;
private final HeadsUpManagerPhone mHeadsUpManager;
- private final NotificationStackScrollLayout mStackScroller;
+ private final NotificationStackScrollLayoutController mStackScrollerController;
private final HeadsUpStatusBarView mHeadsUpStatusBarView;
private final View mCenteredIconView;
private final View mClockView;
@@ -93,7 +93,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
public HeadsUpAppearanceController(
NotificationIconAreaController notificationIconAreaController,
HeadsUpManagerPhone headsUpManager,
- View notificationShadeView,
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController,
SysuiStatusBarStateController statusBarStateController,
KeyguardBypassController keyguardBypassController,
KeyguardStateController keyguardStateController,
@@ -101,10 +101,9 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
NotificationPanelViewController notificationPanelViewController, View statusBarView) {
this(notificationIconAreaController, headsUpManager, statusBarStateController,
keyguardBypassController, wakeUpCoordinator, keyguardStateController,
- commandQueue,
- statusBarView.findViewById(R.id.heads_up_status_bar_view),
- notificationShadeView.findViewById(R.id.notification_stack_scroller),
+ commandQueue, notificationStackScrollLayoutController,
notificationPanelViewController,
+ statusBarView.findViewById(R.id.heads_up_status_bar_view),
statusBarView.findViewById(R.id.clock),
statusBarView.findViewById(R.id.operator_name_frame),
statusBarView.findViewById(R.id.centered_icon_area));
@@ -119,9 +118,9 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
NotificationWakeUpCoordinator wakeUpCoordinator,
KeyguardStateController keyguardStateController,
CommandQueue commandQueue,
- HeadsUpStatusBarView headsUpStatusBarView,
- NotificationStackScrollLayout stackScroller,
+ NotificationStackScrollLayoutController stackScrollerController,
NotificationPanelViewController notificationPanelViewController,
+ HeadsUpStatusBarView headsUpStatusBarView,
View clockView,
View operatorNameView,
View centeredIconView) {
@@ -132,14 +131,14 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mCenteredIconView = centeredIconView;
headsUpStatusBarView.setOnDrawingRectChangedListener(
() -> updateIsolatedIconLocation(true /* requireUpdate */));
- mStackScroller = stackScroller;
+ mStackScrollerController = stackScrollerController;
mNotificationPanelViewController = notificationPanelViewController;
notificationPanelViewController.addTrackingHeadsUpListener(mSetTrackingHeadsUp);
notificationPanelViewController.addVerticalTranslationListener(mUpdatePanelTranslation);
notificationPanelViewController.setHeadsUpAppearanceController(this);
- mStackScroller.addOnExpandedHeightChangedListener(mSetExpandedHeight);
- mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
- mStackScroller.setHeadsUpAppearanceController(this);
+ mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight);
+ mStackScrollerController.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
+ mStackScrollerController.setHeadsUpAppearanceController(this);
mClockView = clockView;
mOperatorNameView = operatorNameView;
mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
@@ -153,7 +152,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
updateTopEntry();
// trigger scroller to notify the latest panel translation
- mStackScroller.requestLayout();
+ mStackScrollerController.requestLayout();
}
mHeadsUpStatusBarView.removeOnLayoutChangeListener(this);
}
@@ -174,8 +173,8 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mNotificationPanelViewController.removeTrackingHeadsUpListener(mSetTrackingHeadsUp);
mNotificationPanelViewController.removeVerticalTranslationListener(mUpdatePanelTranslation);
mNotificationPanelViewController.setHeadsUpAppearanceController(null);
- mStackScroller.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
- mStackScroller.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener);
+ mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
+ mStackScrollerController.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener);
mDarkIconDispatcher.removeDarkReceiver(this);
}
@@ -219,12 +218,12 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
}
int realDisplaySize = 0;
- if (mStackScroller.getDisplay() != null) {
- mStackScroller.getDisplay().getRealSize(mPoint);
+ if (mStackScrollerController.getDisplay() != null) {
+ mStackScrollerController.getDisplay().getRealSize(mPoint);
realDisplaySize = mPoint.x;
}
- WindowInsets windowInset = mStackScroller.getRootWindowInsets();
+ WindowInsets windowInset = mStackScrollerController.getRootWindowInsets();
DisplayCutout cutout = (windowInset != null) ? windowInset.getDisplayCutout() : null;
int sysWinLeft = (windowInset != null) ? windowInset.getStableInsetLeft() : 0;
int sysWinRight = (windowInset != null) ? windowInset.getStableInsetRight() : 0;
@@ -233,17 +232,17 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
int leftInset = Math.max(sysWinLeft, cutoutLeft);
int rightInset = Math.max(sysWinRight, cutoutRight);
- return leftInset + mStackScroller.getRight() + rightInset - realDisplaySize;
+ return leftInset + mStackScrollerController.getRight() + rightInset - realDisplaySize;
}
public void updatePanelTranslation() {
float newTranslation;
- if (mStackScroller.isLayoutRtl()) {
+ if (mStackScrollerController.isLayoutRtl()) {
newTranslation = getRtlTranslation();
} else {
- newTranslation = mStackScroller.getLeft();
+ newTranslation = mStackScrollerController.getLeft();
}
- newTranslation += mStackScroller.getTranslationX();
+ newTranslation += mStackScrollerController.getTranslationX();
mHeadsUpStatusBarView.setPanelTranslation(newTranslation);
}
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 6946346eee2f..70fb71a1d2f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -106,6 +106,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -175,6 +176,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final ZenModeController mZenModeController;
private final ConfigurationController mConfigurationController;
private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
+ private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
// Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
// changed.
@@ -265,7 +267,6 @@ public class NotificationPanelViewController extends PanelViewController {
private KeyguardStatusView mKeyguardStatusView;
private View mQsNavbarScrim;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
- private NotificationStackScrollLayout mNotificationStackScroller;
private boolean mAnimateNextPositionUpdate;
private int mTrackingPointer;
@@ -500,7 +501,8 @@ public class NotificationPanelViewController extends PanelViewController {
MediaHierarchyManager mediaHierarchyManager,
BiometricUnlockController biometricUnlockController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider) {
+ Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider,
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -513,6 +515,7 @@ public class NotificationPanelViewController extends PanelViewController {
mMediaHierarchyManager = mediaHierarchyManager;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider;
+ mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
@@ -592,21 +595,26 @@ public class NotificationPanelViewController extends PanelViewController {
keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
- mNotificationStackScroller = mView.findViewById(R.id.notification_stack_scroller);
- mNotificationStackScroller.setOnHeightChangedListener(mOnHeightChangedListener);
- mNotificationStackScroller.setOverscrollTopChangedListener(mOnOverscrollTopChangedListener);
- mNotificationStackScroller.setOnEmptySpaceClickListener(mOnEmptySpaceClickListener);
- addTrackingHeadsUpListener(mNotificationStackScroller::setTrackingHeadsUp);
+ NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
+ R.id.notification_stack_scroller);
+ mNotificationStackScrollLayoutController.attach(stackScrollLayout);
+ mNotificationStackScrollLayoutController.setOnHeightChangedListener(
+ mOnHeightChangedListener);
+ mNotificationStackScrollLayoutController.setOverscrollTopChangedListener(
+ mOnOverscrollTopChangedListener);
+ mNotificationStackScrollLayoutController.setOnEmptySpaceClickListener(
+ mOnEmptySpaceClickListener);
+ addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp);
mKeyguardBottomArea = mView.findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = mView.findViewById(R.id.qs_navbar_scrim);
mLastOrientation = mResources.getConfiguration().orientation;
initBottomArea();
- mWakeUpCoordinator.setStackScroller(mNotificationStackScroller);
+ mWakeUpCoordinator.setStackScroller(mNotificationStackScrollLayoutController);
mQsFrame = mView.findViewById(R.id.qs_frame);
mPulseExpansionHandler.setUp(
- mNotificationStackScroller, mExpansionCallback, mShadeController);
+ mNotificationStackScrollLayoutController, mExpansionCallback, mShadeController);
mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
@@ -690,11 +698,11 @@ public class NotificationPanelViewController extends PanelViewController {
}
int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
- lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
+ lp = mNotificationStackScrollLayoutController.getLayoutParams();
if (lp.width != panelWidth || lp.gravity != panelGravity) {
lp.width = panelWidth;
lp.gravity = panelGravity;
- mNotificationStackScroller.setLayoutParams(lp);
+ mNotificationStackScrollLayoutController.setLayoutParams(lp);
}
}
@@ -772,7 +780,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void setIsFullWidth(boolean isFullWidth) {
mIsFullWidth = isFullWidth;
- mNotificationStackScroller.setIsFullWidth(isFullWidth);
+ mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth);
}
private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
@@ -806,7 +814,7 @@ public class NotificationPanelViewController extends PanelViewController {
* showing.
*/
private void positionClockAndNotifications() {
- boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
+ boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = animate || mAnimateNextPositionUpdate;
int stackScrollerPadding;
if (mBarState != StatusBarState.KEYGUARD) {
@@ -816,12 +824,12 @@ public class NotificationPanelViewController extends PanelViewController {
int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
int clockPreferredY = mKeyguardStatusView.getClockPreferredY(totalHeight);
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
- final boolean
- hasVisibleNotifications =
- !bypassEnabled && mNotificationStackScroller.getVisibleNotificationCount() != 0;
+ final boolean hasVisibleNotifications = !bypassEnabled
+ && mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0;
mKeyguardStatusView.setHasVisibleNotifications(hasVisibleNotifications);
mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding,
- mNotificationStackScroller.getIntrinsicContentHeight(), getExpandedFraction(),
+ mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
+ getExpandedFraction(),
totalHeight, (int) (mKeyguardStatusView.getHeight() - mShelfHeight / 2.0f
- mDarkIconSize / 2.0f), clockPreferredY, hasCustomClock(),
hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
@@ -835,7 +843,7 @@ public class NotificationPanelViewController extends PanelViewController {
updateClock();
stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded;
}
- mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
+ mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding);
mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
mStackScrollerMeasuringPass++;
@@ -867,29 +875,44 @@ public class NotificationPanelViewController extends PanelViewController {
: shelf.getIntrinsicHeight() + notificationPadding;
float
availableSpace =
- mNotificationStackScroller.getHeight() - minPadding - shelfSize - Math.max(
- mIndicationBottomPadding, mAmbientIndicationBottomPadding)
+ mNotificationStackScrollLayoutController.getHeight() - minPadding - shelfSize
+ - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
- mKeyguardStatusView.getLogoutButtonHeight();
int count = 0;
ExpandableView previousView = null;
- for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) {
- ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i);
+ for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) {
+ ExpandableView child = mNotificationStackScrollLayoutController.getChildAt(i);
+ if (!(child instanceof ExpandableNotificationRow)) {
+ continue;
+ }
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ boolean
+ suppressedSummary =
+ mGroupManager != null && mGroupManager.isSummaryOfSuppressedGroup(
+ row.getEntry().getSbn());
+ if (suppressedSummary) {
+ continue;
+ }
if (!canShowViewOnLockscreen(child)) {
continue;
}
+ if (row.isRemoved()) {
+ continue;
+ }
availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */);
availableSpace -= count == 0 ? 0 : notificationPadding;
- availableSpace -= mNotificationStackScroller.calculateGapHeight(previousView, child,
- count);
+ availableSpace -= mNotificationStackScrollLayoutController
+ .calculateGapHeight(previousView, child, count);
previousView = child;
if (availableSpace >= 0 && count < maximum) {
count++;
} else if (availableSpace > -shelfSize) {
// if we are exactly the last view, then we can show us still!
- for (int j = i + 1; j < mNotificationStackScroller.getChildCount(); j++) {
- ExpandableView view = (ExpandableView) mNotificationStackScroller.getChildAt(j);
- if (view instanceof ExpandableNotificationRow &&
- canShowViewOnLockscreen(view)) {
+ int childCount = mNotificationStackScrollLayoutController.getChildCount();
+ for (int j = i + 1; j < childCount; j++) {
+ ExpandableView view = mNotificationStackScrollLayoutController.getChildAt(j);
+ if (view instanceof ExpandableNotificationRow
+ && canShowViewOnLockscreen(view)) {
return count;
}
}
@@ -954,7 +977,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
public void animateToFullShade(long delay) {
- mNotificationStackScroller.goToFullShade(delay);
+ mNotificationStackScrollLayoutController.goToFullShade(delay);
mView.requestLayout();
mAnimateNextPositionUpdate = true;
}
@@ -980,9 +1003,9 @@ public class NotificationPanelViewController extends PanelViewController {
} else {
closeQs();
}
- mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, animate,
+ mNotificationStackScrollLayoutController.setOverScrollAmount(0f, true /* onTop */, animate,
!animate /* cancelAnimators */);
- mNotificationStackScroller.resetScrollPosition();
+ mNotificationStackScrollLayoutController.resetScrollPosition();
}
@Override
@@ -993,7 +1016,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (mQsExpanded) {
mQsExpandImmediate = true;
- mNotificationStackScroller.setShouldShowShelfOnly(true);
+ mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
}
super.collapse(delayed, speedUpFactor);
}
@@ -1029,7 +1052,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void expandWithQs() {
if (mQsExpansionEnabled) {
mQsExpandImmediate = true;
- mNotificationStackScroller.setShouldShowShelfOnly(true);
+ mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
}
if (isFullyCollapsed()) {
expand(true /* animate */);
@@ -1090,7 +1113,7 @@ public class NotificationPanelViewController extends PanelViewController {
onQsExpansionStarted();
mInitialHeightOnTouch = mQsExpansionHeight;
mQsTracking = true;
- mNotificationStackScroller.cancelLongPress();
+ mNotificationStackScrollLayoutController.cancelLongPress();
}
break;
case MotionEvent.ACTION_POINTER_UP:
@@ -1126,7 +1149,7 @@ public class NotificationPanelViewController extends PanelViewController {
mInitialHeightOnTouch = mQsExpansionHeight;
mInitialTouchY = y;
mInitialTouchX = x;
- mNotificationStackScroller.cancelLongPress();
+ mNotificationStackScrollLayoutController.cancelLongPress();
return true;
}
break;
@@ -1146,9 +1169,11 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected boolean isInContentBounds(float x, float y) {
- float stackScrollerX = mNotificationStackScroller.getX();
- return !mNotificationStackScroller.isBelowLastNotification(x - stackScrollerX, y)
- && stackScrollerX < x && x < stackScrollerX + mNotificationStackScroller.getWidth();
+ float stackScrollerX = mNotificationStackScrollLayoutController.getX();
+ return !mNotificationStackScrollLayoutController
+ .isBelowLastNotification(x - stackScrollerX, y)
+ && stackScrollerX < x
+ && x < stackScrollerX + mNotificationStackScrollLayoutController.getWidth();
}
private void initDownStates(MotionEvent event) {
@@ -1256,7 +1281,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected float getOpeningHeight() {
- return mNotificationStackScroller.getOpeningHeight();
+ return mNotificationStackScrollLayoutController.getOpeningHeight();
}
@@ -1292,7 +1317,7 @@ public class NotificationPanelViewController extends PanelViewController {
< mStatusBarMinHeight) {
mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
mQsExpandImmediate = true;
- mNotificationStackScroller.setShouldShowShelfOnly(true);
+ mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
requestPanelHeightUpdate();
// Normally, we start listening when the panel is expanded, but here we need to start
@@ -1304,7 +1329,7 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean isInQsArea(float x, float y) {
return (x >= mQsFrame.getX() && x <= mQsFrame.getX() + mQsFrame.getWidth()) && (
- y <= mNotificationStackScroller.getBottomMostNotificationBottom()
+ y <= mNotificationStackScrollLayoutController.getBottomMostNotificationBottom()
|| y <= mQs.getView().getY() + mQs.getView().getHeight());
}
@@ -1494,7 +1519,7 @@ public class NotificationPanelViewController extends PanelViewController {
float height = mQsExpansionHeight - overscrollAmount;
setQsExpansion(height);
requestPanelHeightUpdate();
- mNotificationStackScroller.checkSnoozeLeavebehind();
+ mNotificationStackScrollLayoutController.checkSnoozeLeavebehind();
// When expanding QS, let's authenticate the user if possible,
// this will speed up notification actions.
@@ -1667,8 +1692,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
private void updateQsState() {
- mNotificationStackScroller.setQsExpanded(mQsExpanded);
- mNotificationStackScroller.setScrollingEnabled(
+ mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded);
+ mNotificationStackScrollLayoutController.setScrollingEnabled(
mBarState != StatusBarState.KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
updateEmptyShadeView();
@@ -1728,7 +1753,7 @@ public class NotificationPanelViewController extends PanelViewController {
float qsExpansionFraction = getQsExpansionFraction();
mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
- mNotificationStackScroller.setQsExpansionFraction(qsExpansionFraction);
+ mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
}
private String determineAccessibilityPaneTitle() {
@@ -1787,18 +1812,18 @@ public class NotificationPanelViewController extends PanelViewController {
return mClockPositionResult.stackScrollerPadding;
}
int collapsedPosition = mHeadsUpInset;
- if (!mNotificationStackScroller.isPulseExpanding()) {
+ if (!mNotificationStackScrollLayoutController.isPulseExpanding()) {
return collapsedPosition;
} else {
int expandedPosition = mClockPositionResult.stackScrollerPadding;
return (int) MathUtils.lerp(collapsedPosition, expandedPosition,
- mNotificationStackScroller.calculateAppearFractionBypass());
+ mNotificationStackScrollLayoutController.calculateAppearFractionBypass());
}
}
protected void requestScrollerTopPaddingUpdate(boolean animate) {
- mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(), animate);
+ mNotificationStackScrollLayoutController.updateTopPadding(calculateQsTopPadding(), animate);
if (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()) {
// update the position of the header
updateQsExpansion();
@@ -1810,7 +1835,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (mQs != null) {
mQs.setShowCollapsedOnKeyguard(
mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()
- && mNotificationStackScroller.isPulseExpanding());
+ && mNotificationStackScrollLayoutController.isPulseExpanding());
}
}
@@ -1906,7 +1931,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void onAnimationEnd(Animator animation) {
mAnimatingQS = false;
notifyExpandingFinished();
- mNotificationStackScroller.resetCheckSnoozeLeavebehind();
+ mNotificationStackScrollLayoutController.resetCheckSnoozeLeavebehind();
mQsExpansionAnimator = null;
if (onFinishRunnable != null) {
onFinishRunnable.run();
@@ -1945,8 +1970,8 @@ public class NotificationPanelViewController extends PanelViewController {
protected boolean canCollapsePanelOnTouch() {
if (!isInSettings()) {
return mBarState == StatusBarState.KEYGUARD
- || mNotificationStackScroller.isScrolledToBottom()
- || mIsPanelCollapseOnQQS;
+ || mIsPanelCollapseOnQQS
+ || mNotificationStackScrollLayoutController.isScrolledToBottom();
} else {
return true;
}
@@ -1964,7 +1989,7 @@ public class NotificationPanelViewController extends PanelViewController {
private int getMaxPanelHeightNonBypass() {
int min = mStatusBarMinHeight;
if (!(mBarState == StatusBarState.KEYGUARD)
- && mNotificationStackScroller.getNotGoneChildCount() == 0) {
+ && mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
int minHeight = (int) (mQsMinExpansionHeight + getOverExpansionAmount());
min = Math.max(min, minHeight);
}
@@ -1990,7 +2015,7 @@ public class NotificationPanelViewController extends PanelViewController {
int position =
mClockPositionAlgorithm.getExpandedClockPosition()
+ mKeyguardStatusView.getHeight();
- if (mNotificationStackScroller.getVisibleNotificationCount() != 0) {
+ if (mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0) {
position += mShelfHeight / 2.0f + mDarkIconSize / 2.0f;
}
return position;
@@ -2029,8 +2054,8 @@ public class NotificationPanelViewController extends PanelViewController {
// minimum QS expansion + minStackHeight
float
panelHeightQsCollapsed =
- mNotificationStackScroller.getIntrinsicPadding()
- + mNotificationStackScroller.getLayoutMinHeight();
+ mNotificationStackScrollLayoutController.getIntrinsicPadding()
+ + mNotificationStackScrollLayoutController.getLayoutMinHeight();
float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
t =
(expandedHeight - panelHeightQsCollapsed) / (panelHeightQsExpanded
@@ -2062,16 +2087,16 @@ public class NotificationPanelViewController extends PanelViewController {
}
private int calculatePanelHeightShade() {
- int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
- int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin;
- maxHeight += mNotificationStackScroller.getTopPaddingOverflow();
+ int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin();
+ int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
+ maxHeight += mNotificationStackScrollLayoutController.getTopPaddingOverflow();
if (mBarState == StatusBarState.KEYGUARD) {
int
minKeyguardPanelBottom =
mClockPositionAlgorithm.getExpandedClockPosition()
+ mKeyguardStatusView.getHeight()
- + mNotificationStackScroller.getIntrinsicContentHeight();
+ + mNotificationStackScrollLayoutController.getIntrinsicContentHeight();
return Math.max(maxHeight, minKeyguardPanelBottom);
} else {
return maxHeight;
@@ -2081,15 +2106,16 @@ public class NotificationPanelViewController extends PanelViewController {
private int calculatePanelHeightQsExpanded() {
float
notificationHeight =
- mNotificationStackScroller.getHeight()
- - mNotificationStackScroller.getEmptyBottomMargin()
- - mNotificationStackScroller.getTopPadding();
+ mNotificationStackScrollLayoutController.getHeight()
+ - mNotificationStackScrollLayoutController.getEmptyBottomMargin()
+ - mNotificationStackScrollLayoutController.getTopPadding();
// When only empty shade view is visible in QS collapsed state, simulate that we would have
// it in expanded QS state as well so we don't run into troubles when fading the view in/out
// and expanding/collapsing the whole panel from/to quick settings.
- if (mNotificationStackScroller.getNotGoneChildCount() == 0 && mShowEmptyShadeView) {
- notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
+ if (mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0
+ && mShowEmptyShadeView) {
+ notificationHeight = mNotificationStackScrollLayoutController.getEmptyShadeViewHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
@@ -2104,12 +2130,13 @@ public class NotificationPanelViewController extends PanelViewController {
float totalHeight = Math.max(maxQsHeight,
mBarState == StatusBarState.KEYGUARD ? mClockPositionResult.stackScrollerPadding
: 0) + notificationHeight
- + mNotificationStackScroller.getTopPaddingOverflow();
- if (totalHeight > mNotificationStackScroller.getHeight()) {
+ + mNotificationStackScrollLayoutController.getTopPaddingOverflow();
+ if (totalHeight > mNotificationStackScrollLayoutController.getHeight()) {
float
fullyCollapsedHeight =
- maxQsHeight + mNotificationStackScroller.getLayoutMinHeight();
- totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
+ maxQsHeight + mNotificationStackScrollLayoutController.getLayoutMinHeight();
+ totalHeight = Math.max(fullyCollapsedHeight,
+ mNotificationStackScrollLayoutController.getHeight());
}
return (int) totalHeight;
}
@@ -2124,7 +2151,7 @@ public class NotificationPanelViewController extends PanelViewController {
&& !mKeyguardBypassController.getBypassEnabled()) {
alpha *= mClockPositionResult.clockAlpha;
}
- mNotificationStackScroller.setAlpha(alpha);
+ mNotificationStackScrollLayoutController.setAlpha(alpha);
}
private float getFadeoutAlpha() {
@@ -2140,7 +2167,8 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected float getOverExpansionAmount() {
- float result = mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */);
+ float result = mNotificationStackScrollLayoutController
+ .getCurrentOverScrollAmount(true /* top */);
if (isNaN(result)) {
Log.wtf(TAG, "OverExpansionAmount is NaN!");
}
@@ -2150,7 +2178,8 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected float getOverExpansionPixels() {
- return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */);
+ return mNotificationStackScrollLayoutController
+ .getCurrentOverScrolledPixels(true /* top */);
}
/**
@@ -2167,17 +2196,19 @@ public class NotificationPanelViewController extends PanelViewController {
if (mBarState == StatusBarState.KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
return -mQs.getQsMinExpansionHeight();
}
- float appearAmount = mNotificationStackScroller.calculateAppearFraction(mExpandedHeight);
+ float appearAmount = mNotificationStackScrollLayoutController
+ .calculateAppearFraction(mExpandedHeight);
float startHeight = -mQsExpansionHeight;
if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()
- && mNotificationStackScroller.isPulseExpanding()) {
+ && mNotificationStackScrollLayoutController.isPulseExpanding()) {
if (!mPulseExpansionHandler.isExpanding()
&& !mPulseExpansionHandler.getLeavingLockscreen()) {
// If we aborted the expansion we need to make sure the header doesn't reappear
// again after the header has animated away
appearAmount = 0;
} else {
- appearAmount = mNotificationStackScroller.calculateAppearFractionBypass();
+ appearAmount = mNotificationStackScrollLayoutController
+ .calculateAppearFractionBypass();
}
startHeight = -mQs.getQsMinExpansionHeight();
}
@@ -2266,7 +2297,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected void onExpandingStarted() {
super.onExpandingStarted();
- mNotificationStackScroller.onExpansionStarted();
+ mNotificationStackScrollLayoutController.onExpansionStarted();
mIsExpanding = true;
mQsExpandedWhenExpandingStarted = mQsFullyExpanded;
mMediaHierarchyManager.setCollapsingShadeFromQS(mQsExpandedWhenExpandingStarted &&
@@ -2284,7 +2315,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected void onExpandingFinished() {
super.onExpandingFinished();
- mNotificationStackScroller.onExpansionStopped();
+ mNotificationStackScrollLayoutController.onExpansionStopped();
mHeadsUpManager.onExpandingFinished();
mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed());
mIsExpanding = false;
@@ -2310,7 +2341,7 @@ public class NotificationPanelViewController extends PanelViewController {
setListening(true);
}
mQsExpandImmediate = false;
- mNotificationStackScroller.setShouldShowShelfOnly(false);
+ mNotificationStackScrollLayoutController.setShouldShowShelfOnly(false);
mTwoFingerQsExpandPossible = false;
notifyListenersTrackingHeadsUp(null);
mExpandingFromHeadsUp = false;
@@ -2342,15 +2373,16 @@ public class NotificationPanelViewController extends PanelViewController {
return;
}
if (mBarState != StatusBarState.KEYGUARD) {
- mNotificationStackScroller.setOnHeightChangedListener(null);
+ mNotificationStackScrollLayoutController.setOnHeightChangedListener(null);
if (isPixels) {
- mNotificationStackScroller.setOverScrolledPixels(overExpansion, true /* onTop */,
- false /* animate */);
+ mNotificationStackScrollLayoutController.setOverScrolledPixels(
+ overExpansion, true /* onTop */, false /* animate */);
} else {
- mNotificationStackScroller.setOverScrollAmount(overExpansion, true /* onTop */,
- false /* animate */);
+ mNotificationStackScrollLayoutController.setOverScrollAmount(
+ overExpansion, true /* onTop */, false /* animate */);
}
- mNotificationStackScroller.setOnHeightChangedListener(mOnHeightChangedListener);
+ mNotificationStackScrollLayoutController
+ .setOnHeightChangedListener(mOnHeightChangedListener);
}
}
@@ -2360,12 +2392,12 @@ public class NotificationPanelViewController extends PanelViewController {
super.onTrackingStarted();
if (mQsFullyExpanded) {
mQsExpandImmediate = true;
- mNotificationStackScroller.setShouldShowShelfOnly(true);
+ mNotificationStackScrollLayoutController.setShouldShowShelfOnly(true);
}
if (mBarState == StatusBarState.KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) {
mAffordanceHelper.animateHideLeftRightIcon();
}
- mNotificationStackScroller.onPanelTrackingStarted();
+ mNotificationStackScrollLayoutController.onPanelTrackingStarted();
}
@Override
@@ -2373,10 +2405,10 @@ public class NotificationPanelViewController extends PanelViewController {
mFalsingManager.onTrackingStopped();
super.onTrackingStopped(expand);
if (expand) {
- mNotificationStackScroller.setOverScrolledPixels(0.0f, true /* onTop */,
+ mNotificationStackScrollLayoutController.setOverScrolledPixels(0.0f, true /* onTop */,
true /* animate */);
}
- mNotificationStackScroller.onPanelTrackingStopped();
+ mNotificationStackScrollLayoutController.onPanelTrackingStopped();
if (expand && (mBarState == StatusBarState.KEYGUARD
|| mBarState == StatusBarState.SHADE_LOCKED)) {
if (!mHintAnimationRunning) {
@@ -2386,7 +2418,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
private void updateMaxHeadsUpTranslation() {
- mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mNavigationBarBottomHeight);
+ mNotificationStackScrollLayoutController.setHeadsUpBoundaries(
+ getHeight(), mNavigationBarBottomHeight);
}
@Override
@@ -2402,19 +2435,19 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected void onUnlockHintFinished() {
super.onUnlockHintFinished();
- mNotificationStackScroller.setUnlockHintRunning(false);
+ mNotificationStackScrollLayoutController.setUnlockHintRunning(false);
}
@Override
protected void onUnlockHintStarted() {
super.onUnlockHintStarted();
- mNotificationStackScroller.setUnlockHintRunning(true);
+ mNotificationStackScrollLayoutController.setUnlockHintRunning(true);
}
@Override
protected float getPeekHeight() {
- if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
- return mNotificationStackScroller.getPeekHeight();
+ if (mNotificationStackScrollLayoutController.getNotGoneChildCount() > 0) {
+ return mNotificationStackScrollLayoutController.getPeekHeight();
} else {
return mQsMinExpansionHeight;
}
@@ -2428,7 +2461,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
// Let's make sure we're not appearing but the animation will end below the appear.
// Otherwise quick settings would jump at the end of the animation.
- float fraction = mNotificationStackScroller.calculateAppearFraction(targetHeight);
+ float fraction = mNotificationStackScrollLayoutController
+ .calculateAppearFraction(targetHeight);
return fraction >= 1.0f;
}
@@ -2440,18 +2474,19 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected boolean fullyExpandedClearAllVisible() {
- return mNotificationStackScroller.isFooterViewNotGone()
- && mNotificationStackScroller.isScrolledToBottom() && !mQsExpandImmediate;
+ return mNotificationStackScrollLayoutController.isFooterViewNotGone()
+ && mNotificationStackScrollLayoutController.isScrolledToBottom()
+ && !mQsExpandImmediate;
}
@Override
protected boolean isClearAllVisible() {
- return mNotificationStackScroller.isFooterViewContentVisible();
+ return mNotificationStackScrollLayoutController.isFooterViewContentVisible();
}
@Override
protected int getClearAllHeightWithPadding() {
- return mNotificationStackScroller.getFooterViewHeightWithPadding();
+ return mNotificationStackScrollLayoutController.getFooterViewHeightWithPadding();
}
@Override
@@ -2502,7 +2537,8 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateEmptyShadeView() {
// Hide "No notifications" in QS.
- mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded);
+ mNotificationStackScrollLayoutController.updateEmptyShadeView(
+ mShowEmptyShadeView && !mQsExpanded);
}
public void setQsScrimEnabled(boolean qsScrimEnabled) {
@@ -2593,7 +2629,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
mHeadsUpAnimatingAway = headsUpAnimatingAway;
- mNotificationStackScroller.setHeadsUpAnimatingAway(headsUpAnimatingAway);
+ mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway);
updateHeadsUpVisibility();
}
@@ -2605,7 +2641,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
super.setHeadsUpManager(headsUpManager);
mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager,
- mNotificationStackScroller.getHeadsUpCallback(),
+ mNotificationStackScrollLayoutController.getHeadsUpCallback(),
NotificationPanelViewController.this);
}
@@ -2627,7 +2663,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void setClosingWithAlphaFadeout(boolean closing) {
mClosingWithAlphaFadeOut = closing;
- mNotificationStackScroller.forceNoOverlappingRendering(closing);
+ mNotificationStackScrollLayoutController.forceNoOverlappingRendering(closing);
}
/**
@@ -2637,22 +2673,24 @@ public class NotificationPanelViewController extends PanelViewController {
* @param x the x-coordinate the touch event
*/
protected void updateVerticalPanelPosition(float x) {
- if (mNotificationStackScroller.getWidth() * 1.75f > mView.getWidth()) {
+ if (mNotificationStackScrollLayoutController.getWidth() * 1.75f > mView.getWidth()) {
resetHorizontalPanelPosition();
return;
}
- float leftMost = mPositionMinSideMargin + mNotificationStackScroller.getWidth() / 2;
+ float leftMost = mPositionMinSideMargin
+ + mNotificationStackScrollLayoutController.getWidth() / 2;
float
rightMost =
mView.getWidth() - mPositionMinSideMargin
- - mNotificationStackScroller.getWidth() / 2;
- if (Math.abs(x - mView.getWidth() / 2) < mNotificationStackScroller.getWidth() / 4) {
+ - mNotificationStackScrollLayoutController.getWidth() / 2;
+ if (Math.abs(x - mView.getWidth() / 2)
+ < mNotificationStackScrollLayoutController.getWidth() / 4) {
x = mView.getWidth() / 2;
}
x = Math.min(rightMost, Math.max(leftMost, x));
float
- center =
- mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2;
+ center = mNotificationStackScrollLayoutController.getLeft()
+ + mNotificationStackScrollLayoutController.getWidth() / 2;
setHorizontalPanelTranslation(x - center);
}
@@ -2661,7 +2699,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
protected void setHorizontalPanelTranslation(float translation) {
- mNotificationStackScroller.setTranslationX(translation);
+ mNotificationStackScrollLayoutController.setTranslationX(translation);
mQsFrame.setTranslationX(translation);
int size = mVerticalTranslationListener.size();
for (int i = 0; i < size; i++) {
@@ -2671,13 +2709,14 @@ public class NotificationPanelViewController extends PanelViewController {
protected void updateExpandedHeight(float expandedHeight) {
if (mTracking) {
- mNotificationStackScroller.setExpandingVelocity(getCurrentExpandVelocity());
+ mNotificationStackScrollLayoutController
+ .setExpandingVelocity(getCurrentExpandVelocity());
}
if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
// The expandedHeight is always the full panel Height when bypassing
expandedHeight = getMaxPanelHeightNonBypass();
}
- mNotificationStackScroller.setExpandedHeight(expandedHeight);
+ mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
updateBigClockAlpha();
updateStatusBarIcons();
@@ -2837,7 +2876,7 @@ public class NotificationPanelViewController extends PanelViewController {
mHeightListener.onQsHeightChanged();
}
});
- mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView());
+ mNotificationStackScrollLayoutController.setQsContainer((ViewGroup) mQs.getView());
if (mQs instanceof QSFragment) {
mKeyguardStatusBar.setQSPanel(((QSFragment) mQs).getQsPanel());
}
@@ -2861,7 +2900,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) {
mAffordanceHelper.reset(false /* animate */);
}
- mNotificationStackScroller.setAnimationsEnabled(!disabled);
+ mNotificationStackScrollLayoutController.setAnimationsEnabled(!disabled);
}
/**
@@ -2875,7 +2914,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (dozing == mDozing) return;
mView.setDozing(dozing);
mDozing = dozing;
- mNotificationStackScroller.setDozing(mDozing, animate, wakeUpTouchLocation);
+ mNotificationStackScrollLayoutController.setDozing(mDozing, animate, wakeUpTouchLocation);
mKeyguardBottomArea.setDozing(mDozing, animate);
if (dozing) {
@@ -2903,7 +2942,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (!mPulsing && !mDozing) {
mAnimateNextPositionUpdate = false;
}
- mNotificationStackScroller.setPulsing(pulsing, animatePulse);
+ mNotificationStackScrollLayoutController.setPulsing(pulsing, animatePulse);
mKeyguardStatusView.setPulsing(pulsing);
}
@@ -3008,7 +3047,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
public boolean hasActiveClearableNotifications() {
- return mNotificationStackScroller.hasActiveClearableNotifications(ROWS_ALL);
+ return mNotificationStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL);
}
private void updateShowEmptyShadeView() {
@@ -3019,39 +3058,39 @@ public class NotificationPanelViewController extends PanelViewController {
}
public RemoteInputController.Delegate createRemoteInputDelegate() {
- return mNotificationStackScroller.createDelegate();
+ return mNotificationStackScrollLayoutController.createDelegate();
}
void updateNotificationViews(String reason) {
- mNotificationStackScroller.updateSectionBoundaries(reason);
- mNotificationStackScroller.updateSpeedBumpIndex();
- mNotificationStackScroller.updateFooter();
+ mNotificationStackScrollLayoutController.updateSectionBoundaries(reason);
+ mNotificationStackScrollLayoutController.updateSpeedBumpIndex();
+ mNotificationStackScrollLayoutController.updateFooter();
updateShowEmptyShadeView();
- mNotificationStackScroller.updateIconAreaViews();
+ mNotificationStackScrollLayoutController.updateIconAreaViews();
}
public void onUpdateRowStates() {
- mNotificationStackScroller.onUpdateRowStates();
+ mNotificationStackScrollLayoutController.onUpdateRowStates();
}
public boolean hasPulsingNotifications() {
- return mNotificationStackScroller.hasPulsingNotifications();
+ return mNotificationStackScrollLayoutController.hasPulsingNotifications();
}
public ActivatableNotificationView getActivatedChild() {
- return mNotificationStackScroller.getActivatedChild();
+ return mNotificationStackScrollLayoutController.getActivatedChild();
}
public void setActivatedChild(ActivatableNotificationView o) {
- mNotificationStackScroller.setActivatedChild(o);
+ mNotificationStackScrollLayoutController.setActivatedChild(o);
}
public void runAfterAnimationFinished(Runnable r) {
- mNotificationStackScroller.runAfterAnimationFinished(r);
+ mNotificationStackScrollLayoutController.runAfterAnimationFinished(r);
}
public void setScrollingEnabled(boolean b) {
- mNotificationStackScroller.setScrollingEnabled(b);
+ mNotificationStackScrollLayoutController.setScrollingEnabled(b);
}
public void initDependencies(StatusBar statusBar, NotificationGroupManager groupManager,
@@ -3060,12 +3099,13 @@ public class NotificationPanelViewController extends PanelViewController {
ScrimController scrimController) {
setStatusBar(statusBar);
setGroupManager(mGroupManager);
- mNotificationStackScroller.setNotificationPanelController(this);
- mNotificationStackScroller.setIconAreaController(notificationIconAreaController);
- mNotificationStackScroller.setStatusBar(statusBar);
- mNotificationStackScroller.setGroupManager(groupManager);
- mNotificationStackScroller.setShelfController(notificationShelfController);
- mNotificationStackScroller.setScrimController(scrimController);
+ mNotificationStackScrollLayoutController.setNotificationPanelController(this);
+ mNotificationStackScrollLayoutController
+ .setIconAreaController(notificationIconAreaController);
+ mNotificationStackScrollLayoutController.setStatusBar(statusBar);
+ mNotificationStackScrollLayoutController.setGroupManager(groupManager);
+ mNotificationStackScrollLayoutController.setShelfController(notificationShelfController);
+ mNotificationStackScrollLayoutController.setScrimController(scrimController);
updateShowEmptyShadeView();
mNotificationShelfController = notificationShelfController;
}
@@ -3231,7 +3271,8 @@ public class NotificationPanelViewController extends PanelViewController {
if (needsAnimation && mInterpolatedDarkAmount == 0) {
mAnimateNextPositionUpdate = true;
}
- ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone();
+ ExpandableView firstChildNotGone =
+ mNotificationStackScrollLayoutController.getFirstChildNotGone();
ExpandableNotificationRow
firstRow =
firstChildNotGone instanceof ExpandableNotificationRow
@@ -3457,13 +3498,13 @@ public class NotificationPanelViewController extends PanelViewController {
private class MyOnHeadsUpChangedListener implements OnHeadsUpChangedListener {
@Override
public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
- mNotificationStackScroller.setInHeadsUpPinnedMode(inPinnedMode);
+ mNotificationStackScrollLayoutController.setInHeadsUpPinnedMode(inPinnedMode);
if (inPinnedMode) {
mHeadsUpExistenceChangedRunnable.run();
updateNotificationTranslucency();
} else {
setHeadsUpAnimatingAway(true);
- mNotificationStackScroller.runAfterAnimationFinished(
+ mNotificationStackScrollLayoutController.runAfterAnimationFinished(
mHeadsUpExistenceChangedRunnable);
}
updateGestureExclusionRect();
@@ -3475,8 +3516,8 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void onHeadsUpPinned(NotificationEntry entry) {
if (!isOnKeyguard()) {
- mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(),
- true);
+ mNotificationStackScrollLayoutController.generateHeadsUpAnimation(
+ entry.getHeadsUpAnimationView(), true);
}
}
@@ -3488,7 +3529,7 @@ public class NotificationPanelViewController extends PanelViewController {
// notification
// will stick to the top without any interaction.
if (isFullyCollapsed() && entry.isRowHeadsUp() && !isOnKeyguard()) {
- mNotificationStackScroller.generateHeadsUpAnimation(
+ mNotificationStackScrollLayoutController.generateHeadsUpAnimation(
entry.getHeadsUpAnimationView(), false);
entry.setHeadsUpIsVisible();
}
@@ -3496,7 +3537,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp);
+ mNotificationStackScrollLayoutController.generateHeadsUpAnimation(entry, isHeadsUp);
}
}
@@ -3511,7 +3552,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (mAccessibilityManager.isEnabled()) {
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
- mNotificationStackScroller.setMaxTopPadding(
+ mNotificationStackScrollLayoutController.setMaxTopPadding(
mQsMaxExpansionHeight + mQsNotificationTopPadding);
}
}
@@ -3573,7 +3614,7 @@ public class NotificationPanelViewController extends PanelViewController {
} else if (oldState == StatusBarState.SHADE_LOCKED
&& statusBarState == StatusBarState.KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- mNotificationStackScroller.resetScrollPosition();
+ mNotificationStackScrollLayoutController.resetScrollPosition();
// Only animate header if the header is visible. If not, it will partially
// animate out
// the top of QS
@@ -3649,7 +3690,7 @@ public class NotificationPanelViewController extends PanelViewController {
int oldTop, int oldRight, int oldBottom) {
DejankUtils.startDetectingBlockingIpcs("NVP#onLayout");
super.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
- setIsFullWidth(mNotificationStackScroller.getWidth() == mView.getWidth());
+ setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
// Update Clock Pivot
mKeyguardStatusView.setPivotX(mView.getWidth() / 2);
@@ -3665,7 +3706,7 @@ public class NotificationPanelViewController extends PanelViewController {
mQsExpansionHeight = mQsMinExpansionHeight;
}
mQsMaxExpansionHeight = mQs.getDesiredHeight();
- mNotificationStackScroller.setMaxTopPadding(
+ mNotificationStackScrollLayoutController.setMaxTopPadding(
mQsMaxExpansionHeight + mQsNotificationTopPadding);
}
positionClockAndNotifications();
@@ -3727,7 +3768,7 @@ public class NotificationPanelViewController extends PanelViewController {
0, calculateQsTopPadding(), mView.getWidth(), calculateQsTopPadding(), p);
p.setColor(Color.CYAN);
canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
- mNotificationStackScroller.getTopPadding(), p);
+ mNotificationStackScrollLayoutController.getTopPadding(), p);
p.setColor(Color.GRAY);
canvas.drawLine(0, mClockPositionResult.clockY, mView.getWidth(),
mClockPositionResult.clockY, p);
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 c8fb4e3372c8..6cd33c6872c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -209,6 +209,7 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -1075,7 +1076,7 @@ public class StatusBar extends SystemUI implements DemoMode,
// TODO (b/136993073) Separate notification shade and status bar
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mNotificationIconAreaController, mHeadsUpManager,
- mNotificationShadeWindowView,
+ mStackScroller.getController(),
mStatusBarStateController, mKeyguardBypassController,
mKeyguardStateController, mWakeUpCoordinator, mCommandQueue,
mNotificationPanelViewController, mStatusBarView);
@@ -4050,7 +4051,7 @@ public class StatusBar extends SystemUI implements DemoMode,
protected IStatusBarService mBarService;
// all notifications
- protected ViewGroup mStackScroller;
+ protected NotificationStackScrollLayout mStackScroller;
private final NotificationGroupManager mGroupManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 72395e68ff07..ac69d9c32c93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -244,9 +244,10 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
@Override
public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
+ boolean appRequestedAuth,
NotificationRemoteInputManager.ClickHandler defaultHandler) {
final boolean isActivity = pendingIntent.isActivity();
- if (isActivity) {
+ if (isActivity || appRequestedAuth) {
mActionClickLogger.logWaitingToCloseKeyguard(pendingIntent);
final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity(
pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 4fdc06e64e2c..8f082c15df36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -27,6 +27,9 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -34,6 +37,8 @@ import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.media.AudioRecordingConfiguration;
import android.os.Looper;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
@@ -47,9 +52,11 @@ import com.android.systemui.dump.DumpManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Collections;
import java.util.List;
@SmallTest
@@ -73,6 +80,12 @@ public class AppOpsControllerTest extends SysuiTestCase {
private PermissionFlagsCache mFlagsCache;
@Mock
private PackageManager mPackageManager;
+ @Mock(stubOnly = true)
+ private AudioManager mAudioManager;
+ @Mock(stubOnly = true)
+ private AudioManager.AudioRecordingCallback mRecordingCallback;
+ @Mock(stubOnly = true)
+ private AudioRecordingConfiguration mPausedMockRecording;
private AppOpsControllerImpl mController;
private TestableLooper mTestableLooper;
@@ -94,11 +107,20 @@ public class AppOpsControllerTest extends SysuiTestCase {
when(mFlagsCache.getPermissionFlags(anyString(), anyString(),
eq(TEST_UID_NON_USER_SENSITIVE))).thenReturn(0);
+ doAnswer((invocation) -> mRecordingCallback = invocation.getArgument(0))
+ .when(mAudioManager).registerAudioRecordingCallback(any(), any());
+ when(mPausedMockRecording.getClientUid()).thenReturn(TEST_UID);
+ when(mPausedMockRecording.isClientSilenced()).thenReturn(true);
+
+ when(mAudioManager.getActiveRecordingConfigurations())
+ .thenReturn(List.of(mPausedMockRecording));
+
mController = new AppOpsControllerImpl(
mContext,
mTestableLooper.getLooper(),
mDumpManager,
- mFlagsCache
+ mFlagsCache,
+ mAudioManager
);
}
@@ -363,6 +385,89 @@ public class AppOpsControllerTest extends SysuiTestCase {
AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true);
}
+ @Test
+ public void testPausedRecordingIsRetrievedOnCreation() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+ mTestableLooper.processAllMessages();
+
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ verify(mCallback, never())
+ .onActiveStateChanged(anyInt(), anyInt(), anyString(), anyBoolean());
+ }
+
+ @Test
+ public void testPausedRecordingFilteredOut() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+ mTestableLooper.processAllMessages();
+
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ assertTrue(mController.getActiveAppOps().isEmpty());
+ }
+
+ @Test
+ public void testOnlyRecordAudioPaused() {
+ mController.addCallback(new int[]{
+ AppOpsManager.OP_RECORD_AUDIO,
+ AppOpsManager.OP_CAMERA
+ }, mCallback);
+ mTestableLooper.processAllMessages();
+
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ verify(mCallback).onActiveStateChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true);
+ List<AppOpItem> list = mController.getActiveAppOps();
+
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode());
+ }
+
+ @Test
+ public void testUnpausedRecordingSentActive() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+
+ mTestableLooper.processAllMessages();
+ mRecordingCallback.onRecordingConfigChanged(Collections.emptyList());
+
+ mTestableLooper.processAllMessages();
+
+ verify(mCallback).onActiveStateChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ }
+
+ @Test
+ public void testAudioPausedSentInactive() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class);
+ when(mockARC.getClientUid()).thenReturn(TEST_UID_OTHER);
+ when(mockARC.isClientSilenced()).thenReturn(true);
+
+ mRecordingCallback.onRecordingConfigChanged(List.of(mockARC));
+ mTestableLooper.processAllMessages();
+
+ InOrder inOrder = inOrder(mCallback);
+ inOrder.verify(mCallback).onActiveStateChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ inOrder.verify(mCallback).onActiveStateChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
+ }
+
private class TestHandler extends AppOpsControllerImpl.H {
TestHandler(Looper looper) {
mController.super(looper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 3789e6ef1f65..a4ebe1ff2a4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -13,6 +13,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
@@ -58,6 +59,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Mock lateinit var mediaTimeoutListener: MediaTimeoutListener
@Mock lateinit var mediaResumeListener: MediaResumeListener
@Mock lateinit var pendingIntent: PendingIntent
+ @Mock lateinit var activityStarter: ActivityStarter
@JvmField @Rule val mockito = MockitoJUnit.rule()
lateinit var mediaDataManager: MediaDataManager
lateinit var mediaNotification: StatusBarNotification
@@ -68,8 +70,8 @@ class MediaDataManagerTest : SysuiTestCase() {
backgroundExecutor = FakeExecutor(FakeSystemClock())
mediaDataManager = MediaDataManager(context, backgroundExecutor, foregroundExecutor,
mediaControllerFactory, broadcastDispatcher, dumpManager,
- mediaTimeoutListener, mediaResumeListener, useMediaResumption = true,
- useQsMediaPlayer = true)
+ mediaTimeoutListener, mediaResumeListener, activityStarter,
+ useMediaResumption = true, useQsMediaPlayer = true)
session = MediaSession(context, "MediaDataManagerTestSession")
mediaNotification = SbnBuilder().run {
setPkg(PACKAGE_NAME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 85701c24f7d6..fec467706b7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -212,7 +212,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// holds a copy of the CUT's instances of these KeyguardBypassController, so they still
// refer to the CUT's member variables, not the spy's member variables.
mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
- true /* allowLongPress */, mNotificationRoundnessManager,
+ mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
mock(SysuiStatusBarStateController.class),
mHeadsUpManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index e546dff8abf6..8dea84c4d0b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -38,7 +38,7 @@ import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Assert;
@@ -51,8 +51,8 @@ import org.junit.runner.RunWith;
@RunWithLooper
public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
- private final NotificationStackScrollLayout mStackScroller =
- mock(NotificationStackScrollLayout.class);
+ private final NotificationStackScrollLayoutController mStackScrollerController =
+ mock(NotificationStackScrollLayoutController.class);
private final NotificationPanelViewController mPanelView =
mock(NotificationPanelViewController.class);
private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class);
@@ -93,9 +93,9 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mWakeUpCoordinator,
mKeyguardStateController,
mCommandQueue,
- mHeadsUpStatusBarView,
- mStackScroller,
+ mStackScrollerController,
mPanelView,
+ mHeadsUpStatusBarView,
new View(mContext),
mOperatorNameView,
new View(mContext));
@@ -172,9 +172,9 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mWakeUpCoordinator,
mKeyguardStateController,
mCommandQueue,
- mHeadsUpStatusBarView,
- mStackScroller,
+ mStackScrollerController,
mPanelView,
+ mHeadsUpStatusBarView,
new View(mContext),
new View(mContext),
new View(mContext));
@@ -193,14 +193,14 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
reset(mHeadsUpManager);
reset(mDarkIconDispatcher);
reset(mPanelView);
- reset(mStackScroller);
+ reset(mStackScrollerController);
mHeadsUpAppearanceController.destroy();
verify(mHeadsUpManager).removeListener(any());
verify(mDarkIconDispatcher).removeDarkReceiver((DarkIconDispatcher.DarkReceiver) any());
verify(mPanelView).removeVerticalTranslationListener(any());
verify(mPanelView).removeTrackingHeadsUpListener(any());
verify(mPanelView).setHeadsUpAppearanceController(any());
- verify(mStackScroller).removeOnExpandedHeightChangedListener(any());
- verify(mStackScroller).removeOnLayoutChangeListener(any());
+ verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any());
+ verify(mStackScrollerController).removeOnLayoutChangeListener(any());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index bf4ccd22effd..f66fd5677a5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -72,8 +72,10 @@ import com.android.systemui.statusbar.notification.ConversationNotificationManag
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -186,8 +188,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
private KeyguardClockSwitchController mKeyguardClockSwitchController;
- private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
-
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
@@ -212,7 +212,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class));
when(mView.findViewById(R.id.big_clock_container)).thenReturn(mBigClockContainer);
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
- mFlingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(mDisplayMetrics);
+ FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
+ mDisplayMetrics);
doAnswer((Answer<Void>) invocation -> {
mTouchHandler = invocation.getArgument(0);
@@ -232,6 +233,11 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mock(NotificationRoundnessManager.class),
mStatusBarStateController,
new FalsingManagerFake());
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController =
+ new NotificationStackScrollLayoutController(
+ true /* allowLongPress */,
+ mock(NotificationGutsManager.class)
+ );
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mInjectionInflationController,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
@@ -241,10 +247,11 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController,
- mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
+ flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mBiometricUnlockController, mStatusBarKeyguardViewManager,
- () -> mKeyguardClockSwitchController);
+ () -> mKeyguardClockSwitchController,
+ notificationStackScrollLayoutController);
mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager,
mNotificationShelfController, mNotificationAreaController, mScrimController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
@@ -252,8 +259,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
ArgumentCaptor<View.AccessibilityDelegate> accessibilityDelegateArgumentCaptor =
ArgumentCaptor.forClass(View.AccessibilityDelegate.class);
- verify(mView)
- .setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture());
+ verify(mView).setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture());
mAccessibiltyDelegate = accessibilityDelegateArgumentCaptor.getValue();
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index c45da8668087..a2d58c8019fc 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -631,7 +631,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
// Two pointers moving in the same direction within
// a given distance perform a drag.
mState.startDragging();
- adjustEventLocationForDrag(event);
+ computeDraggingPointerIdIfNeeded(event);
pointerIdBits = 1 << mDraggingPointerId;
event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags());
mDispatcher.sendMotionEvent(
@@ -794,7 +794,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
case 2:
if (isDraggingGesture(event)) {
// If still dragging send a drag event.
- adjustEventLocationForDrag(event);
+ computeDraggingPointerIdIfNeeded(event);
mDispatcher.sendMotionEvent(
event, ACTION_MOVE, rawEvent, pointerIdBits, policyFlags);
} else {
@@ -959,44 +959,27 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
/**
- * Adjust the location of an injected event when performing a drag. The location will be the
- * location of the finger closest to an edge of the screen.
+ * Computes {@link #mDraggingPointerId} if it is invalid. The pointer will be the finger
+ * closet to an edge of the screen.
*/
- private void adjustEventLocationForDrag(MotionEvent event) {
+ private void computeDraggingPointerIdIfNeeded(MotionEvent event) {
+ if (mDraggingPointerId != INVALID_POINTER_ID) {
+ // If we have a valid pointer ID, we should be good
+ final int pointerIndex = event.findPointerIndex(mDraggingPointerId);
+ if (event.findPointerIndex(pointerIndex) >= 0) {
+ return;
+ }
+ }
+ // Use the pointer that is closest to its closest edge.
final float firstPtrX = event.getX(0);
final float firstPtrY = event.getY(0);
final int firstPtrId = event.getPointerId(0);
final float secondPtrX = event.getX(1);
final float secondPtrY = event.getY(1);
final int secondPtrId = event.getPointerId(1);
- float draggingX = firstPtrX;
- float draggingY = firstPtrY;
- if (mDraggingPointerId != INVALID_POINTER_ID) {
- // Just use the coordinates of the dragging pointer.
- int pointerIndex = event.findPointerIndex(mDraggingPointerId);
- if (pointerIndex >= 0) {
- draggingX = event.getX(pointerIndex);
- draggingY = event.getY(pointerIndex);
- } else {
- // We've lost track of the dragging pointer. Try to recover by invalidating it.
- // We'll the drop into the code below to choose a new one.
- mDraggingPointerId = INVALID_POINTER_ID;
- }
- }
- // Not quite an else, since the above code can invalidate the pointer
- if (mDraggingPointerId == INVALID_POINTER_ID) {
- // The goal is to use the coordinates of the finger that is closest to its closest edge.
- if (getDistanceToClosestEdge(firstPtrX, firstPtrY)
- < getDistanceToClosestEdge(secondPtrX, secondPtrY)) {
- // X and Y initialized to firstPtrX and Y was right
- mDraggingPointerId = firstPtrId;
- } else {
- draggingX = secondPtrX;
- draggingY = secondPtrY;
- mDraggingPointerId = secondPtrId;
- }
- }
- event.setLocation(draggingX, draggingY);
+ mDraggingPointerId = (getDistanceToClosestEdge(firstPtrX, firstPtrY)
+ < getDistanceToClosestEdge(secondPtrX, secondPtrY))
+ ? firstPtrId : secondPtrId;
}
private float getDistanceToClosestEdge(float x, float y) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3eb26de3a675..b83aa4fb4d86 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -694,12 +694,8 @@ public final class ActiveServices {
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
- if (!r.mAllowWhileInUsePermissionInFgs) {
- r.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
- callingUid, service, r, allowBackgroundActivityStarts);
- }
-
+ setFgsRestrictionLocked(callingPackage, callingPid,
+ callingUid, service, r, allowBackgroundActivityStarts);
return cmp;
}
@@ -1369,6 +1365,7 @@ public final class ActiveServices {
+ r.shortInstanceName);
}
}
+
boolean alreadyStartedOp = false;
boolean stopProcStatsOp = false;
if (r.fgRequired) {
@@ -1415,6 +1412,24 @@ public final class ActiveServices {
ignoreForeground = true;
}
+ if (!ignoreForeground) {
+ if (!r.mAllowStartForeground) {
+ if (!r.mLoggedInfoAllowStartForeground) {
+ Slog.wtf(TAG, "Background started FGS "
+ + r.mInfoAllowStartForeground);
+ r.mLoggedInfoAllowStartForeground = true;
+ }
+ if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
+ Slog.w(TAG,
+ "Service.startForeground() not allowed due to "
+ + " mAllowStartForeground false: service "
+ + r.shortInstanceName);
+ updateServiceForegroundLocked(r.app, true);
+ ignoreForeground = true;
+ }
+ }
+ }
+
// Apps under strict background restrictions simply don't get to have foreground
// services, so now that we've enforced the startForegroundService() contract
// we only do the machinery of making the service foreground when the app
@@ -2067,12 +2082,7 @@ public final class ActiveServices {
}
}
- if (!s.mAllowWhileInUsePermissionInFgs) {
- s.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage,
- callingPid, callingUid,
- service, s, false);
- }
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, false);
if (s.app != null) {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -4840,21 +4850,48 @@ public final class ActiveServices {
}
/**
- * Should allow while-in-use permissions in foreground service or not.
- * while-in-use permissions in FGS started from background might be restricted.
+ * There are two FGS restrictions:
+ * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground
+ * service or not. while-in-use permissions in FGS started from background might be restricted.
+ * In S, mAllowStartForeground is to allow FGS to startForeground or not. Service started
+ * from background may not become a FGS.
* @param callingPackage caller app's package name.
* @param callingUid caller app's uid.
* @param intent intent to start/bind service.
* @param r the service to start.
* @return true if allow, false otherwise.
*/
- private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage,
+ private void setFgsRestrictionLocked(String callingPackage,
int callingPid, int callingUid, Intent intent, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
- // Is the background FGS start restriction turned on?
+ // Check DeviceConfig flag.
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
- return true;
+ r.mAllowWhileInUsePermissionInFgs = true;
+ }
+
+ if (!r.mAllowWhileInUsePermissionInFgs || !r.mAllowStartForeground) {
+ final boolean temp = shouldAllowFgsFeatureLocked(callingPackage, callingPid,
+ callingUid, intent, r, allowBackgroundActivityStarts);
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ r.mAllowWhileInUsePermissionInFgs = temp;
+ }
+ if (!r.mAllowStartForeground) {
+ r.mAllowStartForeground = temp;
+ }
}
+ }
+
+ /**
+ * Should allow FGS feature or not.
+ * @param callingPackage caller app's package name.
+ * @param callingUid caller app's uid.
+ * @param intent intent to start/bind service.
+ * @param r the service to start.
+ * @return true if allow, false otherwise.
+ */
+ private boolean shouldAllowFgsFeatureLocked(String callingPackage,
+ int callingPid, int callingUid, Intent intent, ServiceRecord r,
+ boolean allowBackgroundActivityStarts) {
// Is the allow activity background start flag on?
if (allowBackgroundActivityStarts) {
return true;
@@ -4894,10 +4931,11 @@ public final class ActiveServices {
}
// Is the calling UID at PROCESS_STATE_TOP or above?
- final boolean isCallingUidTopApp = appIsTopLocked(callingUid);
- if (isCallingUidTopApp) {
+ final int uidState = mAm.getUidState(callingUid);
+ if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
return true;
}
+
// Does the calling UID have any visible activity?
final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid);
if (isCallingUidVisible) {
@@ -4915,6 +4953,19 @@ public final class ActiveServices {
if (isDeviceOwner) {
return true;
}
+
+ final String info =
+ "[callingPackage: " + callingPackage
+ + "; callingUid: " + callingUid
+ + "; uidState: " + ProcessList.makeProcStateString(uidState)
+ + "; intent: " + intent
+ + "; targetSdkVersion:" + r.appInfo.targetSdkVersion
+ + "]";
+ if (!info.equals(r.mInfoAllowStartForeground)) {
+ r.mLoggedInfoAllowStartForeground = false;
+ r.mInfoAllowStartForeground = info;
+ }
+
return false;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 775119c18037..e9539be8b0d5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -144,6 +144,13 @@ final class ActivityManagerConstants extends ContentObserver {
private static final String KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED =
"default_background_fgs_starts_restriction_enabled";
+ /**
+ * Default value for mFlagFgsStartRestrictionEnabled if not explicitly set in
+ * Settings.Global.
+ */
+ private static final String KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED =
+ "default_fgs_starts_restriction_enabled";
+
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -293,6 +300,11 @@ final class ActivityManagerConstants extends ContentObserver {
// started, the restriction is on while-in-use permissions.)
volatile boolean mFlagBackgroundFgsStartRestrictionEnabled = true;
+ // Indicates whether the foreground service background start restriction is enabled.
+ // When the restriction is enabled, service is not allowed to startForeground from background
+ // at all.
+ volatile boolean mFlagFgsStartRestrictionEnabled = false;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -436,6 +448,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED:
updateBackgroundFgsStartsRestriction();
break;
+ case KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED:
+ updateFgsStartsRestriction();
+ break;
case KEY_OOMADJ_UPDATE_POLICY:
updateOomAdjUpdatePolicy();
break;
@@ -659,6 +674,7 @@ final class ActivityManagerConstants extends ContentObserver {
mFlagForegroundServiceStartsLoggingEnabled = Settings.Global.getInt(mResolver,
Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, 1) == 1;
}
+
private void updateBackgroundFgsStartsRestriction() {
mFlagBackgroundFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -666,6 +682,13 @@ final class ActivityManagerConstants extends ContentObserver {
/*defaultValue*/ true);
}
+ private void updateFgsStartsRestriction() {
+ mFlagFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED,
+ /*defaultValue*/ false);
+ }
+
private void updateOomAdjUpdatePolicy() {
OOMADJ_UPDATE_QUICK = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a838aadc404e..f250647d7711 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1581,6 +1581,7 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
static final int KILL_APP_ZYGOTE_MSG = 71;
static final int BINDER_HEAVYHITTER_AUTOSAMPLER_TIMEOUT_MSG = 72;
+ static final int WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG = 73;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1917,6 +1918,11 @@ public class ActivityManagerService extends IActivityManager.Stub
case BINDER_HEAVYHITTER_AUTOSAMPLER_TIMEOUT_MSG: {
handleBinderHeavyHitterAutoSamplerTimeOut();
} break;
+ case WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG: {
+ synchronized (ActivityManagerService.this) {
+ ((ContentProviderRecord) msg.obj).onProviderPublishStatusLocked(false);
+ }
+ } break;
}
}
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 5cc7aba736e1..bfba4afcd4e4 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -50,6 +50,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -218,7 +219,7 @@ public class ContentProviderHelper {
// of being published... but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
- ContentProviderHolder holder = cpr.newHolder(null);
+ ContentProviderHolder holder = cpr.newHolder(null, true);
// don't give caller the provider object, it needs to make its own.
holder.provider = null;
return holder;
@@ -415,7 +416,7 @@ public class ContentProviderHelper {
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
- return cpr.newHolder(null);
+ return cpr.newHolder(null, true);
}
if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
@@ -513,6 +514,38 @@ public class ContentProviderHelper {
UserHandle.getAppId(cpi.applicationInfo.uid));
}
+ if (caller != null) {
+ // The client will be waiting, and we'll notify it when the provider is ready.
+ synchronized (cpr) {
+ if (cpr.provider == null) {
+ if (cpr.launchingApp == null) {
+ Slog.w(TAG, "Unable to launch app "
+ + cpi.applicationInfo.packageName + "/"
+ + cpi.applicationInfo.uid + " for provider "
+ + name + ": launching app became null");
+ EventLogTags.writeAmProviderLostProcess(
+ UserHandle.getUserId(cpi.applicationInfo.uid),
+ cpi.applicationInfo.packageName,
+ cpi.applicationInfo.uid, name);
+ return null;
+ }
+
+ if (conn != null) {
+ conn.waiting = true;
+ }
+ Message msg = mService.mHandler.obtainMessage(
+ ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG);
+ msg.obj = cpr;
+ mService.mHandler.sendMessageDelayed(msg,
+ ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
+ }
+ }
+ // Return a holder instance even if we are waiting for the publishing of the provider,
+ // client will check for the holder.provider to see if it needs to wait for it.
+ return cpr.newHolder(conn, false);
+ }
+
+ // Because of the provider's external client (i.e., SHELL), we'll have to wait right here.
// Wait for the provider to be published...
final long timeout =
SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
@@ -569,7 +602,7 @@ public class ContentProviderHelper {
+ " caller=" + callerName + "/" + Binder.getCallingUid());
return null;
}
- return cpr.newHolder(conn);
+ return cpr.newHolder(conn, false);
}
void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
@@ -622,6 +655,8 @@ public class ContentProviderHelper {
}
if (wasInLaunchingProviders) {
mService.mHandler.removeMessages(
+ ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG, dst);
+ mService.mHandler.removeMessages(
ActivityManagerService.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
// Make sure the package is associated with the process.
@@ -635,6 +670,7 @@ public class ContentProviderHelper {
dst.provider = src.provider;
dst.setProcess(r);
dst.notifyAll();
+ dst.onProviderPublishStatusLocked(true);
}
dst.mRestartCount = 0;
mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
@@ -1504,6 +1540,9 @@ public class ContentProviderHelper {
synchronized (cpr) {
cpr.launchingApp = null;
cpr.notifyAll();
+ cpr.onProviderPublishStatusLocked(false);
+ mService.mHandler.removeMessages(
+ ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG, cpr);
}
final int userId = UserHandle.getUserId(cpr.uid);
// Don't remove from provider map if it doesn't match
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index d8d8cccc05f3..fb8b5d480b27 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -85,11 +85,12 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
noReleaseNeeded = cpr.noReleaseNeeded;
}
- public ContentProviderHolder newHolder(ContentProviderConnection conn) {
+ public ContentProviderHolder newHolder(ContentProviderConnection conn, boolean local) {
ContentProviderHolder holder = new ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = noReleaseNeeded;
holder.connection = conn;
+ holder.mLocal = local;
return holder;
}
@@ -179,6 +180,50 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
return !connections.isEmpty() || hasExternalProcessHandles();
}
+ /**
+ * Notify all clients that the provider has been published and ready to use,
+ * or timed out.
+ *
+ * @param status true: successfully published; false: timed out
+ */
+ void onProviderPublishStatusLocked(boolean status) {
+ final int numOfConns = connections.size();
+ final int userId = UserHandle.getUserId(appInfo.uid);
+ for (int i = 0; i < numOfConns; i++) {
+ final ContentProviderConnection conn = connections.get(i);
+ if (conn.waiting && conn.client != null) {
+ final ProcessRecord client = conn.client;
+ if (!status) {
+ if (launchingApp == null) {
+ Slog.w(TAG_AM, "Unable to launch app "
+ + appInfo.packageName + "/"
+ + appInfo.uid + " for provider "
+ + info.authority + ": launching app became null");
+ EventLogTags.writeAmProviderLostProcess(
+ userId,
+ appInfo.packageName,
+ appInfo.uid, info.authority);
+ } else {
+ Slog.wtf(TAG_AM, "Timeout waiting for provider "
+ + appInfo.packageName + "/"
+ + appInfo.uid + " for provider "
+ + info.authority
+ + " caller=" + client);
+ }
+ }
+ if (client.thread != null) {
+ try {
+ client.thread.notifyContentProviderPublishStatus(
+ newHolder(status ? conn : null, false),
+ info.authority, userId, status);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ conn.waiting = false;
+ }
+ }
+
void dump(PrintWriter pw, String prefix, boolean full) {
if (full) {
pw.print(prefix); pw.print("package=");
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 4a2703056871..66677b67b6aa 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -146,6 +146,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// the most recent package that start/bind this service.
String mRecentCallingPackage;
+ // allow the service becomes foreground service? Service started from background may not be
+ // allowed to become a foreground service.
+ boolean mAllowStartForeground;
+ String mInfoAllowStartForeground;
+ boolean mLoggedInfoAllowStartForeground;
+
String stringName; // caching of toString
private int lastStartId; // identifier of most recent start request.
@@ -408,6 +414,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.println(mAllowWhileInUsePermissionInFgs);
pw.print(prefix); pw.print("recentCallingPackage=");
pw.println(mRecentCallingPackage);
+ pw.print(prefix); pw.print("allowStartForeground=");
+ pw.println(mAllowStartForeground);
+ pw.print(prefix); pw.print("infoAllowStartForeground=");
+ pw.println(mInfoAllowStartForeground);
if (delayed) {
pw.print(prefix); pw.print("delayed="); pw.println(delayed);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index b94396634530..23b09294260c 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1282,6 +1282,7 @@ public class AudioService extends IAudioService.Stub
}
if (isPlatformTelevision()) {
+ checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller);
synchronized (mHdmiClientLock) {
if (mHdmiManager != null && mHdmiPlaybackClient != null) {
updateHdmiCecSinkLocked(mHdmiCecSink | false);
@@ -1301,54 +1302,22 @@ public class AudioService extends IAudioService.Stub
}
}
- /**
- * Update volume states for the given device.
- *
- * This will initialize the volume index if no volume index is available.
- * If the device is the currently routed device, fixed/full volume policies will be applied.
- *
- * @param device a single audio device, ensure that this is not a devices bitmask
- * @param caller caller of this method
- */
- private void updateVolumeStatesForAudioDevice(int device, String caller) {
+ private void checkAddAllFixedVolumeDevices(int device, String caller) {
final int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- updateVolumeStates(device, streamType, caller);
- }
- }
-
- /**
- * Update volume states for the given device and given stream.
- *
- * This will initialize the volume index if no volume index is available.
- * If the device is the currently routed device, fixed/full volume policies will be applied.
- *
- * @param device a single audio device, ensure that this is not a devices bitmask
- * @param streamType streamType to be updated
- * @param caller caller of this method
- */
- private void updateVolumeStates(int device, int streamType, String caller) {
- if (!mStreamStates[streamType].hasIndexForDevice(device)) {
- // set the default value, if device is affected by a full/fix/abs volume rule, it
- // will taken into account in checkFixedVolumeDevices()
- mStreamStates[streamType].setIndex(
- mStreamStates[mStreamVolumeAlias[streamType]]
- .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
- device, caller, true /*hasModifyAudioSettings*/);
- }
-
- // Check if device to be updated is routed for the given audio stream
- List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributes(
- new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build());
- for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) {
- if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType(
- device)) {
- mStreamStates[streamType].checkFixedVolumeDevices();
+ if (!mStreamStates[streamType].hasIndexForDevice(device)) {
+ // set the default value, if device is affected by a full/fix/abs volume rule, it
+ // will taken into account in checkFixedVolumeDevices()
+ mStreamStates[streamType].setIndex(
+ mStreamStates[mStreamVolumeAlias[streamType]]
+ .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
+ device, caller, true /*hasModifyAudioSettings*/);
+ }
+ mStreamStates[streamType].checkFixedVolumeDevices();
- // Unmute streams if required if device is full volume
- if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) {
- mStreamStates[streamType].mute(false);
- }
+ // Unmute streams if device is full volume
+ if (mFullVolumeDevices.contains(device)) {
+ mStreamStates[streamType].mute(false);
}
}
}
@@ -4932,15 +4901,7 @@ public class AudioService extends IAudioService.Stub
synchronized (VolumeStreamState.class) {
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (stream != skipStream) {
- int devices = mStreamStates[stream].observeDevicesForStream_syncVSS(
- false /*checkOthers*/);
-
- Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices);
- for (Integer device : devicesSet) {
- // Update volume states for devices routed for the stream
- updateVolumeStates(device, stream,
- "AudioService#observeDevicesForStreams");
- }
+ mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
}
}
}
@@ -5009,7 +4970,7 @@ public class AudioService extends IAudioService.Stub
+ Integer.toHexString(audioSystemDeviceOut) + " from:" + caller));
// make sure we have a volume entry for this device, and that volume is updated according
// to volume behavior
- updateVolumeStatesForAudioDevice(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
+ checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
}
/**
@@ -7231,9 +7192,10 @@ public class AudioService extends IAudioService.Stub
// HDMI output
removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
}
- updateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
- "HdmiPlaybackClient.DisplayStatusCallback");
}
+
+ checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
+ "HdmiPlaybackClient.DisplayStatusCallback");
}
private class MyHdmiControlStatusChangeListenerCallback
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 840645edcb82..8af74631fb2e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -613,6 +613,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
throw new IllegalArgumentException(
"APEX files can only be installed as part of a staged session.");
}
+ if (params.isMultiPackage) {
+ throw new IllegalArgumentException("A multi-session can't be set as APEX.");
+ }
}
if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9dda3812fccf..f66b4ee5a1a7 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -141,6 +141,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Service for {@link UserManager}.
@@ -443,6 +444,11 @@ public class UserManagerService extends IUserManager.Stub {
}
};
+ // TODO(b/161915546): remove once userWithName() is fixed / removed
+ // Use to debug / dump when user 0 is allocated at userWithName()
+ public static final boolean DBG_ALLOCATION = false; // DO NOT SUBMIT WITH TRUE
+ public final AtomicInteger mUser0Allocations;
+
/**
* Start an {@link IntentSender} when user is unlocked after disabling quiet mode.
*
@@ -629,6 +635,7 @@ public class UserManagerService extends IUserManager.Stub {
LocalServices.addService(UserManagerInternal.class, mLocalService);
mLockPatternUtils = new LockPatternUtils(mContext);
mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
+ mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
}
void systemReady() {
@@ -1310,6 +1317,10 @@ public class UserManagerService extends IUserManager.Stub {
*/
private UserInfo userWithName(UserInfo orig) {
if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) {
+ if (DBG_ALLOCATION) {
+ final int number = mUser0Allocations.incrementAndGet();
+ Slog.w(LOG_TAG, "System user instantiated at least " + number + " times");
+ }
UserInfo withName = new UserInfo(orig);
withName.name = getOwnerName();
return withName;
@@ -4833,6 +4844,10 @@ public class UserManagerService extends IUserManager.Stub {
pw.println(" Is split-system user: " + UserManager.isSplitSystemUser());
pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
pw.println(" User version: " + mUserVersion);
+ pw.println(" Owner name: " + getOwnerName());
+ if (DBG_ALLOCATION) {
+ pw.println(" System user allocations: " + mUser0Allocations.get());
+ }
// Dump UserTypes
pw.println();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 03771be0ce7c..63aa80e8269a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -83,6 +83,7 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -120,6 +121,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.TimingsTraceLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -2521,12 +2523,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final PermissionsState permissionsState = ps.getPermissionsState();
- final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+ final int[] userIds = getAllUserIds();
boolean runtimePermissionsRevoked = false;
int[] updatedUserIds = EMPTY_INT_ARRAY;
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
if (permissionsState.isMissing(userId)) {
Collection<String> requestedPermissions;
int targetSdkVersion;
@@ -2592,7 +2594,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// runtime and revocation of a runtime from a shared user.
synchronized (mLock) {
updatedUserIds = revokeUnusedSharedUserPermissionsLocked(ps.getSharedUser(),
- currentUserIds);
+ userIds);
if (!ArrayUtils.isEmpty(updatedUserIds)) {
runtimePermissionsRevoked = true;
}
@@ -2747,7 +2749,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// a runtime permission being downgraded to an install one.
// Also in permission review mode we keep dangerous permissions
// for legacy apps
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
if (origPermissions.getRuntimePermissionState(
perm, userId) != null) {
// Revoke the runtime permission and clear the flags.
@@ -2770,7 +2772,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean hardRestricted = bp.isHardRestricted();
boolean softRestricted = bp.isSoftRestricted();
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
// If permission policy is not ready we don't deal with restricted
// permissions as the policy may whitelist some permissions. Once
// the policy is initialized we would re-evaluate permissions.
@@ -2909,7 +2911,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean hardRestricted = bp.isHardRestricted();
boolean softRestricted = bp.isSoftRestricted();
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
// If permission policy is not ready we don't deal with restricted
// permissions as the policy may whitelist some permissions. Once
// the policy is initialized we would re-evaluate permissions.
@@ -3061,10 +3063,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
synchronized (mLock) {
updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
- currentUserIds, updatedUserIds);
+ userIds, updatedUserIds);
updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
- permissionsState, pkg, newImplicitPermissions, currentUserIds, updatedUserIds);
- updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, currentUserIds,
+ permissionsState, pkg, newImplicitPermissions, userIds, updatedUserIds);
+ updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, userIds,
updatedUserIds);
}
@@ -3081,6 +3083,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
/**
+ * Returns all relevant user ids. This list include the current set of created user ids as well
+ * as pre-created user ids.
+ * @return user ids for created users and pre-created users
+ */
+ private int[] getAllUserIds() {
+ final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+ t.traceBegin("getAllUserIds");
+ List<UserInfo> users = UserManagerService.getInstance().getUsers(
+ /*excludePartial=*/ true, /*excludeDying=*/ true, /*excludePreCreated=*/ false);
+ int size = users.size();
+ final int[] userIds = new int[size];
+ for (int i = 0; i < size; i++) {
+ userIds[i] = users.get(i).id;
+ }
+ t.traceEnd();
+ return userIds;
+ }
+
+ /**
* Revoke permissions that are not implicit anymore and that have
* {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set.
*
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 2a74b3d23829..5aedfc19028b 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -28,8 +28,6 @@ import static android.os.Process.SYSTEM_UID;
import android.Manifest.permission;
import android.annotation.NonNull;
import android.app.AppOpsManager;
-import android.app.role.OnRoleHoldersChangedListener;
-import android.app.role.RoleManager;
import android.app.slice.ISliceManager;
import android.app.slice.SliceSpec;
import android.app.usage.UsageStatsManagerInternal;
@@ -41,9 +39,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
@@ -65,7 +61,6 @@ import com.android.internal.app.AssistUtils;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -77,10 +72,7 @@ import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.function.Supplier;
public class SliceManagerService extends ISliceManager.Stub {
@@ -88,16 +80,13 @@ public class SliceManagerService extends ISliceManager.Stub {
private final Object mLock = new Object();
private final Context mContext;
- private final PackageManagerInternal mPackageManagerInternal;
private final AppOpsManager mAppOps;
private final AssistUtils mAssistUtils;
@GuardedBy("mLock")
private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
@GuardedBy("mLock")
- private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>();
- @GuardedBy("mLock")
- private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>();
+ private final SparseArray<String> mLastAssistantPackage = new SparseArray<>();
private final Handler mHandler;
private final SlicePermissionManager mPermissions;
@@ -110,8 +99,6 @@ public class SliceManagerService extends ISliceManager.Stub {
@VisibleForTesting
SliceManagerService(Context context, Looper looper) {
mContext = context;
- mPackageManagerInternal = Objects.requireNonNull(
- LocalServices.getService(PackageManagerInternal.class));
mAppOps = context.getSystemService(AppOpsManager.class);
mAssistUtils = new AssistUtils(context);
mHandler = new Handler(looper);
@@ -124,7 +111,6 @@ public class SliceManagerService extends ISliceManager.Stub {
filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
- mRoleObserver = new RoleObserver();
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
}
@@ -174,8 +160,7 @@ public class SliceManagerService extends ISliceManager.Stub {
mHandler.post(() -> {
if (slicePkg != null && !Objects.equals(pkg, slicePkg)) {
mAppUsageStats.reportEvent(slicePkg, user,
- isAssistant(pkg, user) || isDefaultHomeApp(pkg, user)
- ? SLICE_PINNED_PRIV : SLICE_PINNED);
+ isAssistant(pkg, user) ? SLICE_PINNED_PRIV : SLICE_PINNED);
}
});
}
@@ -440,38 +425,19 @@ public class SliceManagerService extends ISliceManager.Stub {
private boolean hasFullSliceAccess(String pkg, int userId) {
long ident = Binder.clearCallingIdentity();
try {
- boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
- || isGrantedFullAccess(pkg, userId);
- return ret;
+ return isAssistant(pkg, userId) || isGrantedFullAccess(pkg, userId);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private boolean isAssistant(String pkg, int userId) {
- return getAssistantMatcher(userId).matches(pkg);
- }
-
- private boolean isDefaultHomeApp(String pkg, int userId) {
- return getHomeMatcher(userId).matches(pkg);
- }
-
- private PackageMatchingCache getAssistantMatcher(int userId) {
- PackageMatchingCache matcher = mAssistantLookup.get(userId);
- if (matcher == null) {
- matcher = new PackageMatchingCache(() -> getAssistant(userId));
- mAssistantLookup.put(userId, matcher);
- }
- return matcher;
- }
-
- private PackageMatchingCache getHomeMatcher(int userId) {
- PackageMatchingCache matcher = mHomeLookup.get(userId);
- if (matcher == null) {
- matcher = new PackageMatchingCache(() -> getDefaultHome(userId));
- mHomeLookup.put(userId, matcher);
+ if (pkg == null) return false;
+ if (!pkg.equals(mLastAssistantPackage.get(userId))) {
+ // Failed on cached value, try updating.
+ mLastAssistantPackage.put(userId, getAssistant(userId));
}
- return matcher;
+ return pkg.equals(mLastAssistantPackage.get(userId));
}
private String getAssistant(int userId) {
@@ -482,111 +448,6 @@ public class SliceManagerService extends ISliceManager.Stub {
return cn.getPackageName();
}
- /**
- * A cached value of the default home app
- */
- private String mCachedDefaultHome = null;
-
- // Based on getDefaultHome in ShortcutService.
- // TODO: Unify if possible
- @VisibleForTesting
- protected String getDefaultHome(int userId) {
-
- // Set VERIFY to true to run the cache in "shadow" mode for cache
- // testing. Do not commit set to true;
- final boolean VERIFY = false;
-
- if (mCachedDefaultHome != null) {
- if (!VERIFY) {
- return mCachedDefaultHome;
- }
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
-
- // Default launcher from package manager.
- final ComponentName defaultLauncher = mPackageManagerInternal
- .getHomeActivitiesAsUser(allHomeCandidates, userId);
-
- ComponentName detected = defaultLauncher;
-
- // Cache the default launcher. It is not a problem if the
- // launcher is null - eventually, the default launcher will be
- // set to something non-null.
- mCachedDefaultHome = ((detected != null) ? detected.getPackageName() : null);
-
- if (detected == null) {
- // If we reach here, that means it's the first check since the user was created,
- // and there's already multiple launchers and there's no default set.
- // Find the system one with the highest priority.
- // (We need to check the priority too because of FallbackHome in Settings.)
- // If there's no system launcher yet, then no one can access slices, until
- // the user explicitly sets one.
- final int size = allHomeCandidates.size();
-
- int lastPriority = Integer.MIN_VALUE;
- for (int i = 0; i < size; i++) {
- final ResolveInfo ri = allHomeCandidates.get(i);
- if (!ri.activityInfo.applicationInfo.isSystemApp()) {
- continue;
- }
- if (ri.priority < lastPriority) {
- continue;
- }
- detected = ri.activityInfo.getComponentName();
- lastPriority = ri.priority;
- }
- }
- final String ret = ((detected != null) ? detected.getPackageName() : null);
- if (VERIFY) {
- if (mCachedDefaultHome != null && !mCachedDefaultHome.equals(ret)) {
- Slog.e(TAG, "getDefaultHome() cache failure, is " +
- mCachedDefaultHome + " should be " + ret);
- }
- }
- return ret;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- public void invalidateCachedDefaultHome() {
- mCachedDefaultHome = null;
- }
-
- /**
- * Listen for changes in the roles, and invalidate the cached default
- * home as necessary.
- */
- private RoleObserver mRoleObserver;
-
- class RoleObserver implements OnRoleHoldersChangedListener {
- private RoleManager mRm;
- private final Executor mExecutor;
-
- RoleObserver() {
- mExecutor = mContext.getMainExecutor();
- register();
- }
-
- public void register() {
- mRm = mContext.getSystemService(RoleManager.class);
- if (mRm != null) {
- mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
- invalidateCachedDefaultHome();
- }
- }
-
- @Override
- public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
- if (RoleManager.ROLE_HOME.equals(roleName)) {
- invalidateCachedDefaultHome();
- }
- }
- }
-
private boolean isGrantedFullAccess(String pkg, int userId) {
return mPermissions.hasFullAccess(pkg, userId);
}
@@ -635,30 +496,6 @@ public class SliceManagerService extends ISliceManager.Stub {
return mPermissions.getAllPackagesGranted(pkg);
}
- /**
- * Holder that caches a package that has access to a slice.
- */
- static class PackageMatchingCache {
-
- private final Supplier<String> mPkgSource;
- private String mCurrentPkg;
-
- public PackageMatchingCache(Supplier<String> pkgSource) {
- mPkgSource = pkgSource;
- }
-
- public boolean matches(String pkgCandidate) {
- if (pkgCandidate == null) return false;
-
- if (Objects.equals(pkgCandidate, mCurrentPkg)) {
- return true;
- }
- // Failed on cached value, try updating.
- mCurrentPkg = mPkgSource.get();
- return Objects.equals(pkgCandidate, mCurrentPkg);
- }
- }
-
public static class Lifecycle extends SystemService {
private SliceManagerService mService;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5b8078729eee..e4f28546a5fd 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2549,7 +2549,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final Task stack = getRootTask();
final boolean mayAdjustTop = (isState(RESUMED) || stack.mResumedActivity == null)
- && stack.isFocusedStackOnDisplay();
+ && stack.isFocusedStackOnDisplay()
+ // Do not adjust focus task because the task will be reused to launch new activity.
+ && !task.isClearingToReuseTask();
final boolean shouldAdjustGlobalFocus = mayAdjustTop
// It must be checked before {@link #makeFinishingLocked} is called, because a stack
// is not visible if it only contains finishing activities.
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index f7cb0146ea52..15e88fc44746 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2023,8 +2023,6 @@ class ActivityStarter {
// of history or if it is finished immediately), thus disassociating the task. Also note
// that mReuseTask is reset as a result of {@link Task#performClearTaskLocked}
// launching another activity.
- // TODO(b/36119896): We shouldn't trigger activity launches in this path since we are
- // already launching one.
targetTask.performClearTaskLocked();
targetTask.setIntent(mStartActivity);
mAddingToTask = true;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ba5a38290349..affbafa095cc 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1557,7 +1557,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// the heavy operations. This also benefits that the states of multiple activities
// are handled together.
r.linkFixedRotationTransform(prevRotatedLaunchingApp);
- setFixedRotationLaunchingAppUnchecked(r, rotation);
+ if (r != mFixedRotationTransitionListener.mAnimatingRecents) {
+ // Only update the record for normal activity so the display orientation can be
+ // updated when the transition is done if it becomes the top. And the case of
+ // recents can be handled when the recents animation is finished.
+ setFixedRotationLaunchingAppUnchecked(r, rotation);
+ }
return;
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index df5356303f8b..3c64ffb237d6 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1627,8 +1627,8 @@ class RecentTasks {
}
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at "
+ topIndex + " from intial " + taskIndex);
- // Find the end of the chain, doing a sanity check along the way.
- boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
+ // Find the end of the chain, doing a validity check along the way.
+ boolean isValid = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
int endIndex = topIndex;
Task prev = top;
while (endIndex < recentsCount) {
@@ -1640,7 +1640,7 @@ class RecentTasks {
if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) {
Slog.wtf(TAG, "Bad chain @" + endIndex
+ ": first task has next affiliate: " + prev);
- sane = false;
+ isValid = false;
break;
}
} else {
@@ -1652,7 +1652,7 @@ class RecentTasks {
+ " has bad next affiliate "
+ cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId
+ ", expected " + prev);
- sane = false;
+ isValid = false;
break;
}
}
@@ -1662,7 +1662,7 @@ class RecentTasks {
Slog.wtf(TAG, "Bad chain @" + endIndex
+ ": last task " + cur + " has previous affiliate "
+ cur.mPrevAffiliate);
- sane = false;
+ isValid = false;
}
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex);
break;
@@ -1673,7 +1673,7 @@ class RecentTasks {
+ ": task " + cur + " has previous affiliate "
+ cur.mPrevAffiliate + " but should be id "
+ cur.mPrevAffiliate);
- sane = false;
+ isValid = false;
break;
}
}
@@ -1682,7 +1682,7 @@ class RecentTasks {
+ ": task " + cur + " has affiliated id "
+ cur.mAffiliatedTaskId + " but should be "
+ task.mAffiliatedTaskId);
- sane = false;
+ isValid = false;
break;
}
prev = cur;
@@ -1690,18 +1690,18 @@ class RecentTasks {
if (endIndex >= recentsCount) {
Slog.wtf(TAG, "Bad chain ran off index " + endIndex
+ ": last task " + prev);
- sane = false;
+ isValid = false;
break;
}
}
- if (sane) {
+ if (isValid) {
if (endIndex < taskIndex) {
Slog.wtf(TAG, "Bad chain @" + endIndex
+ ": did not extend to task " + task + " @" + taskIndex);
- sane = false;
+ isValid = false;
}
}
- if (sane) {
+ if (isValid) {
// All looks good, we can just move all of the affiliated tasks
// to the top.
for (int i=topIndex; i<=endIndex; i++) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b3a3ed7eeba4..fe2d08f6a4c2 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -737,7 +737,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
winAnimator.mSession.mPid, operation);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- // There was some problem...first, do a sanity check of the window list to make sure
+ // There was some problem...first, do a validity check of the window list to make sure
// we haven't left any dangling surfaces around.
Slog.i(TAG_WM, "Out of memory for surface! Looking for leaks...");
@@ -811,7 +811,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
// "Something has changed! Let's make it correct now."
- // TODO: Super crazy long method that should be broken down...
+ // TODO: Super long method that should be broken down...
void performSurfacePlacementNoTrace() {
if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
+ Debug.getCallers(3));
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ec7b1eed7f91..0529abf89f6e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1836,14 +1836,25 @@ class Task extends WindowContainer<WindowContainer> {
*/
void performClearTaskLocked() {
mReuseTask = true;
- performClearTask("clear-task-all");
- mReuseTask = false;
+ mStackSupervisor.beginDeferResume();
+ try {
+ performClearTask("clear-task-all");
+ } finally {
+ mStackSupervisor.endDeferResume();
+ mReuseTask = false;
+ }
}
ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
mReuseTask = true;
- final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
- mReuseTask = false;
+ mStackSupervisor.beginDeferResume();
+ final ActivityRecord result;
+ try {
+ result = performClearTaskLocked(newR, launchFlags);
+ } finally {
+ mStackSupervisor.endDeferResume();
+ mReuseTask = false;
+ }
return result;
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 68445f6970fb..dbbb7ff69b3b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -27,7 +27,6 @@ import android.annotation.Nullable;
import android.app.ActivityManager.TaskSnapshot;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
-import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.RecordingCanvas;
@@ -82,7 +81,7 @@ class TaskSnapshotController {
/**
* Return value for {@link #getSnapshotMode}: We are not allowed to take a real screenshot but
- * we should try to use the app theme to create a dummy representation of the app.
+ * we should try to use the app theme to create a fake representation of the app.
*/
@VisibleForTesting
static final int SNAPSHOT_MODE_APP_THEME = 1;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b33a8e9ef5df..7624d4c1ea36 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3612,7 +3612,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM, ">>> showStrictModeViolation");
- // TODO: Modify this to use the surface trace once it is not going crazy.
+ // TODO: Modify this to use the surface trace once it is not going baffling.
// b/31532461
// TODO(multi-display): support multiple displays
if (mStrictModeFlash == null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ebbd74aa7d1e..49e623d8dd11 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2456,9 +2456,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
finishInputEvent(event, true);
}
}
- /**
- * Dummy event receiver for windows that died visible.
- */
+ /** Fake event receiver for windows that died visible. */
private DeadWindowEventReceiver mDeadWindowEventReceiver;
void openInputChannel(InputChannel outInputChannel) {
@@ -2476,9 +2474,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mClientChannel.dispose();
mClientChannel = null;
} else {
- // If the window died visible, we setup a dummy input channel, so that taps
+ // If the window died visible, we setup a fake input channel, so that taps
// can still detected by input monitor channel, and we can relaunch the app.
- // Create dummy event receiver that simply reports all events as handled.
+ // Create fake event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 16edb55939a3..92177abbbf85 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -560,9 +560,9 @@ class WindowStateAnimator {
}
}
- // Something is wrong and SurfaceFlinger will not like this, try to revert to sane values.
- // This doesn't necessarily mean that there is an error in the system. The sizes might be
- // incorrect, because it is before the first layout or draw.
+ // Something is wrong and SurfaceFlinger will not like this, try to revert to reasonable
+ // values. This doesn't necessarily mean that there is an error in the system. The sizes
+ // might be incorrect, because it is before the first layout or draw.
if (outSize.width() < 1) {
outSize.right = 1;
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index f7cd37fb6748..bc4d9a973ecb 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -548,7 +548,7 @@ class WindowToken extends WindowContainer<WindowState> {
void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
Configuration config) {
if (mFixedRotationTransformState != null) {
- return;
+ cleanUpFixedRotationTransformState(true /* replacing */);
}
mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
new Configuration(config), mDisplayContent.getRotation());
@@ -565,13 +565,13 @@ class WindowToken extends WindowContainer<WindowState> {
* one. This takes the same effect as {@link #applyFixedRotationTransform}.
*/
void linkFixedRotationTransform(WindowToken other) {
- if (mFixedRotationTransformState != null) {
- return;
- }
final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState;
- if (fixedRotationState == null) {
+ if (fixedRotationState == null || mFixedRotationTransformState == fixedRotationState) {
return;
}
+ if (mFixedRotationTransformState != null) {
+ cleanUpFixedRotationTransformState(true /* replacing */);
+ }
mFixedRotationTransformState = fixedRotationState;
fixedRotationState.mAssociatedTokens.add(this);
onConfigurationChanged(getParent().getConfiguration());
@@ -626,11 +626,17 @@ class WindowToken extends WindowContainer<WindowState> {
// The state is cleared at the end, because it is used to indicate that other windows can
// use seamless rotation when applying rotation to display.
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
- state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState();
+ state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState(
+ false /* replacing */);
}
}
- private void cleanUpFixedRotationTransformState() {
+ private void cleanUpFixedRotationTransformState(boolean replacing) {
+ if (replacing && mFixedRotationTransformState.mAssociatedTokens.size() > 1) {
+ // The state is not only used by self. Make sure to leave the influence by others.
+ mFixedRotationTransformState.mAssociatedTokens.remove(this);
+ mFixedRotationTransformState.mRotatedContainers.remove(this);
+ }
mFixedRotationTransformState = null;
notifyFixedRotationTransform(false /* enabled */);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java
deleted file mode 100644
index f6c854e23494..000000000000
--- a/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.server.slice;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.server.UiServiceTestCase;
-import com.android.server.slice.SliceManagerService.PackageMatchingCache;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.function.Supplier;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class PackageMatchingCacheTest extends UiServiceTestCase {
-
- private final Supplier<String> supplier = mock(Supplier.class);
- private final PackageMatchingCache cache = new PackageMatchingCache(supplier);
-
- @Test
- public void testNulls() {
- // Doesn't get for a null input
- cache.matches(null);
- verify(supplier, never()).get();
-
- // Gets once valid input in sent.
- cache.matches("");
- verify(supplier).get();
- }
-
- @Test
- public void testCaching() {
- when(supplier.get()).thenReturn("ret.pkg");
-
- assertTrue(cache.matches("ret.pkg"));
- assertTrue(cache.matches("ret.pkg"));
- assertTrue(cache.matches("ret.pkg"));
-
- verify(supplier, times(1)).get();
- }
-
- @Test
- public void testGetOnFailure() {
- when(supplier.get()).thenReturn("ret.pkg");
- assertTrue(cache.matches("ret.pkg"));
-
- when(supplier.get()).thenReturn("other.pkg");
- assertTrue(cache.matches("other.pkg"));
- verify(supplier, times(2)).get();
- }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index a4436951f48b..cf1c36c0d243 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -90,8 +90,6 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
@Test
public void testAddPinCreatesPinned() throws RemoteException {
- doReturn("pkg").when(mService).getDefaultHome(anyInt());
-
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
verify(mService, times(1)).createPinnedSlice(eq(maybeAddUserId(TEST_URI, 0)), anyString());
@@ -99,8 +97,6 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
@Test
public void testRemovePinDestroysPinned() throws RemoteException {
- doReturn("pkg").when(mService).getDefaultHome(anyInt());
-
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
when(mCreatedSliceState.unpin(eq("pkg"), eq(mToken))).thenReturn(false);
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 d9c48fc4ba37..e0785c13a336 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -27,6 +27,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -145,29 +146,40 @@ public class WindowTokenTests extends WindowTestsBase {
assertEquals(0, token.getWindowsCount());
}
- @UseTestDisplay(addWindows = { W_ACTIVITY, W_WALLPAPER })
@Test
public void testFinishFixedRotationTransform() {
- final WindowToken appToken = mAppWindow.mToken;
- final WindowToken wallpaperToken = mWallpaperWindow.mToken;
+ final WindowToken[] tokens = new WindowToken[3];
+ for (int i = 0; i < tokens.length; i++) {
+ tokens[i] = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent);
+ }
+
final Configuration config = new Configuration(mDisplayContent.getConfiguration());
final int originalRotation = config.windowConfiguration.getRotation();
final int targetRotation = (originalRotation + 1) % 4;
config.windowConfiguration.setRotation(targetRotation);
- appToken.applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config);
- wallpaperToken.linkFixedRotationTransform(appToken);
+ tokens[0].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config);
+ tokens[1].linkFixedRotationTransform(tokens[0]);
// The window tokens should apply the rotation by the transformation.
- assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation());
- assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation());
+ assertEquals(targetRotation, tokens[0].getWindowConfiguration().getRotation());
+ assertEquals(targetRotation, tokens[1].getWindowConfiguration().getRotation());
+
+ tokens[2].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config);
+ // The tokens[1] was linked to tokens[0], this should make tokens[1] link to tokens[2].
+ tokens[1].linkFixedRotationTransform(tokens[2]);
+
+ // Assume the display doesn't rotate, the transformation will be canceled.
+ tokens[0].finishFixedRotationTransform();
- // The display doesn't rotate, the transformation will be canceled.
- mAppWindow.mToken.finishFixedRotationTransform();
+ // The tokens[0] should restore to the original rotation.
+ assertEquals(originalRotation, tokens[0].getWindowConfiguration().getRotation());
+ // The tokens[1] is linked to tokens[2], it should keep the target rotation.
+ assertNotEquals(originalRotation, tokens[1].getWindowConfiguration().getRotation());
- // The window tokens should restore to the original rotation.
- assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation());
- assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation());
+ tokens[2].finishFixedRotationTransform();
+ // The rotation of tokens[1] should be restored because its linked state is finished.
+ assertEquals(originalRotation, tokens[1].getWindowConfiguration().getRotation());
}
/**
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 2b2608724e12..78dc377a303c 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -46,6 +46,7 @@ import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.ISms;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.SmsRawData;
+import com.android.telephony.Rlog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1953,7 +1954,6 @@ public final class SmsManager {
public boolean enableCellBroadcastRange(int startMessageId, int endMessageId,
@android.telephony.SmsCbMessage.MessageFormat int ranType) {
boolean success = false;
-
if (endMessageId < startMessageId) {
throw new IllegalArgumentException("endMessageId < startMessageId");
}
@@ -1962,10 +1962,14 @@ public final class SmsManager {
if (iSms != null) {
// If getSubscriptionId() returns INVALID or an inactive subscription, we will use
// the default phone internally.
- success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+ int subId = getSubscriptionId();
+ success = iSms.enableCellBroadcastRangeForSubscriber(subId,
startMessageId, endMessageId, ranType);
+ Rlog.d(TAG, "enableCellBroadcastRange: " + (success ? "succeeded" : "failed")
+ + " at calling enableCellBroadcastRangeForSubscriber. subId = " + subId);
}
} catch (RemoteException ex) {
+ Rlog.d(TAG, "enableCellBroadcastRange: " + ex.getStackTrace());
// ignore it
}
@@ -2019,10 +2023,14 @@ public final class SmsManager {
if (iSms != null) {
// If getSubscriptionId() returns INVALID or an inactive subscription, we will use
// the default phone internally.
- success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+ int subId = getSubscriptionId();
+ success = iSms.disableCellBroadcastRangeForSubscriber(subId,
startMessageId, endMessageId, ranType);
+ Rlog.d(TAG, "disableCellBroadcastRange: " + (success ? "succeeded" : "failed")
+ + " at calling disableCellBroadcastRangeForSubscriber. subId = " + subId);
}
} catch (RemoteException ex) {
+ Rlog.d(TAG, "disableCellBroadcastRange: " + ex.getStackTrace());
// ignore it
}