Remove obsolete FGS notification code

The features that used this code were turned off several years ago.

Test: atest SystemUITests
Test: run FGS - see notification in shade and app in task manager
Fixes: 275709313

Change-Id: Ie21fc03ac243932426e78c36ce2ec34d1a16a173
This commit is contained in:
Julia Reynolds
2023-08-07 15:45:31 -04:00
parent 97c61a0858
commit fe375f3606
10 changed files with 119 additions and 1040 deletions

View File

@@ -131,14 +131,14 @@ import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.util.sensors.AsyncSensorManager;
import dagger.Lazy;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
import dagger.Lazy;
/**
* Class to handle ugly dependencies throughout sysui until we determine the
* long-term dependency injection solution.
@@ -280,7 +280,6 @@ public class Dependency {
@Inject Lazy<AccessibilityManagerWrapper> mAccessibilityManagerWrapper;
@Inject Lazy<SysuiColorExtractor> mSysuiColorExtractor;
@Inject Lazy<TunablePaddingService> mTunablePaddingService;
@Inject Lazy<ForegroundServiceController> mForegroundServiceController;
@Inject Lazy<UiOffloadThread> mUiOffloadThread;
@Inject Lazy<PowerUI.WarningsUI> mWarningsUI;
@Inject Lazy<LightBarController> mLightBarController;
@@ -458,8 +457,6 @@ public class Dependency {
mProviders.put(TunablePaddingService.class, mTunablePaddingService::get);
mProviders.put(ForegroundServiceController.class, mForegroundServiceController::get);
mProviders.put(UiOffloadThread.class, mUiOffloadThread::get);
mProviders.put(PowerUI.WarningsUI.class, mWarningsUI::get);

View File

@@ -1,183 +0,0 @@
/*
* Copyright (C) 2017 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;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.SparseArray;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.Assert;
import javax.inject.Inject;
/**
* Tracks state of foreground services and notifications related to foreground services per user.
*/
@SysUISingleton
public class ForegroundServiceController {
public static final int[] APP_OPS = new int[] {AppOpsManager.OP_SYSTEM_ALERT_WINDOW};
private final SparseArray<ForegroundServicesUserState> mUserServices = new SparseArray<>();
private final Object mMutex = new Object();
private final Handler mMainHandler;
@Inject
public ForegroundServiceController(
AppOpsController appOpsController,
@Main Handler mainHandler) {
mMainHandler = mainHandler;
appOpsController.addCallback(APP_OPS, (code, uid, packageName, active) -> {
mMainHandler.post(() -> {
onAppOpChanged(code, uid, packageName, active);
});
});
}
/**
* @return true if this user has services missing notifications and therefore needs a
* disclosure notification for running a foreground service.
*/
public boolean isDisclosureNeededForUser(int userId) {
synchronized (mMutex) {
final ForegroundServicesUserState services = mUserServices.get(userId);
if (services == null) return false;
return services.isDisclosureNeeded();
}
}
/**
* @return true if this user/pkg has a missing or custom layout notification and therefore needs
* a disclosure notification showing the user which appsOps the app is using.
*/
public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
synchronized (mMutex) {
final ForegroundServicesUserState services = mUserServices.get(userId);
if (services == null) return false;
return services.getStandardLayoutKeys(pkg) == null;
}
}
/**
* Gets active app ops for this user and package
*/
@Nullable
public ArraySet<Integer> getAppOps(int userId, String pkg) {
synchronized (mMutex) {
final ForegroundServicesUserState services = mUserServices.get(userId);
if (services == null) {
return null;
}
return services.getFeatures(pkg);
}
}
/**
* Records active app ops and updates the app op for the pending or visible notifications
* with the given parameters.
* App Ops are stored in FSC in addition to NotificationEntry in case they change before we
* have a notification to tag.
* @param appOpCode code for appOp to add/remove
* @param uid of user the notification is sent to
* @param packageName package that created the notification
* @param active whether the appOpCode is active or not
*/
void onAppOpChanged(int appOpCode, int uid, String packageName, boolean active) {
Assert.isMainThread();
int userId = UserHandle.getUserId(uid);
// Record active app ops
synchronized (mMutex) {
ForegroundServicesUserState userServices = mUserServices.get(userId);
if (userServices == null) {
userServices = new ForegroundServicesUserState();
mUserServices.put(userId, userServices);
}
if (active) {
userServices.addOp(packageName, appOpCode);
} else {
userServices.removeOp(packageName, appOpCode);
}
}
}
/**
* Looks up the {@link ForegroundServicesUserState} for the given {@code userId}, then performs
* the given {@link UserStateUpdateCallback} on it. If no state exists for the user ID, creates
* a new one if {@code createIfNotFound} is true, then performs the update on the new state.
* If {@code createIfNotFound} is false, no update is performed.
*
* @return false if no user state was found and none was created; true otherwise.
*/
boolean updateUserState(int userId,
UserStateUpdateCallback updateCallback,
boolean createIfNotFound) {
synchronized (mMutex) {
ForegroundServicesUserState userState = mUserServices.get(userId);
if (userState == null) {
if (createIfNotFound) {
userState = new ForegroundServicesUserState();
mUserServices.put(userId, userState);
} else {
return false;
}
}
return updateCallback.updateUserState(userState);
}
}
/**
* @return true if {@code sbn} is the system-provided disclosure notification containing the
* list of running foreground services.
*/
public boolean isDisclosureNotification(StatusBarNotification sbn) {
return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
&& sbn.getTag() == null
&& sbn.getPackageName().equals("android");
}
/**
* @return true if sbn is one of the window manager "drawing over other apps" notifications
*/
public boolean isSystemAlertNotification(StatusBarNotification sbn) {
return sbn.getPackageName().equals("android")
&& sbn.getTag() != null
&& sbn.getTag().contains("AlertWindowNotification");
}
/**
* Callback provided to {@link #updateUserState(int, UserStateUpdateCallback, boolean)}
* to perform the update.
*/
interface UserStateUpdateCallback {
/**
* Perform update operations on the provided {@code userState}.
*
* @return true if the update succeeded.
*/
boolean updateUserState(ForegroundServicesUserState userState);
/** Called if the state was not found and was not created. */
default void userStateNotFound(int userId) {
}
}
}

