diff options
39 files changed, 702 insertions, 413 deletions
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index f951d2b89958..745add174582 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -17,6 +17,7 @@ package android.content; import android.annotation.IntDef; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; @@ -40,6 +41,7 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -766,16 +768,30 @@ public class IntentFilter implements Parcelable { * @return True if the action is listed in the filter. */ public final boolean matchAction(String action) { - return matchAction(action, false); + return matchAction(action, false /*wildcardSupported*/, null /*ignoreActions*/); } /** * Variant of {@link #matchAction(String)} that allows a wildcard for the provided action. * @param wildcardSupported if true, will allow action to use wildcards - */ - private boolean matchAction(String action, boolean wildcardSupported) { - if (wildcardSupported && !mActions.isEmpty() && WILDCARD.equals(action)) { - return true; + * @param ignoreActions if not null, the set of actions to should not be considered valid while + * calculating the match + */ + private boolean matchAction(String action, boolean wildcardSupported, + @Nullable Collection<String> ignoreActions) { + if (wildcardSupported && WILDCARD.equals(action)) { + if (ignoreActions == null) { + return !mActions.isEmpty(); + } + for (int i = mActions.size() - 1; i >= 0; i--) { + if (!ignoreActions.contains(mActions.get(i))) { + return true; + } + } + return false; + } + if (ignoreActions != null && ignoreActions.contains(action)) { + return false; } return hasAction(action); } @@ -1779,17 +1795,24 @@ public class IntentFilter implements Parcelable { */ public final int match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag) { - return match(action, type, scheme, data, categories, logTag, false /*supportWildcards*/); + return match(action, type, scheme, data, categories, logTag, false /*supportWildcards*/, + null /*ignoreActions*/); } /** * Variant of {@link #match(ContentResolver, Intent, boolean, String)} that supports wildcards * in the action, type, scheme, host and path. - * @hide if true, will allow supported parameters to use wildcards to match this filter + * @param supportWildcards if true, will allow supported parameters to use wildcards to match + * this filter + * @param ignoreActions a collection of actions that, if not null should be ignored and not used + * if provided as the matching action or the set of actions defined by this + * filter + * @hide */ public final int match(String action, String type, String scheme, - Uri data, Set<String> categories, String logTag, boolean supportWildcards) { - if (action != null && !matchAction(action, supportWildcards)) { + Uri data, Set<String> categories, String logTag, boolean supportWildcards, + @Nullable Collection<String> ignoreActions) { + if (action != null && !matchAction(action, supportWildcards, ignoreActions)) { if (false) Log.v( logTag, "No matching action " + action + " for " + this); return NO_MATCH_ACTION; diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 174165c5ba59..cfceb031539f 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -50,6 +50,22 @@ public class SurfaceControlViewHost { * elements. It's expected to get this object from * {@link SurfaceControlViewHost#getSurfacePackage} afterwards it can be embedded within * a SurfaceView by calling {@link SurfaceView#setChildSurfacePackage}. + * + * Note that each {@link SurfacePackage} must be released by calling + * {@link SurfacePackage#release}. However, if you use the recommended flow, + * the framework will automatically handle the lifetime for you. + * + * 1. When sending the package to the remote process, return it from an AIDL method + * or manually use FLAG_WRITE_RETURN_VALUE in writeToParcel. This will automatically + * release the package in the local process. + * 2. In the remote process, consume the package using SurfaceView. This way the + * SurfaceView will take over the lifetime and call {@link SurfacePackage#release} + * for the user. + * + * One final note: The {@link SurfacePackage} lifetime is totally de-coupled + * from the lifetime of the underlying {@link SurfaceControlViewHost}. Regardless + * of the lifetime of the package the user should still call + * {@link SurfaceControlViewHost#release} when finished. */ public static final class SurfacePackage implements Parcelable { private SurfaceControl mSurfaceControl; diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index b677ccd9a618..9880ea096cf2 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1650,11 +1650,24 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall /** * Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage} - * within this SurfaceView. If this SurfaceView is above it's host Surface (see + * within this SurfaceView. + * + * This can be called independently of the SurfaceView lifetime callbacks. SurfaceView + * will internally manage reparenting the package to our Surface as it is created + * and destroyed. + * + * If this SurfaceView is above its host Surface (see * {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive - * input. This will take ownership of the SurfaceControl contained inside the SurfacePackage + * input. + * + * This will take ownership of the SurfaceControl contained inside the SurfacePackage * and free the caller of the obligation to call - * {@link SurfaceControlViewHost.SurfacePackage#release}. + * {@link SurfaceControlViewHost.SurfacePackage#release}. However, note that + * {@link SurfaceControlViewHost.SurfacePackage#release} and + * {@link SurfaceControlViewHost#release} are not the same. While the ownership + * of this particular {@link SurfaceControlViewHost.SurfacePackage} will be taken by the + * SurfaceView the underlying {@link SurfaceControlViewHost} remains managed by it's original + * remote-owner. * * @param p The SurfacePackage to embed. */ diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 0eadcc741747..f63365bcd369 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -45,6 +45,7 @@ android_library { "WindowManager-Shell", "SystemUIPluginLib", "SystemUISharedLib", + "SystemUI-statsd", "SettingsLib", "androidx.viewpager2_viewpager2", "androidx.legacy_legacy-support-v4", @@ -81,6 +82,8 @@ filegroup { "tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java", "tests/src/com/android/systemui/statusbar/RankingBuilder.java", "tests/src/com/android/systemui/statusbar/SbnBuilder.java", + "tests/src/com/android/systemui/util/concurrency/FakeExecutor.java", + "tests/src/com/android/systemui/util/time/FakeSystemClock.java", ], path: "tests/src", } @@ -106,6 +109,7 @@ android_library { static_libs: [ "SystemUIPluginLib", "SystemUISharedLib", + "SystemUI-statsd", "SettingsLib", "androidx.viewpager2_viewpager2", "androidx.legacy_legacy-support-v4", diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index fe6e44b5de0a..592f6c2a0dff 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -36,7 +36,6 @@ android_library { static_libs: [ "PluginCoreLib", - "SystemUI-statsd", ], // Enforce that the library is built against java 7 so that there are diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java index 13d6a9bef266..6923079dd5c4 100644 --- a/packages/SystemUI/src/com/android/systemui/Interpolators.java +++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java @@ -49,8 +49,6 @@ public class Interpolators { public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f); public static final Interpolator HEADS_UP_APPEAR = new HeadsUpAppearInterpolator(); public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f); - public static final Interpolator SHADE_ANIMATION = - new PathInterpolator(0.6f, 0.02f, 0.4f, 0.98f); public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f, 1.1f); public static final Interpolator PANEL_CLOSE_ACCELERATED diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 3f095dc0510e..4db5374cd566 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1638,7 +1638,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private static final int MESSAGE_REFRESH = 1; private static final int MESSAGE_SHOW = 2; private static final int DIALOG_DISMISS_DELAY = 300; // ms - private static final int DIALOG_PRESS_DELAY = 500; // ms + private static final int DIALOG_PRESS_DELAY = 850; // ms @VisibleForTesting void setZeroDialogPressDelayForTesting() { mDialogPressDelay = 0; // ms diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index bc1c1e12203e..2f582727c766 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -38,6 +38,7 @@ import com.android.systemui.R; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.statusbar.policy.LocationController; import java.text.DateFormat; import java.time.LocalTime; @@ -60,12 +61,14 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements private static final String PATTERN_HOUR_NINUTE_24 = "HH:mm"; private final ColorDisplayManager mManager; + private final LocationController mLocationController; private NightDisplayListener mListener; private boolean mIsListening; @Inject - public NightDisplayTile(QSHost host) { + public NightDisplayTile(QSHost host, LocationController locationController) { super(host); + mLocationController = locationController; mManager = mContext.getSystemService(ColorDisplayManager.class); mListener = new NightDisplayListener(mContext, new Handler(Looper.myLooper())); } @@ -132,6 +135,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements private String getSecondaryLabel(boolean isNightLightActivated) { switch (mManager.getNightDisplayAutoMode()) { case ColorDisplayManager.AUTO_MODE_TWILIGHT: + if (!mLocationController.isLocationEnabled()) return null; // Auto mode related to sunrise & sunset. If the light is on, it's guaranteed to be // turned off at sunrise. If it's off, it's guaranteed to be turned on at sunset. return isNightLightActivated diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index b90ca01df481..7b83c20d4b86 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -31,6 +31,7 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.LocationController; import java.time.LocalTime; import java.time.format.DateTimeFormatter; @@ -51,13 +52,15 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements com.android.internal.R.drawable.ic_qs_ui_mode_night); private final UiModeManager mUiModeManager; private final BatteryController mBatteryController; + private final LocationController mLocationController; @Inject public UiModeNightTile(QSHost host, ConfigurationController configurationController, - BatteryController batteryController) { + BatteryController batteryController, LocationController locationController) { super(host); mBatteryController = batteryController; mUiModeManager = mContext.getSystemService(UiModeManager.class); + mLocationController = locationController; configurationController.observe(getLifecycle(), this); batteryController.observe(getLifecycle(), this); } @@ -97,7 +100,8 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements if (powerSave) { state.secondaryLabel = mContext.getResources().getString( R.string.quick_settings_dark_mode_secondary_label_battery_saver); - } else if (uiMode == UiModeManager.MODE_NIGHT_AUTO) { + } else if (uiMode == UiModeManager.MODE_NIGHT_AUTO + && mLocationController.isLocationEnabled()) { state.secondaryLabel = mContext.getResources().getString(nightMode ? R.string.quick_settings_dark_mode_secondary_label_until_sunrise : R.string.quick_settings_dark_mode_secondary_label_on_at_sunset); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index 729f934937da..0d7715958995 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -21,7 +21,6 @@ import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.app.WallpaperManager import android.util.Log -import android.util.MathUtils import android.view.Choreographer import android.view.View import androidx.annotation.VisibleForTesting @@ -252,10 +251,7 @@ class NotificationShadeDepthController @Inject constructor( var newBlur = 0 val state = statusBarStateController.state if (state == StatusBarState.SHADE || state == StatusBarState.SHADE_LOCKED) { - val animatedBlur = - Interpolators.SHADE_ANIMATION.getInterpolation( - MathUtils.constrain(shadeExpansion / 0.15f, 0f, 1f)) - newBlur = blurUtils.blurRadiusOfRatio(0.35f * animatedBlur + 0.65f * shadeExpansion) + newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion) } shadeSpring.animateTo(newBlur) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 9324b14bf211..d37e16b17620 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -88,14 +88,11 @@ import dagger.Lazy; * @see #getActiveNotificationUnfiltered(String) to check if a key exists * @see #getPendingNotificationsIterator() for an iterator over the pending notifications * @see #getPendingOrActiveNotif(String) to find a notification exists for that key in any list - * @see #getPendingAndActiveNotifications() to get the entire set of Notifications that we're - * aware of * @see #getActiveNotificationsForCurrentUser() to see every notification that the current user owns */ public class NotificationEntryManager implements CommonNotifCollection, Dumpable, - InflationCallback, VisualStabilityManager.Callback { private static final String TAG = "NotificationEntryMgr"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -309,12 +306,7 @@ public class NotificationEntryManager implements * * WARNING: this will call back into us. Don't hold any locks. */ - @Override - public void handleInflationException(NotificationEntry n, Exception e) { - handleInflationException(n.getSbn(), e); - } - - public void handleInflationException(StatusBarNotification n, Exception e) { + private void handleInflationException(StatusBarNotification n, Exception e) { removeNotificationInternal( n.getKey(), null, null, true /* forceRemove */, false /* removedByUser */, REASON_ERROR); @@ -323,30 +315,37 @@ public class NotificationEntryManager implements } } - @Override - public void onAsyncInflationFinished(NotificationEntry entry) { - mPendingNotifications.remove(entry.getKey()); - // If there was an async task started after the removal, we don't want to add it back to - // the list, otherwise we might get leaks. - if (!entry.isRowRemoved()) { - boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null; - mLogger.logNotifInflated(entry.getKey(), isNew); - if (isNew) { - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryInflated(entry); - } - addActiveNotification(entry); - updateNotifications("onAsyncInflationFinished"); - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onNotificationAdded(entry); - } - } else { - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryReinflated(entry); + private final InflationCallback mInflationCallback = new InflationCallback() { + @Override + public void handleInflationException(NotificationEntry entry, Exception e) { + NotificationEntryManager.this.handleInflationException(entry.getSbn(), e); + } + + @Override + public void onAsyncInflationFinished(NotificationEntry entry) { + mPendingNotifications.remove(entry.getKey()); + // If there was an async task started after the removal, we don't want to add it back to + // the list, otherwise we might get leaks. + if (!entry.isRowRemoved()) { + boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null; + mLogger.logNotifInflated(entry.getKey(), isNew); + if (isNew) { + for (NotificationEntryListener listener : mNotificationEntryListeners) { + listener.onEntryInflated(entry); + } + addActiveNotification(entry); + updateNotifications("onAsyncInflationFinished"); + for (NotificationEntryListener listener : mNotificationEntryListeners) { + listener.onNotificationAdded(entry); + } + } else { + for (NotificationEntryListener listener : mNotificationEntryListeners) { + listener.onEntryReinflated(entry); + } } } } - } + }; private final NotificationHandler mNotifListener = new NotificationHandler() { @Override @@ -558,6 +557,10 @@ public class NotificationEntryManager implements ranking, mFgsFeatureController.isForegroundServiceDismissalEnabled(), SystemClock.uptimeMillis()); + for (NotifCollectionListener listener : mNotifCollectionListeners) { + listener.onEntryBind(entry, notification); + } + mAllNotifications.add(entry); mLeakDetector.trackInstance(entry); @@ -568,8 +571,10 @@ public class NotificationEntryManager implements // Construct the expanded view. if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { mNotificationRowBinderLazy.get() - .inflateViews(entry, () -> performRemoveNotification(notification, - REASON_CANCEL)); + .inflateViews( + entry, + () -> performRemoveNotification(notification, REASON_CANCEL), + mInflationCallback); } abortExistingInflation(key, "addNotification"); @@ -612,7 +617,9 @@ public class NotificationEntryManager implements updateRankingAndSort(ranking, "updateNotificationInternal"); StatusBarNotification oldSbn = entry.getSbn(); entry.setSbn(notification); - mGroupManager.onEntryUpdated(entry, oldSbn); + for (NotifCollectionListener listener : mNotifCollectionListeners) { + listener.onEntryBind(entry, notification); + } mGroupManager.onEntryUpdated(entry, oldSbn); mLogger.logNotifUpdated(entry.getKey()); for (NotificationEntryListener listener : mNotificationEntryListeners) { @@ -624,8 +631,10 @@ public class NotificationEntryManager implements if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { mNotificationRowBinderLazy.get() - .inflateViews(entry, () -> performRemoveNotification(notification, - REASON_CANCEL)); + .inflateViews( + entry, + () -> performRemoveNotification(notification, REASON_CANCEL), + mInflationCallback); } updateNotifications("updateNotificationInternal"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index 365862bef871..a3621b6cabf6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -65,6 +65,7 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent; import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer; import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler; +import com.android.systemui.statusbar.notification.collection.notifcollection.BindEntryEvent; import com.android.systemui.statusbar.notification.collection.notifcollection.CleanUpEntryEvent; import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; @@ -389,6 +390,7 @@ public class NotifCollection implements Dumpable { if (entry == null) { // A new notification! entry = new NotificationEntry(sbn, ranking, SystemClock.uptimeMillis()); + mEventQueue.add(new BindEntryEvent(entry, sbn)); mNotificationSet.put(sbn.getKey(), entry); mLogger.logNotifPosted(sbn.getKey()); @@ -409,6 +411,7 @@ public class NotifCollection implements Dumpable { entry.mCancellationReason = REASON_NOT_CANCELED; entry.setSbn(sbn); + mEventQueue.add(new BindEntryEvent(entry, sbn)); mLogger.logNotifUpdated(sbn.getKey()); mEventQueue.add(new EntryUpdatedEvent(entry)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java index 1f6413b525cb..d081e114855e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java @@ -47,7 +47,6 @@ public class NotifInflaterImpl implements NotifInflater { private final NotifPipeline mNotifPipeline; private NotificationRowBinderImpl mNotificationRowBinder; - private InflationCallback mExternalInflationCallback; @Inject public NotifInflaterImpl( @@ -66,17 +65,11 @@ public class NotifInflaterImpl implements NotifInflater { */ public void setRowBinder(NotificationRowBinderImpl rowBinder) { mNotificationRowBinder = rowBinder; - mNotificationRowBinder.setInflationCallback(mInflationCallback); } @Override - public void setInflationCallback(InflationCallback callback) { - mExternalInflationCallback = callback; - } - - @Override - public void rebindViews(NotificationEntry entry) { - inflateViews(entry); + public void rebindViews(NotificationEntry entry, InflationCallback callback) { + inflateViews(entry, callback); } /** @@ -84,11 +77,14 @@ public class NotifInflaterImpl implements NotifInflater { * views are bound. */ @Override - public void inflateViews(NotificationEntry entry) { + public void inflateViews(NotificationEntry entry, InflationCallback callback) { try { - requireBinder().inflateViews(entry, getDismissCallback(entry)); + requireBinder().inflateViews( + entry, + getDismissCallback(entry), + wrapInflationCallback(callback)); } catch (InflationException e) { - // logged in mInflationCallback.handleInflationException + mNotifErrorManager.setInflationError(entry, e); } } @@ -121,6 +117,26 @@ public class NotifInflaterImpl implements NotifInflater { }; } + private NotificationContentInflater.InflationCallback wrapInflationCallback( + InflationCallback callback) { + return new NotificationContentInflater.InflationCallback() { + @Override + public void handleInflationException( + NotificationEntry entry, + Exception e) { + mNotifErrorManager.setInflationError(entry, e); + } + + @Override + public void onAsyncInflationFinished(NotificationEntry entry) { + mNotifErrorManager.clearInflationError(entry); + if (callback != null) { + callback.onInflationFinished(entry); + } + } + }; + } + private NotificationRowBinderImpl requireBinder() { if (mNotificationRowBinder == null) { throw new RuntimeException("NotificationRowBinder must be attached before using " @@ -128,22 +144,4 @@ public class NotifInflaterImpl implements NotifInflater { } return mNotificationRowBinder; } - - private final NotificationContentInflater.InflationCallback mInflationCallback = - new NotificationContentInflater.InflationCallback() { - @Override - public void handleInflationException( - NotificationEntry entry, - Exception e) { - mNotifErrorManager.setInflationError(entry, e); - } - - @Override - public void onAsyncInflationFinished(NotificationEntry entry) { - mNotifErrorManager.clearInflationError(entry); - if (mExternalInflationCallback != null) { - mExternalInflationCallback.onInflationFinished(entry); - } - } - }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 68ec34e90760..749c3e4c9d0d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -408,15 +408,6 @@ public final class NotificationEntry extends ListEntry { return wasBubble != isBubble(); } - /** - * Resets the notification entry to be re-used. - */ - public void reset() { - if (row != null) { - row.reset(); - } - } - @NotificationSectionsManager.PriorityBucket public int getBucket() { return mBucket; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt new file mode 100644 index 000000000000..1c1b2bb087f0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt @@ -0,0 +1,56 @@ +/* + * 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.collection + +import android.content.Context +import android.content.pm.PackageManager +import android.service.notification.StatusBarNotification +import android.util.Log +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener +import com.android.systemui.statusbar.phone.StatusBar +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class TargetSdkResolver @Inject constructor( + private val context: Context, + private val collection: CommonNotifCollection +) { + init { + collection.addCollectionListener(object : NotifCollectionListener { + override fun onEntryBind(entry: NotificationEntry, sbn: StatusBarNotification) { + entry.targetSdk = resolveNotificationSdk(sbn) + } + }) + } + + private fun resolveNotificationSdk(sbn: StatusBarNotification): Int { + val pmUser = StatusBar.getPackageManagerForUser(context, sbn.user.identifier) + var targetSdk = 0 + // Extract target SDK version. + try { + val info = pmUser.getApplicationInfo(sbn.packageName, 0) + targetSdk = info.targetSdkVersion + } catch (ex: PackageManager.NameNotFoundException) { + Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.packageName, ex) + } + return targetSdk + } + + private val TAG = "TargetSdkResolver" +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 9973ef9ae14e..0e8dd5e24e91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -72,7 +72,6 @@ public class PreparationCoordinator implements Coordinator { ) { mLogger = logger; mNotifInflater = notifInflater; - mNotifInflater.setInflationCallback(mInflationCallback); mNotifErrorManager = errorManager; mNotifErrorManager.addInflationErrorListener(mInflationErrorListener); mViewBarn = viewBarn; @@ -218,11 +217,11 @@ public class PreparationCoordinator implements Coordinator { private void inflateEntry(NotificationEntry entry, String reason) { abortInflation(entry, reason); - mNotifInflater.inflateViews(entry); + mNotifInflater.inflateViews(entry, mInflationCallback); } private void rebind(NotificationEntry entry, String reason) { - mNotifInflater.rebindViews(entry); + mNotifInflater.rebindViews(entry, mInflationCallback); } private void abortInflation(NotificationEntry entry, String reason) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java index ea0ece444a67..e3d76113d537 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java @@ -24,22 +24,20 @@ import com.android.systemui.statusbar.notification.collection.coordinator.Prepar * main thread. When the inflation is finished, NotifInflater will trigger its InflationCallback. */ public interface NotifInflater { - - /** - * Callback used when inflation is finished. - */ - void setInflationCallback(InflationCallback callback); - /** * Called to rebind the entry's views. + * + * @param callback callback called after inflation finishes */ - void rebindViews(NotificationEntry entry); + void rebindViews(NotificationEntry entry, InflationCallback callback); /** * Called to inflate the views of an entry. Views are not considered inflated until all of its * views are bound. Once all views are inflated, the InflationCallback is triggered. + * + * @param callback callback called after inflation finishes */ - void inflateViews(NotificationEntry entry); + void inflateViews(NotificationEntry entry, InflationCallback callback); /** * Request to stop the inflation of an entry. For example, called when a notification is diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java index 3f500644b184..f4c4924b4b9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java @@ -22,6 +22,7 @@ import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; /** * Used by the {@link NotificationEntryManager}. When notifications are added or updated, the binder @@ -37,7 +38,8 @@ public interface NotificationRowBinder { */ void inflateViews( NotificationEntry entry, - Runnable onDismissRunnable) + Runnable onDismissRunnable, + NotificationRowContentBinder.InflationCallback callback) throws InflationException; /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index 32f1822804f8..73f12f86e52e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -16,13 +16,11 @@ package com.android.systemui.statusbar.notification.collection.inflation; +import static java.util.Objects.requireNonNull; + import android.annotation.Nullable; import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; import android.os.Build; -import android.service.notification.StatusBarNotification; -import android.util.Log; import android.view.ViewGroup; import com.android.internal.util.NotificationMessagingUtil; @@ -44,9 +42,6 @@ import com.android.systemui.statusbar.notification.row.RowContentBindStage; import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.phone.StatusBar; - -import java.util.Objects; import javax.inject.Inject; import javax.inject.Provider; @@ -72,7 +67,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { private NotificationPresenter mPresenter; private NotificationListContainer mListContainer; - private NotificationRowContentBinder.InflationCallback mInflationCallback; private BindRowCallback mBindRowCallback; private NotificationClicker mNotificationClicker; @@ -113,10 +107,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { mIconManager.attach(); } - public void setInflationCallback(NotificationRowContentBinder.InflationCallback callback) { - mInflationCallback = callback; - } - public void setNotificationClicker(NotificationClicker clicker) { mNotificationClicker = clicker; } @@ -125,17 +115,19 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { * Inflates the views for the given entry (possibly asynchronously). */ @Override - public void inflateViews(NotificationEntry entry, Runnable onDismissRunnable) + public void inflateViews( + NotificationEntry entry, + Runnable onDismissRunnable, + NotificationRowContentBinder.InflationCallback callback) throws InflationException { ViewGroup parent = mListContainer.getViewParentForNotification(entry); - PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext, - entry.getSbn().getUser().getIdentifier()); - final StatusBarNotification sbn = entry.getSbn(); if (entry.rowExists()) { mIconManager.updateIcons(entry); - entry.reset(); - updateNotification(entry, pmUser, sbn, entry.getRow()); + ExpandableNotificationRow row = entry.getRow(); + row.reset(); + updateRow(entry, row); + inflateContentViews(entry, row, callback); entry.getRowController().setOnDismissRunnable(onDismissRunnable); } else { mIconManager.createIcons(entry); @@ -147,7 +139,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { .expandableNotificationRow(row) .notificationEntry(entry) .onDismissRunnable(onDismissRunnable) - .inflationCallback(mInflationCallback) .rowContentBindStage(mRowContentBindStage) .onExpandClickListener(mPresenter) .build(); @@ -155,26 +146,34 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { component.getExpandableNotificationRowController(); rowController.init(); entry.setRowController(rowController); - bindRow(entry, pmUser, sbn, row); - updateNotification(entry, pmUser, sbn, row); + bindRow(entry, row); + updateRow(entry, row); + inflateContentViews(entry, row, callback); }); } } - //TODO: This method associates a row with an entry, but eventually needs to not do that - private void bindRow(NotificationEntry entry, PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row) { + /** + * Bind row to various controllers and managers. This is only called when the row is first + * created. + * + * TODO: This method associates a row with an entry, but eventually needs to not do that + */ + private void bindRow(NotificationEntry entry, ExpandableNotificationRow row) { mListContainer.bindRow(row); mNotificationRemoteInputManager.bindRow(row); + row.setOnActivatedListener(mPresenter); entry.setRow(row); row.setEntry(entry); mNotifBindPipeline.manageRow(entry, row); - mBindRowCallback.onBindRow(entry, pmUser, sbn, row); + mBindRowCallback.onBindRow(row); } /** * Updates the views bound to an entry when the entry's ranking changes, either in-place or by * reinflating them. + * + * TODO: Should this method be in this class? */ @Override public void onNotificationRankingUpdated( @@ -184,11 +183,10 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { NotificationUiAdjustment newAdjustment) { if (NotificationUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) { if (entry.rowExists()) { - entry.reset(); - PackageManager pmUser = StatusBar.getPackageManagerForUser( - mContext, - entry.getSbn().getUser().getIdentifier()); - updateNotification(entry, pmUser, entry.getSbn(), entry.getRow()); + ExpandableNotificationRow row = entry.getRow(); + row.reset(); + updateRow(entry, row); + inflateContentViews(entry, row, null /* callback */); } else { // Once the RowInflaterTask is done, it will pick up the updated entry, so // no-op here. @@ -202,59 +200,53 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { } } - private void updateNotification( + /** + * Update row after the notification has updated. + * + * @param entry notification that has updated + */ + private void updateRow( NotificationEntry entry, - PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row) { - - // Extract target SDK version. - try { - ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0); - entry.targetSdk = info.targetSdkVersion; - } catch (PackageManager.NameNotFoundException ex) { - Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex); - } row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP); - // TODO: should this be happening somewhere else? - mIconManager.updateIconTags(entry, entry.targetSdk); - - row.setOnActivatedListener(mPresenter); + // bind the click event to the content area + requireNonNull(mNotificationClicker).register(row, entry.getSbn()); + } + /** + * Inflate the row's basic content views. + */ + private void inflateContentViews( + NotificationEntry entry, + ExpandableNotificationRow row, + NotificationRowContentBinder.InflationCallback inflationCallback) { final boolean useIncreasedCollapsedHeight = - mMessagingUtil.isImportantMessaging(sbn, entry.getImportance()); + mMessagingUtil.isImportantMessaging(entry.getSbn(), entry.getImportance()); final boolean isLowPriority = entry.isAmbient(); RowContentBindParams params = mRowContentBindStage.getStageParams(entry); params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight); params.setUseLowPriority(entry.isAmbient()); - //TODO: Replace this API with RowContentBindParams directly + // TODO: Replace this API with RowContentBindParams directly. Also move to a separate + // redaction controller. row.setNeedsRedaction(mNotificationLockscreenUserManager.needsRedaction(entry)); + params.rebindAllContentViews(); mRowContentBindStage.requestRebind(entry, en -> { row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight); row.setIsLowPriority(isLowPriority); - mInflationCallback.onAsyncInflationFinished(en); + inflationCallback.onAsyncInflationFinished(en); }); - - // bind the click event to the content area - Objects.requireNonNull(mNotificationClicker).register(row, sbn); } /** Callback for when a row is bound to an entry. */ public interface BindRowCallback { /** - * Called when a new notification and row is created. - * - * @param entry entry for the notification - * @param pmUser package manager for user - * @param sbn notification - * @param row row for the notification + * Called when a new row is created and bound to a notification. */ - void onBindRow(NotificationEntry entry, PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row); + void onBindRow(ExpandableNotificationRow row); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java index 41ca52d5a626..59f119e987b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection.notifcollection; import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -25,6 +26,15 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; * Listener interface for {@link NotificationEntry} events. */ public interface NotifCollectionListener { + + /** + * Called when the entry is having a new status bar notification bound to it. This should + * be used to initialize any derivative state on the entry that needs to update when the + * notification is updated. + */ + default void onEntryBind(NotificationEntry entry, StatusBarNotification sbn) { + } + /** * Called whenever a new {@link NotificationEntry} is initialized. This should be used for * initializing any decorated state tied to the notification. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt index 2ef0368061ba..2810b891373f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection.notifcollection import android.service.notification.NotificationListenerService.RankingMap +import android.service.notification.StatusBarNotification import com.android.systemui.statusbar.notification.collection.NotifCollection import com.android.systemui.statusbar.notification.collection.NotificationEntry @@ -37,6 +38,15 @@ sealed class NotifEvent { abstract fun dispatchToListener(listener: NotifCollectionListener) } +data class BindEntryEvent( + val entry: NotificationEntry, + val sbn: StatusBarNotification +) : NotifEvent() { + override fun dispatchToListener(listener: NotifCollectionListener) { + listener.onEntryBind(entry, sbn) + } +} + data class InitEntryEvent( val entry: NotificationEntry ) : NotifEvent() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt index da8ad2da5c87..08be4f872415 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt @@ -172,18 +172,6 @@ class IconManager @Inject constructor( } } - /** - * Updates tags on the icon views to match the posting app's target SDK level - * - * Note that this method MUST be called after both [createIcons] and [updateIcons]. - */ - fun updateIconTags(entry: NotificationEntry, targetSdk: Int) { - setTagOnIconViews( - entry.icons, - R.id.icon_is_pre_L, - targetSdk < Build.VERSION_CODES.LOLLIPOP) - } - private fun updateIconsSafe(entry: NotificationEntry) { try { updateIcons(entry) @@ -259,6 +247,7 @@ class IconManager @Inject constructor( iconView: StatusBarIconView ) { iconView.setShowsConversation(showsConversation(entry, iconView, iconDescriptor)) + iconView.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) if (!iconView.set(iconDescriptor)) { throw InflationException("Couldn't create icon $iconDescriptor") } @@ -326,20 +315,13 @@ class IconManager @Inject constructor( val usedInSensitiveContext = iconView === entry.icons.shelfIcon || iconView === entry.icons.aodIcon val isSmallIcon = iconDescriptor.icon.equals(entry.sbn.notification.smallIcon) - return isImportantConversation(entry) && !isSmallIcon - && (!usedInSensitiveContext || !entry.isSensitive) + return isImportantConversation(entry) && !isSmallIcon && + (!usedInSensitiveContext || !entry.isSensitive) } private fun isImportantConversation(entry: NotificationEntry): Boolean { return entry.ranking.channel != null && entry.ranking.channel.isImportantConversation } - - private fun setTagOnIconViews(icons: IconPack, key: Int, tag: Any) { - icons.statusBarIcon?.setTag(key, tag) - icons.shelfIcon?.setTag(key, tag) - icons.aodIcon?.setTag(key, tag) - icons.centeredIcon?.setTag(key, tag) - } } private const val TAG = "IconManager"
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index d1cceaeb6dd5..5fac5b1cf159 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -108,8 +108,6 @@ class NotificationsControllerImpl @Inject constructor( if (featureFlags.isNewNotifPipelineRenderingEnabled) { // TODO } else { - notificationRowBinder.setInflationCallback(entryManager) - remoteInputUriController.attach(entryManager) groupAlertTransferHelper.bind(entryManager, groupManager) headsUpManager.addListener(groupManager) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index 8b3d06b97882..f8d9c4648ac9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -60,7 +60,6 @@ public class ExpandableNotificationRowController { private final HeadsUpManager mHeadsUpManager; private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener; private final StatusBarStateController mStatusBarStateController; - private final NotificationRowContentBinder.InflationCallback mInflationCallback; private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger = this::logNotificationExpansion; @@ -82,7 +81,6 @@ public class ExpandableNotificationRowController { NotificationLogger notificationLogger, HeadsUpManager headsUpManager, ExpandableNotificationRow.OnExpandClickListener onExpandClickListener, StatusBarStateController statusBarStateController, - NotificationRowContentBinder.InflationCallback inflationCallback, NotificationGutsManager notificationGutsManager, @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, @DismissRunnable Runnable onDismissRunnable, FalsingManager falsingManager, @@ -101,7 +99,6 @@ public class ExpandableNotificationRowController { mHeadsUpManager = headsUpManager; mOnExpandClickListener = onExpandClickListener; mStatusBarStateController = statusBarStateController; - mInflationCallback = inflationCallback; mNotificationGutsManager = notificationGutsManager; mOnDismissRunnable = onDismissRunnable; mOnAppOpsClickListener = mNotificationGutsManager::openGuts; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java index 6d6d3e446f53..9846f2dcd170 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java @@ -25,7 +25,6 @@ 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.ExpandableNotificationRowController; -import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; import com.android.systemui.statusbar.notification.row.RowContentBindStage; import com.android.systemui.statusbar.phone.StatusBar; @@ -60,8 +59,6 @@ public interface ExpandableNotificationRowComponent { @BindsInstance Builder rowContentBindStage(RowContentBindStage rowContentBindStage); @BindsInstance - Builder inflationCallback(NotificationRowContentBinder.InflationCallback inflationCallback); - @BindsInstance Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter); ExpandableNotificationRowComponent build(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 79cea91b8612..aecbb9097c7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -22,7 +22,6 @@ import static com.android.systemui.statusbar.phone.StatusBar.SPEW; import android.annotation.Nullable; import android.app.KeyguardManager; import android.content.Context; -import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.ServiceManager; import android.service.notification.StatusBarNotification; @@ -355,8 +354,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } @Override - public void onBindRow(NotificationEntry entry, PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row) { + public void onBindRow(ExpandableNotificationRow row) { row.setAboveShelfChangedListener(mAboveShelfObserver); row.setSecureStateProvider(mKeyguardStateController::canDismissLockScreen); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt deleted file mode 100644 index d522f903c83a..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 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 - -import com.android.systemui.statusbar.FeatureFlags -import com.android.systemui.statusbar.NotificationPresenter -import com.android.systemui.statusbar.NotificationRemoteInputManager -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.collection.NotificationRankingManager -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder -import com.android.systemui.statusbar.phone.NotificationGroupManager -import com.android.systemui.util.leak.LeakDetector -import java.util.concurrent.CountDownLatch - -/** - * Enable some test capabilities for NEM without making everything public on the base class - */ -class TestableNotificationEntryManager( - logger: NotificationEntryManagerLogger, - gm: NotificationGroupManager, - rm: NotificationRankingManager, - ke: KeyguardEnvironment, - ff: FeatureFlags, - rb: dagger.Lazy<NotificationRowBinder>, - notificationRemoteInputManagerLazy: dagger.Lazy<NotificationRemoteInputManager>, - leakDetector: LeakDetector, - fgsFeatureController: ForegroundServiceDismissalFeatureController -) : NotificationEntryManager(logger, gm, rm, ke, ff, rb, - notificationRemoteInputManagerLazy, leakDetector, fgsFeatureController) { - - public var countDownLatch: CountDownLatch = CountDownLatch(1) - - override fun onAsyncInflationFinished(entry: NotificationEntry) { - super.onAsyncInflationFinished(entry) - countDownLatch.countDown() - } - - fun setUpForTest( - presenter: NotificationPresenter? - ) { - super.setUpWithPresenter(presenter) - } - - fun setActiveNotificationList(activeList: List<NotificationEntry>) { - mSortedAndFiltered.clear() - mSortedAndFiltered.addAll(activeList) - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index 6b9e43bcb290..35b31c01fd9c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -62,7 +63,6 @@ public class PreparationCoordinatorTest extends SysuiTestCase { private OnBeforeFinalizeFilterListener mBeforeFilterListener; private NotifFilter mUninflatedFilter; private NotifFilter mInflationErrorFilter; - private NotifInflaterImpl.InflationCallback mCallback; private NotifInflationErrorManager mErrorManager; private NotificationEntry mEntry; private Exception mInflationError; @@ -104,9 +104,6 @@ public class PreparationCoordinatorTest extends SysuiTestCase { mBeforeFilterListenerCaptor.capture()); mBeforeFilterListener = mBeforeFilterListenerCaptor.getValue(); - verify(mNotifInflater).setInflationCallback(mCallbackCaptor.capture()); - mCallback = mCallbackCaptor.getValue(); - mCollectionListener.onEntryInit(mEntry); } @@ -142,7 +139,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase { mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); // THEN we inflate it - verify(mNotifInflater).inflateViews(mEntry); + verify(mNotifInflater).inflateViews(eq(mEntry), any()); // THEN we filter it out until it's done inflating. assertTrue(mUninflatedFilter.shouldFilterOut(mEntry, 0)); @@ -151,14 +148,17 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Test public void testRebindsInflatedNotificationsOnUpdate() { // GIVEN an inflated notification - mCallback.onInflationFinished(mEntry); + mCollectionListener.onEntryAdded(mEntry); + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); + verify(mNotifInflater).inflateViews(eq(mEntry), mCallbackCaptor.capture()); + mCallbackCaptor.getValue().onInflationFinished(mEntry); // WHEN notification is updated mCollectionListener.onEntryUpdated(mEntry); mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); // THEN we rebind it - verify(mNotifInflater).rebindViews(mEntry); + verify(mNotifInflater).rebindViews(eq(mEntry), any()); // THEN we do not filter it because it's not the first inflation. assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0)); @@ -166,8 +166,11 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Test public void testDoesntFilterInflatedNotifs() { - // WHEN a notification is inflated - mCallback.onInflationFinished(mEntry); + // GIVEN an inflated notification + mCollectionListener.onEntryAdded(mEntry); + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); + verify(mNotifInflater).inflateViews(eq(mEntry), mCallbackCaptor.capture()); + mCallbackCaptor.getValue().onInflationFinished(mEntry); // THEN it isn't filtered from shade list assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index 1c6e5a36bd8a..855f524db3f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -23,7 +23,6 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon import static junit.framework.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -216,9 +215,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { .onDismissRunnable(any())) .thenReturn(mExpandableNotificationRowComponentBuilder); when(mExpandableNotificationRowComponentBuilder - .inflationCallback(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder .rowContentBindStage(any())) .thenReturn(mExpandableNotificationRowComponentBuilder); when(mExpandableNotificationRowComponentBuilder @@ -243,7 +239,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { mHeadsUpManager, mPresenter, mStatusBarStateController, - mEntryManager, mGutsManager, true, null, @@ -275,7 +270,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { mEntryManager.addNotificationEntryListener(mEntryListener); mRowBinder.setUpWithPresenter(mPresenter, mListContainer, mBindCallback); - mRowBinder.setInflationCallback(mEntryManager); mRowBinder.setNotificationClicker(mock(NotificationClicker.class)); Ranking ranking = new Ranking(); @@ -330,7 +324,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { assertNotNull(entry.getRow().getPrivateLayout().getContractedChild()); // THEN inflation callbacks are called - verify(mBindCallback).onBindRow(eq(entry), any(), eq(mSbn), any()); + verify(mBindCallback).onBindRow(entry.getRow()); verify(mEntryListener, never()).onInflationError(any(), any()); verify(mEntryListener).onEntryInflated(entry); verify(mEntryListener).onNotificationAdded(entry); 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 ef2071ef090e..657bc8d614cf 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 @@ -69,7 +69,6 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; -import com.android.systemui.statusbar.notification.TestableNotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -138,7 +137,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private FeatureFlags mFeatureFlags; private UserChangedListener mUserChangedListener; - private TestableNotificationEntryManager mEntryManager; + private NotificationEntryManager mEntryManager; private int mOriginalInterruptionModelSetting; private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake(); @@ -167,7 +166,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor .forClass(UserChangedListener.class); - mEntryManager = new TestableNotificationEntryManager( + mEntryManager = new NotificationEntryManager( mock(NotificationEntryManagerLogger.class), mock(NotificationGroupManager.class), new NotificationRankingManager( @@ -187,7 +186,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mock(LeakDetector.class), mock(ForegroundServiceDismissalFeatureController.class) ); - mEntryManager.setUpForTest(mock(NotificationPresenter.class)); + mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class)); when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); NotificationShelf notificationShelf = mock(NotificationShelf.class); diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 50ec0400a729..e8acbd493180 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -165,7 +165,7 @@ public class AttentionManagerService extends SystemService { * Returns {@code true} if attention service is supported on this device. */ private boolean isAttentionServiceSupported() { - return isServiceEnabled() && isServiceAvailable(); + return isServiceEnabled() && isServiceConfigured(mContext); } @VisibleForTesting @@ -210,6 +210,11 @@ public class AttentionManagerService extends SystemService { return false; } + if (!isServiceAvailable()) { + Slog.w(LOG_TAG, "Service is not available at this moment."); + return false; + } + // don't allow attention check in screen off state if (!mPowerManager.isInteractive()) { return false; diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 173dfc244fe5..ec941c8aea59 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -800,7 +800,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true); - setRestrictBackgroundUL(mLoadedRestrictBackground); + setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service"); updateRulesForGlobalChangeAL(false); updateNotificationsNL(); } @@ -2877,10 +2877,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackground"); try { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); + final int callingUid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { synchronized (mUidRulesFirstLock) { - setRestrictBackgroundUL(restrictBackground); + setRestrictBackgroundUL(restrictBackground, "uid:" + callingUid); } } finally { Binder.restoreCallingIdentity(token); @@ -2891,7 +2892,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @GuardedBy("mUidRulesFirstLock") - private void setRestrictBackgroundUL(boolean restrictBackground) { + private void setRestrictBackgroundUL(boolean restrictBackground, String reason) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackgroundUL"); try { if (restrictBackground == mRestrictBackground) { @@ -2899,7 +2900,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Slog.w(TAG, "setRestrictBackgroundUL: already " + restrictBackground); return; } - Slog.d(TAG, "setRestrictBackgroundUL(): " + restrictBackground); + Slog.d(TAG, "setRestrictBackgroundUL(): " + restrictBackground + "; reason: " + reason); final boolean oldRestrictBackground = mRestrictBackground; mRestrictBackground = restrictBackground; // Must whitelist foreground apps before turning data saver mode on. @@ -3425,7 +3426,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("Restrict background: "); fout.println(mRestrictBackground); fout.print("Restrict power: "); fout.println(mRestrictPower); fout.print("Device idle: "); fout.println(mDeviceIdleMode); - fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces)); + fout.print("Metered ifaces: "); fout.println(mMeteredIfaces); + + fout.println(); + fout.print("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode); + fout.print("mRestrictBackgroundBeforeBsm: " + mRestrictBackgroundBeforeBsm); + fout.print("mLoadedRestrictBackground: " + mLoadedRestrictBackground); + fout.print("mRestrictBackgroundChangedInBsm: " + mRestrictBackgroundChangedInBsm); fout.println(); fout.println("Network policies:"); @@ -5020,7 +5027,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } if (shouldInvokeRestrictBackground) { - setRestrictBackgroundUL(restrictBackground); + setRestrictBackgroundUL(restrictBackground, "low_power"); } // Change it at last so setRestrictBackground() won't affect this variable diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 09b782d768d2..7c47cf0450d4 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -113,6 +113,7 @@ public class AppsFilter { private final OverlayReferenceMapper mOverlayReferenceMapper; private PackageParser.SigningDetails mSystemSigningDetails; + private Set<String> mProtectedBroadcasts = new ArraySet<>(); AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist, boolean systemAppsQueryable, @@ -298,10 +299,10 @@ public class AppsFilter { /** Returns true if the querying package may query for the potential target package */ private static boolean canQueryViaComponents(AndroidPackage querying, - AndroidPackage potentialTarget) { + AndroidPackage potentialTarget, Set<String> protectedBroadcasts) { if (!querying.getQueriesIntents().isEmpty()) { for (Intent intent : querying.getQueriesIntents()) { - if (matchesIntentFilters(intent, potentialTarget)) { + if (matchesIntentFilters(intent, potentialTarget, protectedBroadcasts)) { return true; } } @@ -353,13 +354,14 @@ public class AppsFilter { return false; } - private static boolean matchesIntentFilters(Intent intent, AndroidPackage potentialTarget) { + private static boolean matchesIntentFilters(Intent intent, AndroidPackage potentialTarget, + Set<String> protectedBroadcasts) { for (int s = ArrayUtils.size(potentialTarget.getServices()) - 1; s >= 0; s--) { ParsedService service = potentialTarget.getServices().get(s); if (!service.isExported()) { continue; } - if (matchesAnyFilter(intent, service)) { + if (matchesAnyFilter(intent, service, null /*protectedBroadcasts*/)) { return true; } } @@ -368,7 +370,8 @@ public class AppsFilter { if (!activity.isExported()) { continue; } - if (matchesAnyFilter(intent, activity)) { + + if (matchesAnyFilter(intent, activity, null /*protectedBroadcasts*/)) { return true; } } @@ -377,25 +380,32 @@ public class AppsFilter { if (!receiver.isExported()) { continue; } - if (matchesAnyFilter(intent, receiver)) { + if (matchesAnyFilter(intent, receiver, protectedBroadcasts)) { return true; } } return false; } - private static boolean matchesAnyFilter(Intent intent, ParsedComponent component) { + private static boolean matchesAnyFilter(Intent intent, ParsedComponent component, + Set<String> protectedBroadcasts) { List<ParsedIntentInfo> intents = component.getIntents(); for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) { IntentFilter intentFilter = intents.get(i); - if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), - intent.getData(), intent.getCategories(), "AppsFilter", true) > 0) { + if (matchesIntentFilter(intent, intentFilter, protectedBroadcasts)) { return true; } } return false; } + private static boolean matchesIntentFilter(Intent intent, IntentFilter intentFilter, + @Nullable Set<String> protectedBroadcasts) { + return intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), + intent.getData(), intent.getCategories(), "AppsFilter", true, protectedBroadcasts) + > 0; + } + /** * Grants access based on an interaction between a calling and target package, granting * visibility of the caller from the target. @@ -434,6 +444,12 @@ public class AppsFilter { } } } + + if (!newPkgSetting.pkg.getProtectedBroadcasts().isEmpty()) { + mProtectedBroadcasts.addAll(newPkgSetting.pkg.getProtectedBroadcasts()); + recomputeComponentVisibility(existingSettings, newPkgSetting.pkg.getPackageName()); + } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); try { final AndroidPackage newPkg = newPkgSetting.pkg; @@ -464,7 +480,7 @@ public class AppsFilter { final AndroidPackage existingPkg = existingSetting.pkg; // let's evaluate the ability of already added packages to see this new package if (!newIsForceQueryable) { - if (canQueryViaComponents(existingPkg, newPkg)) { + if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) { mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId); } if (canQueryViaPackage(existingPkg, newPkg) @@ -474,7 +490,7 @@ public class AppsFilter { } // now we'll evaluate our new package's ability to see existing packages if (!mForceQueryable.contains(existingSetting.appId)) { - if (canQueryViaComponents(newPkg, existingPkg)) { + if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) { mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId); } if (canQueryViaPackage(newPkg, existingPkg) @@ -511,10 +527,47 @@ public class AppsFilter { && pkgSetting.signatures.mSigningDetails.signaturesMatchExactly(sysSigningDetails); } - private static void sort(int[] uids, int nextUidIndex) { - Arrays.sort(uids, 0, nextUidIndex); + private ArraySet<String> collectProtectedBroadcasts( + ArrayMap<String, PackageSetting> existingSettings, @Nullable String excludePackage) { + ArraySet<String> ret = new ArraySet<>(); + for (int i = existingSettings.size() - 1; i >= 0; i--) { + PackageSetting setting = existingSettings.valueAt(i); + if (setting.pkg == null || setting.pkg.getPackageName().equals(excludePackage)) { + continue; + } + final List<String> protectedBroadcasts = setting.pkg.getProtectedBroadcasts(); + if (!protectedBroadcasts.isEmpty()) { + ret.addAll(protectedBroadcasts); + } + } + return ret; } + private void recomputeComponentVisibility(ArrayMap<String, PackageSetting> existingSettings, + @Nullable String excludePackage) { + mQueriesViaComponent.clear(); + for (int i = existingSettings.size() - 1; i >= 0; i--) { + PackageSetting setting = existingSettings.valueAt(i); + if (setting.pkg == null + || setting.pkg.getPackageName().equals(excludePackage) + || mForceQueryable.contains(setting.appId)) { + continue; + } + for (int j = existingSettings.size() - 1; j >= 0; j--) { + if (i == j) { + continue; + } + final PackageSetting otherSetting = existingSettings.valueAt(j); + if (otherSetting.pkg == null + || otherSetting.pkg.getPackageName().equals(excludePackage)) { + continue; + } + if (canQueryViaComponents(setting.pkg, otherSetting.pkg, mProtectedBroadcasts)) { + mQueriesViaComponent.add(setting.appId, otherSetting.appId); + } + } + } + } /** * Fetches all app Ids that a given setting is currently visible to, per provided user. This * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see @@ -608,6 +661,14 @@ public class AppsFilter { } } + if (!setting.pkg.getProtectedBroadcasts().isEmpty()) { + final String removingPackageName = setting.pkg.getPackageName(); + mProtectedBroadcasts.clear(); + mProtectedBroadcasts.addAll( + collectProtectedBroadcasts(existingSettings, removingPackageName)); + recomputeComponentVisibility(existingSettings, removingPackageName); + } + mOverlayReferenceMapper.removePkg(setting.name); mFeatureConfig.updatePackageState(setting, true /*removed*/); } diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java index 976ce1f3dde0..1c4568095ce3 100644 --- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java +++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java @@ -21,9 +21,14 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHE import android.annotation.NonNull; import android.app.ActivityManager; import android.app.AlarmManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.os.Handler; import android.permission.PermissionControllerManager; +import android.provider.DeviceConfig; import android.util.Log; import android.util.SparseArray; @@ -36,7 +41,10 @@ public class OneTimePermissionUserManager { private static final String LOG_TAG = OneTimePermissionUserManager.class.getSimpleName(); - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; + private static final long DEFAULT_KILLED_DELAY_MILLIS = 5000; + public static final String PROPERTY_KILLED_DELAY_CONFIG_KEY = + "one_time_permissions_killed_delay_millis"; private final @NonNull Context mContext; private final @NonNull ActivityManager mActivityManager; @@ -45,15 +53,37 @@ public class OneTimePermissionUserManager { private final Object mLock = new Object(); + private final BroadcastReceiver mUninstallListener = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_UID_REMOVED.equals(intent.getAction())) { + int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + PackageInactivityListener listener = mListeners.get(uid); + if (listener != null) { + if (DEBUG) { + Log.d(LOG_TAG, "Removing the inactivity listener for " + uid); + } + listener.cancel(); + mListeners.remove(uid); + } + } + } + }; + /** Maps the uid to the PackageInactivityListener */ @GuardedBy("mLock") private final SparseArray<PackageInactivityListener> mListeners = new SparseArray<>(); + private final Handler mHandler; OneTimePermissionUserManager(@NonNull Context context) { mContext = context; mActivityManager = context.getSystemService(ActivityManager.class); mAlarmManager = context.getSystemService(AlarmManager.class); mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class); + mHandler = context.getMainThreadHandler(); + + // Listen for tracked uid being uninstalled + context.registerReceiver(mUninstallListener, new IntentFilter(Intent.ACTION_UID_REMOVED)); } /** @@ -132,6 +162,15 @@ public class OneTimePermissionUserManager { } /** + * The delay to wait before revoking on the event an app is terminated. Recommended to be long + * enough so that apps don't lose permission on an immediate restart + */ + private static long getKilledDelayMillis() { + return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS, + PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS); + } + + /** * A class which watches a package for inactivity and notifies the permission controller when * the package becomes inactive */ @@ -155,16 +194,15 @@ public class OneTimePermissionUserManager { private final ActivityManager.OnUidImportanceListener mGoneListener; private final Object mInnerLock = new Object(); + private final Object mToken = new Object(); private PackageInactivityListener(int uid, @NonNull String packageName, long timeout, int importanceToResetTimer, int importanceToKeepSessionAlive) { - if (DEBUG) { - Log.d(LOG_TAG, - "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout - + " importanceToResetTimer=" + importanceToResetTimer - + " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive); - } + Log.i(LOG_TAG, + "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout + + " importanceToResetTimer=" + importanceToResetTimer + + " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive); mUid = uid; mPackageName = packageName; @@ -193,18 +231,34 @@ public class OneTimePermissionUserManager { return; } - - if (DEBUG) { - Log.d(LOG_TAG, "Importance changed for " + mPackageName + " (" + mUid + ")." - + " importance=" + importance); - } + Log.v(LOG_TAG, "Importance changed for " + mPackageName + " (" + mUid + ")." + + " importance=" + importance); synchronized (mInnerLock) { + // Remove any pending inactivity callback + mHandler.removeCallbacksAndMessages(mToken); + if (importance > IMPORTANCE_CACHED) { - onPackageInactiveLocked(); + // Delay revocation in case app is restarting + mHandler.postDelayed(() -> { + int imp = mActivityManager.getUidImportance(mUid); + if (imp > IMPORTANCE_CACHED) { + onPackageInactiveLocked(); + } else { + if (DEBUG) { + Log.d(LOG_TAG, "No longer gone after delayed revocation. " + + "Rechecking for " + mPackageName + " (" + mUid + ")."); + } + onImportanceChanged(mUid, imp); + } + }, mToken, getKilledDelayMillis()); return; } if (importance > mImportanceToResetTimer) { if (mTimerStart == TIMER_INACTIVE) { + if (DEBUG) { + Log.d(LOG_TAG, "Start the timer for " + + mPackageName + " (" + mUid + ")."); + } mTimerStart = System.currentTimeMillis(); } } else { @@ -240,10 +294,13 @@ public class OneTimePermissionUserManager { return; } + if (DEBUG) { + Log.d(LOG_TAG, "Scheduling alarm for " + mPackageName + " (" + mUid + ")."); + } long revokeTime = mTimerStart + mTimeout; if (revokeTime > System.currentTimeMillis()) { mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, revokeTime, LOG_TAG, this, - mContext.getMainThreadHandler()); + mHandler); mIsAlarmSet = true; } else { mIsAlarmSet = true; @@ -257,6 +314,9 @@ public class OneTimePermissionUserManager { @GuardedBy("mInnerLock") private void cancelAlarmLocked() { if (mIsAlarmSet) { + if (DEBUG) { + Log.d(LOG_TAG, "Canceling alarm for " + mPackageName + " (" + mUid + ")."); + } mAlarmManager.cancel(this); mIsAlarmSet = false; } @@ -270,14 +330,16 @@ public class OneTimePermissionUserManager { if (mIsFinished) { return; } + if (DEBUG) { + Log.d(LOG_TAG, "onPackageInactiveLocked stack trace for " + + mPackageName + " (" + mUid + ").", new RuntimeException()); + } mIsFinished = true; cancelAlarmLocked(); - mContext.getMainThreadHandler().post( + mHandler.post( () -> { - if (DEBUG) { - Log.d(LOG_TAG, "One time session expired for " - + mPackageName + " (" + mUid + ")."); - } + Log.i(LOG_TAG, "One time session expired for " + + mPackageName + " (" + mUid + ")."); mPermissionControllerManager.notifyOneTimePermissionSessionTimeout( mPackageName); @@ -292,6 +354,9 @@ public class OneTimePermissionUserManager { @Override public void onAlarm() { + if (DEBUG) { + Log.d(LOG_TAG, "Alarm received for " + mPackageName + " (" + mUid + ")."); + } synchronized (mInnerLock) { if (!mIsAlarmSet) { return; 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 b7c9ecb604f8..ccc749232dc3 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -2519,7 +2519,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; String upgradedActivityRecognitionPermission = null; - if (DEBUG_INSTALL) { + if (DEBUG_INSTALL && bp != null) { Log.i(TAG, "Package " + pkg.getPackageName() + " checking " + permName + ": " + bp); } @@ -3881,8 +3881,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg, @NonNull PermissionCallback callback) { + // If the package is being deleted, update the permissions of all the apps final int flags = - (pkg != null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG : 0); + (pkg == null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG + : UPDATE_PERMISSIONS_REPLACE_PKG); updatePermissions( packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback); } @@ -4007,6 +4009,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (permissionTreesSourcePackageChanged | permissionSourcePackageChanged) { // Permission ownership has changed. This e.g. changes which packages can get signature // permissions + Slog.i(TAG, "Permission ownership changed. Updating all permissions."); flags |= UPDATE_PERMISSIONS_ALL; } @@ -4057,8 +4060,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { private boolean updatePermissionSourcePackage(@Nullable String packageName, @Nullable AndroidPackage pkg, final @Nullable PermissionCallback callback) { - boolean changed = false; + // Always need update if packageName is null + if (packageName == null) { + return true; + } + boolean changed = false; Set<BasePermission> needsUpdate = null; synchronized (mLock) { final Iterator<BasePermission> it = mSettings.mPermissions.values().iterator(); @@ -4067,54 +4074,29 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (bp.isDynamic()) { bp.updateDynamicPermission(mSettings.mPermissionTrees.values()); } - if (bp.getSourcePackageSetting() != null) { - if (packageName != null && packageName.equals(bp.getSourcePackageName()) - && (pkg == null || !hasPermission(pkg, bp.getName()))) { - Slog.i(TAG, "Removing permission " + bp.getName() - + " that used to be declared by " + bp.getSourcePackageName()); - if (bp.isRuntime()) { - final int[] userIds = mUserManagerInt.getUserIds(); - final int numUserIds = userIds.length; - for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { - final int userId = userIds[userIdNum]; - - mPackageManagerInt.forEachPackage((AndroidPackage p) -> { - final String pName = p.getPackageName(); - final ApplicationInfo appInfo = - mPackageManagerInt.getApplicationInfo(pName, 0, - Process.SYSTEM_UID, UserHandle.USER_SYSTEM); - if (appInfo != null - && appInfo.targetSdkVersion < Build.VERSION_CODES.M) { - return; - } - - final String permissionName = bp.getName(); - if (checkPermissionImpl(permissionName, pName, userId) - == PackageManager.PERMISSION_GRANTED) { - try { - revokeRuntimePermissionInternal( - permissionName, - pName, - false, - Process.SYSTEM_UID, - userId, - callback); - } catch (IllegalArgumentException e) { - Slog.e(TAG, - "Failed to revoke " - + permissionName - + " from " - + pName, - e); - } - } - }); - } + if (bp.getSourcePackageSetting() == null + || !packageName.equals(bp.getSourcePackageName())) { + continue; + } + // The target package is the source of the current permission + // Set to changed for either install or uninstall + changed = true; + // If the target package is being uninstalled, we need to revoke this permission + // From all other packages + if (pkg == null || !hasPermission(pkg, bp.getName())) { + Slog.i(TAG, "Removing permission " + bp.getName() + + " that used to be declared by " + bp.getSourcePackageName()); + if (bp.isRuntime()) { + final int[] userIds = mUserManagerInt.getUserIds(); + final int numUserIds = userIds.length; + for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { + final int userId = userIds[userIdNum]; + mPackageManagerInt.forEachPackage((AndroidPackage p) -> + revokePermissionFromPackageForUser(p.getPackageName(), + bp.getName(), userId, callback)); } - changed = true; - it.remove(); } - continue; + it.remove(); } if (needsUpdate == null) { needsUpdate = new ArraySet<>(mSettings.mPermissions.size()); @@ -4146,6 +4128,39 @@ public class PermissionManagerService extends IPermissionManager.Stub { } /** + * Revoke a runtime permission from a package for a given user ID. + */ + private void revokePermissionFromPackageForUser(@NonNull String pName, + @NonNull String permissionName, int userId, @Nullable PermissionCallback callback) { + final ApplicationInfo appInfo = + mPackageManagerInt.getApplicationInfo(pName, 0, + Process.SYSTEM_UID, UserHandle.USER_SYSTEM); + if (appInfo != null + && appInfo.targetSdkVersion < Build.VERSION_CODES.M) { + return; + } + + if (checkPermissionImpl(permissionName, pName, userId) + == PackageManager.PERMISSION_GRANTED) { + try { + revokeRuntimePermissionInternal( + permissionName, + pName, + false, + Process.SYSTEM_UID, + userId, + callback); + } catch (IllegalArgumentException e) { + Slog.e(TAG, + "Failed to revoke " + + permissionName + + " from " + + pName, + e); + } + } + } + /** * Update which app owns a permission trees. * * <p>Possible parameter combinations @@ -4164,6 +4179,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private boolean updatePermissionTreeSourcePackage(@Nullable String packageName, @Nullable AndroidPackage pkg) { + // Always need update if packageName is null + if (packageName == null) { + return true; + } boolean changed = false; Set<BasePermission> needsUpdate = null; @@ -4171,16 +4190,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { final Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator(); while (it.hasNext()) { final BasePermission bp = it.next(); - if (bp.getSourcePackageSetting() != null) { - if (packageName != null && packageName.equals(bp.getSourcePackageName()) - && (pkg == null || !hasPermission(pkg, bp.getName()))) { - Slog.i(TAG, "Removing permission tree " + bp.getName() - + " that used to be declared by " + bp.getSourcePackageName()); - changed = true; - it.remove(); - } + if (bp.getSourcePackageSetting() == null + || !packageName.equals(bp.getSourcePackageName())) { continue; } + // The target package is the source of the current permission tree + // Set to changed for either install or uninstall + changed = true; + if (pkg == null || !hasPermission(pkg, bp.getName())) { + Slog.i(TAG, "Removing permission tree " + bp.getName() + + " that used to be declared by " + bp.getSourcePackageName()); + it.remove(); + } if (needsUpdate == null) { needsUpdate = new ArraySet<>(mSettings.mPermissionTrees.size()); } diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 695b68bf71cb..149dfa6be6c4 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -1279,7 +1279,7 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ { std::lock_guard lock(mJobMutex); if (mRunning) { - auto& existingJobs = mJobQueue[storage]; + auto& existingJobs = mJobQueue[ifs->mountId]; if (existingJobs.empty()) { existingJobs = std::move(jobQueue); } else { @@ -1369,12 +1369,32 @@ void IncrementalService::extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle } bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) { + struct WaitPrinter { + const Clock::time_point startTs = Clock::now(); + ~WaitPrinter() noexcept { + if (sEnablePerfLogging) { + const auto endTs = Clock::now(); + LOG(INFO) << "incfs: waitForNativeBinariesExtraction() complete in " + << elapsedMcs(startTs, endTs) << "mcs"; + } + } + } waitPrinter; + + MountId mount; + { + auto ifs = getIfs(storage); + if (!ifs) { + return true; + } + mount = ifs->mountId; + } + std::unique_lock lock(mJobMutex); - mJobCondition.wait(lock, [this, storage] { + mJobCondition.wait(lock, [this, mount] { return !mRunning || - (mPendingJobsStorage != storage && mJobQueue.find(storage) == mJobQueue.end()); + (mPendingJobsMount != mount && mJobQueue.find(mount) == mJobQueue.end()); }); - return mPendingJobsStorage != storage && mJobQueue.find(storage) == mJobQueue.end(); + return mRunning; } void IncrementalService::runJobProcessing() { @@ -1386,7 +1406,7 @@ void IncrementalService::runJobProcessing() { } auto it = mJobQueue.begin(); - mPendingJobsStorage = it->first; + mPendingJobsMount = it->first; auto queue = std::move(it->second); mJobQueue.erase(it); lock.unlock(); @@ -1396,7 +1416,7 @@ void IncrementalService::runJobProcessing() { } lock.lock(); - mPendingJobsStorage = kInvalidStorageId; + mPendingJobsMount = kInvalidStorageId; lock.unlock(); mJobCondition.notify_all(); } diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index e7705df633d1..c016bab067be 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -308,8 +308,8 @@ private: StorageId mNextId = 0; using Job = std::function<void()>; - std::unordered_map<StorageId, std::vector<Job>> mJobQueue; - StorageId mPendingJobsStorage = kInvalidStorageId; + std::unordered_map<MountId, std::vector<Job>> mJobQueue; + MountId mPendingJobsMount = kInvalidStorageId; std::condition_variable mJobCondition; std::mutex mJobMutex; std::thread mJobProcessor; diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index b60e99363706..f205fde88c0d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -117,6 +117,16 @@ public class AppsFilterTest { } private static ParsingPackage pkg(String packageName, IntentFilter... filters) { + ParsedActivity activity = createActivity(packageName, filters); + return pkg(packageName).addActivity(activity); + } + + private static ParsingPackage pkgWithReceiver(String packageName, IntentFilter... filters) { + ParsedActivity receiver = createActivity(packageName, filters); + return pkg(packageName).addReceiver(receiver); + } + + private static ParsedActivity createActivity(String packageName, IntentFilter[] filters) { ParsedActivity activity = new ParsedActivity(); activity.setPackageName(packageName); for (IntentFilter filter : filters) { @@ -136,9 +146,7 @@ public class AppsFilterTest { activity.addIntent(info); activity.setExported(true); } - - return pkg(packageName) - .addActivity(activity); + return activity; } private static ParsingPackage pkgWithInstrumentation( @@ -176,9 +184,10 @@ public class AppsFilterTest { } @Test - public void testQueriesAction_FilterMatches() { + public void testQueriesAction_FilterMatches() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -190,9 +199,46 @@ public class AppsFilterTest { } @Test - public void testQueriesProvider_FilterMatches() { + public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception { + final AppsFilter appsFilter = + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + final Signature frameworkSignature = Mockito.mock(Signature.class); + final PackageParser.SigningDetails frameworkSigningDetails = + new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1); + final ParsingPackage android = pkg("android"); + android.addProtectedBroadcast("TEST_ACTION"); + simulateAddPackage(appsFilter, android, 1000, + b -> b.setSigningDetails(frameworkSigningDetails)); + appsFilter.onSystemReady(); + + final int activityUid = DUMMY_TARGET_UID; + PackageSetting targetActivity = simulateAddPackage(appsFilter, + pkg("com.target.activity", new IntentFilter("TEST_ACTION")), activityUid); + final int receiverUid = DUMMY_TARGET_UID + 1; + PackageSetting targetReceiver = simulateAddPackage(appsFilter, + pkgWithReceiver("com.target.receiver", new IntentFilter("TEST_ACTION")), + receiverUid); + final int callingUid = DUMMY_CALLING_UID; + PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.calling.action", new Intent("TEST_ACTION")), callingUid); + final int wildcardUid = DUMMY_CALLING_UID + 1; + PackageSetting callingWildCard = simulateAddPackage(appsFilter, + pkg("com.calling.wildcard", new Intent("*")), wildcardUid); + + assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity, 0)); + assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver, 0)); + + assertFalse(appsFilter.shouldFilterApplication( + wildcardUid, callingWildCard, targetActivity, 0)); + assertTrue(appsFilter.shouldFilterApplication( + wildcardUid, callingWildCard, targetReceiver, 0)); + } + + @Test + public void testQueriesProvider_FilterMatches() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -205,9 +251,10 @@ public class AppsFilterTest { } @Test - public void testQueriesDifferentProvider_Filters() { + public void testQueriesDifferentProvider_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -220,9 +267,10 @@ public class AppsFilterTest { } @Test - public void testQueriesProviderWithSemiColon_FilterMatches() { + public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -236,9 +284,10 @@ public class AppsFilterTest { } @Test - public void testQueriesAction_NoMatchingAction_Filters() { + public void testQueriesAction_NoMatchingAction_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -250,9 +299,10 @@ public class AppsFilterTest { } @Test - public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() { + public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -269,9 +319,10 @@ public class AppsFilterTest { } @Test - public void testNoQueries_Filters() { + public void testNoQueries_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -283,9 +334,10 @@ public class AppsFilterTest { } @Test - public void testForceQueryable_DoesntFilter() { + public void testForceQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -297,9 +349,10 @@ public class AppsFilterTest { } @Test - public void testForceQueryableByDevice_SystemCaller_DoesntFilter() { + public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -340,9 +393,10 @@ public class AppsFilterTest { } @Test - public void testForceQueryableByDevice_NonSystemCaller_Filters() { + public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -355,10 +409,11 @@ public class AppsFilterTest { @Test - public void testSystemQueryable_DoesntFilter() { + public void testSystemQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, true /* system force queryable */, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -371,9 +426,10 @@ public class AppsFilterTest { } @Test - public void testQueriesPackage_DoesntFilter() { + public void testQueriesPackage_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -385,11 +441,12 @@ public class AppsFilterTest { } @Test - public void testNoQueries_FeatureOff_DoesntFilter() { + public void testNoQueries_FeatureOff_DoesntFilter() throws Exception { when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(false); final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage( @@ -401,9 +458,10 @@ public class AppsFilterTest { } @Test - public void testSystemUid_DoesntFilter() { + public void testSystemUid_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -415,9 +473,10 @@ public class AppsFilterTest { } @Test - public void testNonSystemUid_NoCallingSetting_Filters() { + public void testNonSystemUid_NoCallingSetting_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -427,9 +486,10 @@ public class AppsFilterTest { } @Test - public void testNoTargetPackage_filters() { + public void testNoTargetPackage_filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = new PackageSettingBuilder() @@ -445,7 +505,7 @@ public class AppsFilterTest { } @Test - public void testActsOnTargetOfOverlay() { + public void testActsOnTargetOfOverlay() throws Exception { final String actorName = "overlay://test/actorName"; ParsingPackage target = pkg("com.some.package.target") @@ -481,6 +541,7 @@ public class AppsFilterTest { return Collections.emptyMap(); } }); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); @@ -507,7 +568,7 @@ public class AppsFilterTest { } @Test - public void testActsOnTargetOfOverlayThroughSharedUser() { + public void testActsOnTargetOfOverlayThroughSharedUser() throws Exception { final String actorName = "overlay://test/actorName"; ParsingPackage target = pkg("com.some.package.target") @@ -545,6 +606,7 @@ public class AppsFilterTest { return Collections.emptyMap(); } }); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); @@ -566,9 +628,10 @@ public class AppsFilterTest { } @Test - public void testInitiatingApp_DoesntFilter() { + public void testInitiatingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), @@ -580,9 +643,10 @@ public class AppsFilterTest { } @Test - public void testUninstalledInitiatingApp_Filters() { + public void testUninstalledInitiatingApp_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), @@ -594,9 +658,10 @@ public class AppsFilterTest { } @Test - public void testOriginatingApp_Filters() { + public void testOriginatingApp_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), @@ -608,9 +673,10 @@ public class AppsFilterTest { } @Test - public void testInstallingApp_DoesntFilter() { + public void testInstallingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), @@ -622,9 +688,10 @@ public class AppsFilterTest { } @Test - public void testInstrumentation_DoesntFilter() { + public void testInstrumentation_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -644,6 +711,7 @@ public class AppsFilterTest { public void testWhoCanSee() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); final int systemAppId = Process.FIRST_APPLICATION_UID - 1; @@ -700,6 +768,15 @@ public class AppsFilterTest { PackageSettingBuilder withBuilder(PackageSettingBuilder builder); } + private void simulateAddBasicAndroid(AppsFilter appsFilter) throws Exception { + final Signature frameworkSignature = Mockito.mock(Signature.class); + final PackageParser.SigningDetails frameworkSigningDetails = + new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1); + final ParsingPackage android = pkg("android"); + simulateAddPackage(appsFilter, android, 1000, + b -> b.setSigningDetails(frameworkSigningDetails)); + } + private PackageSetting simulateAddPackage(AppsFilter filter, ParsingPackage newPkgBuilder, int appId) { return simulateAddPackage(filter, newPkgBuilder, appId, null); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java index b8de3ca4ea1c..ee210b6eeaee 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static org.mockito.ArgumentMatchers.any; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -49,6 +50,7 @@ public class WindowContainerThumbnailTest extends WindowTestsBase { GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER); final ActivityRecord mockAr = mock(ActivityRecord.class); when(mockAr.getPendingTransaction()).thenReturn(new StubTransaction()); + when(mockAr.makeChildSurface(any())).thenReturn(new MockSurfaceControlBuilder()); when(mockAr.makeSurface()).thenReturn(new MockSurfaceControlBuilder()); return new WindowContainerThumbnail(new StubTransaction(), mockAr, buffer, false, mock(Surface.class), mock(SurfaceAnimator.class)); |