Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe375f36 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

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
parent 97c61a08
Loading
Loading
Loading
Loading
+2 −5
Original line number Diff line number Diff line
@@ -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);
+0 −183
Original line number Diff line number Diff line
/*
 * 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) {
        }
    }
}
+0 −150
Original line number Diff line number Diff line
/*
 * 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 */);
    }
}
+81 −0
Original line number Diff line number Diff line
@@ -19,91 +19,42 @@ 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
 * 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 AppOpsCoordinator implements Coordinator {
    private static final String TAG = "AppOpsCoordinator";

    private final ForegroundServiceController mForegroundServiceController;
    private final AppOpsController mAppOpsController;
    private final DelayableExecutor mMainExecutor;

    private NotifPipeline mNotifPipeline;
public class ColorizedFgsCoordinator implements Coordinator {
    private static final String TAG = "ColorizedCoordinator";

    @Inject
    public AppOpsCoordinator(
            ForegroundServiceController foregroundServiceController,
            AppOpsController appOpsController,
            @Main DelayableExecutor mainExecutor) {
        mForegroundServiceController = foregroundServiceController;
        mAppOpsController = appOpsController;
        mMainExecutor = mainExecutor;
    public ColorizedFgsCoordinator() {
    }

    @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",
    private final NotifSectioner mNotifSectioner = new NotifSectioner("ColorizedSectioner",
            NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE) {
        @Override
        public boolean isInSection(ListEntry entry) {
+30 −30
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ class NotifCoordinatorsImpl @Inject constructor(
        hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
        keyguardCoordinator: KeyguardCoordinator,
        rankingCoordinator: RankingCoordinator,
    appOpsCoordinator: AppOpsCoordinator,
        colorizedFgsCoordinator: ColorizedFgsCoordinator,
        deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
        bubbleCoordinator: BubbleCoordinator,
        headsUpCoordinator: HeadsUpCoordinator,
@@ -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
Loading