View File

@@ -1,150 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import javax.inject.Inject;
/** Updates foreground service notification state in response to notification data events. */
@SysUISingleton
public class ForegroundServiceNotificationListener {
private static final String TAG = "FgServiceController";
private static final boolean DBG = false;
private final Context mContext;
private final ForegroundServiceController mForegroundServiceController;
private final NotifPipeline mNotifPipeline;
@Inject
public ForegroundServiceNotificationListener(Context context,
ForegroundServiceController foregroundServiceController,
NotifPipeline notifPipeline) {
mContext = context;
mForegroundServiceController = foregroundServiceController;
mNotifPipeline = notifPipeline;
}
/** Initializes this listener by connecting it to the notification pipeline. */
public void init() {
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
public void onEntryAdded(NotificationEntry entry) {
addNotification(entry, entry.getImportance());
}
@Override
public void onEntryUpdated(NotificationEntry entry) {
updateNotification(entry, entry.getImportance());
}
@Override
public void onEntryRemoved(NotificationEntry entry, int reason) {
removeNotification(entry.getSbn());
}
});
}
/**
* @param entry notification that was just posted
*/
private void addNotification(NotificationEntry entry, int importance) {
updateNotification(entry, importance);
}
/**
* @param sbn notification that was just removed
*/
private void removeNotification(StatusBarNotification sbn) {
mForegroundServiceController.updateUserState(
sbn.getUserId(),
new ForegroundServiceController.UserStateUpdateCallback() {
@Override
public boolean updateUserState(ForegroundServicesUserState userState) {
if (mForegroundServiceController.isDisclosureNotification(sbn)) {
// if you remove the dungeon entirely, we take that to mean there are
// no running services
userState.setRunningServices(null, 0);
return true;
} else {
// this is safe to call on any notification, not just
// FLAG_FOREGROUND_SERVICE
return userState.removeNotification(sbn.getPackageName(), sbn.getKey());
}
}
@Override
public void userStateNotFound(int userId) {
if (DBG) {
Log.w(TAG, String.format(
"user %d with no known notifications got removeNotification "
+ "for %s",
sbn.getUserId(), sbn));
}
}
},
false /* don't create */);
}
/**
* @param entry notification that was just changed in some way
*/
private void updateNotification(NotificationEntry entry, int newImportance) {
final StatusBarNotification sbn = entry.getSbn();
mForegroundServiceController.updateUserState(
sbn.getUserId(),
userState -> {
if (mForegroundServiceController.isDisclosureNotification(sbn)) {
final Bundle extras = sbn.getNotification().extras;
if (extras != null) {
final String[] svcs = extras.getStringArray(
Notification.EXTRA_FOREGROUND_APPS);
userState.setRunningServices(svcs, sbn.getNotification().when);
}
} else {
userState.removeNotification(sbn.getPackageName(), sbn.getKey());
if (0 != (sbn.getNotification().flags
& Notification.FLAG_FOREGROUND_SERVICE)) {
if (newImportance > NotificationManager.IMPORTANCE_MIN) {
userState.addImportantNotification(sbn.getPackageName(),
sbn.getKey());
}
}
final Notification.Builder builder =
Notification.Builder.recoverBuilder(
mContext, sbn.getNotification());
if (builder.usesStandardHeader()) {
userState.addStandardLayoutNotification(
sbn.getPackageName(), sbn.getKey());
}
}
return true;
},
true /* create if not found */);
}
}

View File

@@ -1,130 +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.collection.coordinator;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import android.app.Notification;
import android.service.notification.StatusBarNotification;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import com.android.systemui.util.concurrency.DelayableExecutor;
import javax.inject.Inject;
/**
* Handles ForegroundService and AppOp interactions with notifications.
* Tags notifications with appOps
* Lifetime extends notifications associated with an ongoing ForegroundService.
* Filters out notifications that represent foreground services that are no longer running
* Puts foreground service notifications into the FGS section. See {@link NotifCoordinators} for
* section ordering priority.
*
* Previously this logic lived in
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceController
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender
*/
@CoordinatorScope
public class AppOpsCoordinator implements Coordinator {
private static final String TAG = "AppOpsCoordinator";
private final ForegroundServiceController mForegroundServiceController;
private final AppOpsController mAppOpsController;
private final DelayableExecutor mMainExecutor;
private NotifPipeline mNotifPipeline;
@Inject
public AppOpsCoordinator(
ForegroundServiceController foregroundServiceController,
AppOpsController appOpsController,
@Main DelayableExecutor mainExecutor) {
mForegroundServiceController = foregroundServiceController;
mAppOpsController = appOpsController;
mMainExecutor = mainExecutor;
}
@Override
public void attach(NotifPipeline pipeline) {
mNotifPipeline = pipeline;
// filter out foreground service notifications that aren't necessary anymore
mNotifPipeline.addPreGroupFilter(mNotifFilter);
}
public NotifSectioner getSectioner() {
return mNotifSectioner;
}
/**
* Filters out notifications that represent foreground services that are no longer running or
* that already have an app notification with the appOps tagged to
*/
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
StatusBarNotification sbn = entry.getSbn();
// Filters out system-posted disclosure notifications when unneeded
if (mForegroundServiceController.isDisclosureNotification(sbn)
&& !mForegroundServiceController.isDisclosureNeededForUser(
sbn.getUser().getIdentifier())) {
return true;
}
return false;
}
};
/**
* Puts colorized foreground service and call notifications into its own section.
*/
private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService",
NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE) {
@Override
public boolean isInSection(ListEntry entry) {
NotificationEntry notificationEntry = entry.getRepresentativeEntry();
if (notificationEntry != null) {
return isColorizedForegroundService(notificationEntry) || isCall(notificationEntry);
}
return false;
}
private boolean isColorizedForegroundService(NotificationEntry entry) {
Notification notification = entry.getSbn().getNotification();
return notification.isForegroundService()
&& notification.isColorized()
&& entry.getImportance() > IMPORTANCE_MIN;
}
private boolean isCall(NotificationEntry entry) {
Notification notification = entry.getSbn().getNotification();
return entry.getImportance() > IMPORTANCE_MIN
&& notification.isStyle(Notification.CallStyle.class);
}
};
}

View File

@@ -0,0 +1,81 @@
/*
* 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.collection.coordinator;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import android.app.Notification;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import javax.inject.Inject;
/**
* Handles sectioning for foreground service notifications.
* Puts non-min colorized foreground service notifications into the FGS section. See
* {@link NotifCoordinators} for section ordering priority.
*/
@CoordinatorScope
public class ColorizedFgsCoordinator implements Coordinator {
private static final String TAG = "ColorizedCoordinator";
@Inject
public ColorizedFgsCoordinator() {
}
@Override
public void attach(NotifPipeline pipeline) {
}
public NotifSectioner getSectioner() {
return mNotifSectioner;
}
/**
* Puts colorized foreground service and call notifications into its own section.
*/
private final NotifSectioner mNotifSectioner = new NotifSectioner("ColorizedSectioner",
NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE) {
@Override
public boolean isInSection(ListEntry entry) {
NotificationEntry notificationEntry = entry.getRepresentativeEntry();
if (notificationEntry != null) {
return isColorizedForegroundService(notificationEntry) || isCall(notificationEntry);
}
return false;
}
private boolean isColorizedForegroundService(NotificationEntry entry) {
Notification notification = entry.getSbn().getNotification();
return notification.isForegroundService()
&& notification.isColorized()
&& entry.getImportance() > IMPORTANCE_MIN;
}
private boolean isCall(NotificationEntry entry) {
Notification notification = entry.getSbn().getNotification();
return entry.getImportance() > IMPORTANCE_MIN
&& notification.isStyle(Notification.CallStyle.class);
}
};
}

View File

@@ -33,34 +33,34 @@ interface NotifCoordinators : Coordinator, PipelineDumpable
@CoordinatorScope
class NotifCoordinatorsImpl @Inject constructor(
sectionStyleProvider: SectionStyleProvider,
featureFlags: FeatureFlags,
dataStoreCoordinator: DataStoreCoordinator,
hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
keyguardCoordinator: KeyguardCoordinator,
rankingCoordinator: RankingCoordinator,
appOpsCoordinator: AppOpsCoordinator,
deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
bubbleCoordinator: BubbleCoordinator,
headsUpCoordinator: HeadsUpCoordinator,
gutsCoordinator: GutsCoordinator,
conversationCoordinator: ConversationCoordinator,
debugModeCoordinator: DebugModeCoordinator,
groupCountCoordinator: GroupCountCoordinator,
groupWhenCoordinator: GroupWhenCoordinator,
mediaCoordinator: MediaCoordinator,
preparationCoordinator: PreparationCoordinator,
remoteInputCoordinator: RemoteInputCoordinator,
rowAppearanceCoordinator: RowAppearanceCoordinator,
stackCoordinator: StackCoordinator,
shadeEventCoordinator: ShadeEventCoordinator,
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
viewConfigCoordinator: ViewConfigCoordinator,
visualStabilityCoordinator: VisualStabilityCoordinator,
sensitiveContentCoordinator: SensitiveContentCoordinator,
dismissibilityCoordinator: DismissibilityCoordinator,
dreamCoordinator: DreamCoordinator,
sectionStyleProvider: SectionStyleProvider,
featureFlags: FeatureFlags,
dataStoreCoordinator: DataStoreCoordinator,
hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
keyguardCoordinator: KeyguardCoordinator,
rankingCoordinator: RankingCoordinator,
colorizedFgsCoordinator: ColorizedFgsCoordinator,
deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
bubbleCoordinator: BubbleCoordinator,
headsUpCoordinator: HeadsUpCoordinator,
gutsCoordinator: GutsCoordinator,
conversationCoordinator: ConversationCoordinator,
debugModeCoordinator: DebugModeCoordinator,
groupCountCoordinator: GroupCountCoordinator,
groupWhenCoordinator: GroupWhenCoordinator,
mediaCoordinator: MediaCoordinator,
preparationCoordinator: PreparationCoordinator,
remoteInputCoordinator: RemoteInputCoordinator,
rowAppearanceCoordinator: RowAppearanceCoordinator,
stackCoordinator: StackCoordinator,
shadeEventCoordinator: ShadeEventCoordinator,
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
viewConfigCoordinator: ViewConfigCoordinator,
visualStabilityCoordinator: VisualStabilityCoordinator,
sensitiveContentCoordinator: SensitiveContentCoordinator,
dismissibilityCoordinator: DismissibilityCoordinator,
dreamCoordinator: DreamCoordinator,
) : NotifCoordinators {
private val mCoreCoordinators: MutableList<CoreCoordinator> = ArrayList()
@@ -79,7 +79,7 @@ class NotifCoordinatorsImpl @Inject constructor(
mCoordinators.add(hideNotifsForOtherUsersCoordinator)
mCoordinators.add(keyguardCoordinator)
mCoordinators.add(rankingCoordinator)
mCoordinators.add(appOpsCoordinator)
mCoordinators.add(colorizedFgsCoordinator)
mCoordinators.add(deviceProvisionedCoordinator)
mCoordinators.add(bubbleCoordinator)
mCoordinators.add(debugModeCoordinator)
@@ -106,7 +106,7 @@ class NotifCoordinatorsImpl @Inject constructor(
// Manually add Ordered Sections
mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp
mOrderedSections.add(appOpsCoordinator.sectioner) // ForegroundService
mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService
mOrderedSections.add(conversationCoordinator.peopleAlertingSectioner) // People Alerting
mOrderedSections.add(conversationCoordinator.peopleSilentSectioner) // People Silent
mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting

View File

@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.init
import android.service.notification.StatusBarNotification
import com.android.systemui.ForegroundServiceNotificationListener
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.people.widget.PeopleSpaceWidgetManager
@@ -70,7 +69,6 @@ class NotificationsControllerImpl @Inject constructor(
private val animatedImageNotificationManager: AnimatedImageNotificationManager,
private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager,
private val bubblesOptional: Optional<Bubbles>,
private val fgsNotifListener: ForegroundServiceNotificationListener,
private val featureFlags: FeatureFlags
) : NotificationsController {
@@ -105,7 +103,6 @@ class NotificationsControllerImpl @Inject constructor(
notificationsMediaManager.setUpWithPresenter(presenter)
notificationLogger.setUpWithContainer(listContainer)
peopleSpaceWidgetManager.attach(notificationListener)
fgsNotifListener.init()
}
// TODO: Convert all functions below this line into listeners instead of public methods

View File

@@ -1,487 +0,0 @@
/*
* Copyright (C) 2017 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;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.widget.RemoteViews;
import androidx.test.filters.SmallTest;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class ForegroundServiceControllerTest extends SysuiTestCase {
private ForegroundServiceController mFsc;
private ForegroundServiceNotificationListener mListener;
private NotifCollectionListener mCollectionListener;
@Mock private AppOpsController mAppOpsController;
@Mock private Handler mMainHandler;
@Mock private NotifPipeline mNotifPipeline;
@Before
public void setUp() throws Exception {
// allow the TestLooper to be asserted as the main thread these tests
allowTestableLooperAsMainThread();
MockitoAnnotations.initMocks(this);
mFsc = new ForegroundServiceController(mAppOpsController, mMainHandler);
mListener = new ForegroundServiceNotificationListener(
mContext, mFsc, mNotifPipeline);
mListener.init();
ArgumentCaptor<NotifCollectionListener> entryListenerCaptor =
ArgumentCaptor.forClass(NotifCollectionListener.class);
verify(mNotifPipeline).addCollectionListener(
entryListenerCaptor.capture());
mCollectionListener = entryListenerCaptor.getValue();
}
@Test
public void testAppOpsChangedCalledFromBgThread() {
try {
// WHEN onAppOpChanged is called from a different thread than the MainLooper
disallowTestableLooperAsMainThread();
NotificationEntry entry = createFgEntry();
mFsc.onAppOpChanged(
AppOpsManager.OP_CAMERA,
entry.getSbn().getUid(),
entry.getSbn().getPackageName(),
true);
// This test is run on the TestableLooper, which is not the MainLooper, so
// we expect an exception to be thrown
fail("onAppOpChanged shouldn't be allowed to be called from a bg thread.");
} catch (IllegalStateException e) {
// THEN expect an exception
}
}
@Test
public void testAppOpsCRUD() {
// no crash on remove that doesn't exist
mFsc.onAppOpChanged(9, 1000, "pkg1", false);
assertNull(mFsc.getAppOps(0, "pkg1"));
// multiuser & multipackage
mFsc.onAppOpChanged(8, 50, "pkg1", true);
mFsc.onAppOpChanged(1, 60, "pkg3", true);
mFsc.onAppOpChanged(7, 500000, "pkg2", true);
assertEquals(1, mFsc.getAppOps(0, "pkg1").size());
assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
assertEquals(1, mFsc.getAppOps(0, "pkg3").size());
assertTrue(mFsc.getAppOps(0, "pkg3").contains(1));
// multiple ops for the same package
mFsc.onAppOpChanged(9, 50, "pkg1", true);
mFsc.onAppOpChanged(5, 50, "pkg1", true);
assertEquals(3, mFsc.getAppOps(0, "pkg1").size());
assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
assertTrue(mFsc.getAppOps(0, "pkg1").contains(9));
assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
// remove one of the multiples
mFsc.onAppOpChanged(9, 50, "pkg1", false);
assertEquals(2, mFsc.getAppOps(0, "pkg1").size());
assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
// remove last op
mFsc.onAppOpChanged(1, 60, "pkg3", false);
assertNull(mFsc.getAppOps(0, "pkg3"));
}
@Test
public void testDisclosurePredicate() {
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
StatusBarNotification sbn_user1_disclosure = makeMockSBN(USERID_ONE, "android",
SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
null, Notification.FLAG_NO_CLEAR);
assertTrue(mFsc.isDisclosureNotification(sbn_user1_disclosure));
assertFalse(mFsc.isDisclosureNotification(sbn_user1_app1));
}
@Test
public void testNeedsDisclosureAfterRemovingUnrelatedNotification() {
final String PKG1 = "com.example.app100";
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
// first add a normal notification
entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
// nothing required yet
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
// now the app starts a fg service
entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
// add the fg notification
entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
// remove the boring notification
entryRemoved(sbn_user1_app1);
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has STILL got it covered
entryRemoved(sbn_user1_app1_fg);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
}
@Test
public void testSimpleAddRemove() {
final String PKG1 = "com.example.app1";
final String PKG2 = "com.example.app2";
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
// no services are "running"
entryAdded(makeMockDisclosure(USERID_ONE, null),
NotificationManager.IMPORTANCE_DEFAULT);
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// switch to different package
entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2}),
NotificationManager.IMPORTANCE_DEFAULT);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
entryUpdated(makeMockDisclosure(USERID_TWO, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO)); // finally user2 needs one too
entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2, PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
entryRemoved(makeMockDisclosure(USERID_ONE, null /*unused*/));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
entryRemoved(makeMockDisclosure(USERID_TWO, null /*unused*/));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
}
@Test
public void testDisclosureBasic() {
final String PKG1 = "com.example.app0";
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// let's take out the other notification and see what happens.
entryRemoved(sbn_user1_app1);
assertFalse(
mFsc.isDisclosureNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1);
sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
entryUpdated(sbn_user1_app1_fg_sneaky,
NotificationManager.IMPORTANCE_DEFAULT);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// ok, ok, we'll put it back
sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
entryRemoved(sbn_user1_app1_fg_sneaky);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// now let's test an upgrade
entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
entryUpdated(sbn_user1_app1,
NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
// remove it, make sure we're out of compliance again
entryRemoved(sbn_user1_app1); // was fg, should return true
entryRemoved(sbn_user1_app1);
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
// importance upgrade
entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
entryUpdated(sbn_user1_app1_fg,
NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
// finally, let's turn off the service
entryAdded(makeMockDisclosure(USERID_ONE, null),
NotificationManager.IMPORTANCE_DEFAULT);
assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
}
@Test
public void testNoNotifsNorAppOps_noSystemAlertWarningRequired() {
// no notifications nor app op signals that this package/userId requires system alert
// warning
assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, "any"));
}
@Test
public void testCustomLayouts_systemAlertWarningRequired() {
// GIVEN a notification with a custom layout
final String pkg = "com.example.app0";
StatusBarNotification customLayoutNotif = makeMockSBN(USERID_ONE, pkg, 0,
false);
// WHEN the custom layout entry is added
entryAdded(customLayoutNotif, NotificationManager.IMPORTANCE_MIN);
// THEN a system alert warning is required since there aren't any notifications that can
// display the app ops
assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, pkg));
}
@Test
public void testStandardLayoutExists_noSystemAlertWarningRequired() {
// GIVEN two notifications (one with a custom layout, the other with a standard layout)
final String pkg = "com.example.app0";
StatusBarNotification customLayoutNotif = makeMockSBN(USERID_ONE, pkg, 0,
false);
StatusBarNotification standardLayoutNotif = makeMockSBN(USERID_ONE, pkg, 1, true);
// WHEN the entries are added
entryAdded(customLayoutNotif, NotificationManager.IMPORTANCE_MIN);
entryAdded(standardLayoutNotif, NotificationManager.IMPORTANCE_MIN);
// THEN no system alert warning is required, since there is at least one notification
// with a standard layout that can display the app ops on the notification
assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, pkg));
}
@Test
public void testStandardLayoutRemoved_systemAlertWarningRequired() {
// GIVEN two notifications (one with a custom layout, the other with a standard layout)
final String pkg = "com.example.app0";
StatusBarNotification customLayoutNotif = makeMockSBN(USERID_ONE, pkg, 0,
false);
StatusBarNotification standardLayoutNotif = makeMockSBN(USERID_ONE, pkg, 1, true);
// WHEN the entries are added and then the standard layout notification is removed
entryAdded(customLayoutNotif, NotificationManager.IMPORTANCE_MIN);
entryAdded(standardLayoutNotif, NotificationManager.IMPORTANCE_MIN);
entryRemoved(standardLayoutNotif);
// THEN a system alert warning is required since there aren't any notifications that can
// display the app ops
assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, pkg));
}
@Test
public void testStandardLayoutUpdatedToCustomLayout_systemAlertWarningRequired() {
// GIVEN a standard layout notification and then an updated version with a customLayout
final String pkg = "com.example.app0";
StatusBarNotification standardLayoutNotif = makeMockSBN(USERID_ONE, pkg, 1, true);
StatusBarNotification updatedToCustomLayoutNotif = makeMockSBN(USERID_ONE, pkg, 1, false);
// WHEN the entries is added and then updated to a custom layout
entryAdded(standardLayoutNotif, NotificationManager.IMPORTANCE_MIN);
entryUpdated(updatedToCustomLayoutNotif, NotificationManager.IMPORTANCE_MIN);
// THEN a system alert warning is required since there aren't any notifications that can
// display the app ops
assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, pkg));
}
private StatusBarNotification makeMockSBN(int userId, String pkg, int id, String tag,
int flags) {
final Notification n = mock(Notification.class);
n.extras = new Bundle();
n.flags = flags;
return makeMockSBN(userId, pkg, id, tag, n);
}
private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
Notification n) {
final StatusBarNotification sbn = mock(StatusBarNotification.class);
when(sbn.getNotification()).thenReturn(n);
when(sbn.getId()).thenReturn(id);
when(sbn.getPackageName()).thenReturn(pkg);
when(sbn.getTag()).thenReturn(tag);
when(sbn.getUserId()).thenReturn(userid);
when(sbn.getUser()).thenReturn(new UserHandle(userid));
when(sbn.getKey()).thenReturn("MOCK:"+userid+"|"+pkg+"|"+id+"|"+tag);
return sbn;
}
private StatusBarNotification makeMockSBN(int uid, String pkg, int id,
boolean usesStdLayout) {
StatusBarNotification sbn = makeMockSBN(uid, pkg, id, "foo", 0);
if (usesStdLayout) {
sbn.getNotification().contentView = null;
sbn.getNotification().headsUpContentView = null;
sbn.getNotification().bigContentView = null;
} else {
sbn.getNotification().contentView = mock(RemoteViews.class);
}
return sbn;
}
private StatusBarNotification makeMockFgSBN(int uid, String pkg, int id,
boolean usesStdLayout) {
StatusBarNotification sbn =
makeMockSBN(uid, pkg, id, "foo", Notification.FLAG_FOREGROUND_SERVICE);
if (usesStdLayout) {
sbn.getNotification().contentView = null;
sbn.getNotification().headsUpContentView = null;
sbn.getNotification().bigContentView = null;
} else {
sbn.getNotification().contentView = mock(RemoteViews.class);
}
return sbn;
}
private StatusBarNotification makeMockFgSBN(int uid, String pkg) {
return makeMockSBN(uid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
}
private StatusBarNotification makeMockDisclosure(int userid, String[] pkgs) {
final Notification n = mock(Notification.class);
n.flags = Notification.FLAG_ONGOING_EVENT;
final Bundle extras = new Bundle();
if (pkgs != null) extras.putStringArray(Notification.EXTRA_FOREGROUND_APPS, pkgs);
n.extras = extras;
n.when = System.currentTimeMillis() - 10000; // ten seconds ago
final StatusBarNotification sbn = makeMockSBN(userid, "android",
SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
null, n);
sbn.getNotification().extras = extras;
return sbn;
}
private NotificationEntry addFgEntry() {
NotificationEntry entry = createFgEntry();
mCollectionListener.onEntryAdded(entry);
return entry;
}
private NotificationEntry createFgEntry() {
return new NotificationEntryBuilder()
.setSbn(makeMockFgSBN(0, TEST_PACKAGE_NAME, 1000, true))
.setImportance(NotificationManager.IMPORTANCE_DEFAULT)
.build();
}
private void entryRemoved(StatusBarNotification notification) {
mCollectionListener.onEntryRemoved(
new NotificationEntryBuilder()
.setSbn(notification)
.build(),
REASON_APP_CANCEL);
}
private void entryAdded(StatusBarNotification notification, int importance) {
NotificationEntry entry = new NotificationEntryBuilder()
.setSbn(notification)
.setImportance(importance)
.build();
mCollectionListener.onEntryAdded(entry);
}
private void entryUpdated(StatusBarNotification notification, int importance) {
NotificationEntry entry = new NotificationEntryBuilder()
.setSbn(notification)
.setImportance(importance)
.build();
mCollectionListener.onEntryUpdated(entry);
}
@UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
@UserIdInt private static final int USERID_TWO = USERID_ONE + 1;
private static final String TEST_PACKAGE_NAME = "test";
}

View File

@@ -24,97 +24,53 @@ import static android.app.NotificationManager.IMPORTANCE_MIN;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
import android.content.Intent;
import android.graphics.Color;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class AppOpsCoordinatorTest extends SysuiTestCase {
private static final String TEST_PKG = "test_pkg";
private static final int NOTIF_USER_ID = 0;
public class ColorizedFgsCoordinatorTest extends SysuiTestCase {
@Mock private ForegroundServiceController mForegroundServiceController;
@Mock private AppOpsController mAppOpsController;
private static final int NOTIF_USER_ID = 0;
@Mock private NotifPipeline mNotifPipeline;
private NotificationEntryBuilder mEntryBuilder;
private AppOpsCoordinator mAppOpsCoordinator;
private NotifFilter mForegroundFilter;
private ColorizedFgsCoordinator mColorizedFgsCoordinator;
private NotifSectioner mFgsSection;
private FakeSystemClock mClock = new FakeSystemClock();
private FakeExecutor mExecutor = new FakeExecutor(mClock);
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
allowTestableLooperAsMainThread();
mAppOpsCoordinator =
new AppOpsCoordinator(
mForegroundServiceController,
mAppOpsController,
mExecutor);
mColorizedFgsCoordinator = new ColorizedFgsCoordinator();
mEntryBuilder = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID));
mAppOpsCoordinator.attach(mNotifPipeline);
mColorizedFgsCoordinator.attach(mNotifPipeline);
// capture filter
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
mForegroundFilter = filterCaptor.getValue();
mFgsSection = mAppOpsCoordinator.getSectioner();
}
@Test
public void filterTest_disclosureUnnecessary() {
NotificationEntry entry = mEntryBuilder.build();
StatusBarNotification sbn = entry.getSbn();
// GIVEN the notification is a disclosure notification
when(mForegroundServiceController.isDisclosureNotification(sbn)).thenReturn(true);
// GIVEN the disclosure isn't needed for this user
when(mForegroundServiceController.isDisclosureNeededForUser(sbn.getUserId()))
.thenReturn(false);
// THEN filter out the notification
assertTrue(mForegroundFilter.shouldFilterOut(entry, 0));
mFgsSection = mColorizedFgsCoordinator.getSectioner();
}
@Test

View File

@@ -32,7 +32,6 @@ import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
@@ -94,7 +93,6 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
mDependency.injectTestDependency(ShadeController.class, mShadeController);
mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class);
mDependency.injectMockDependency(NotificationShadeWindowController.class);
mDependency.injectMockDependency(ForegroundServiceNotificationListener.class);
NotificationShadeWindowView notificationShadeWindowView =
mock(NotificationShadeWindowView.class);