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

Commit 803e1a1d authored by Julia Reynolds's avatar Julia Reynolds Committed by Automerger Merge Worker
Browse files

Merge "Remove obsolete FGS notification code" into udc-qpr-dev am: d67ec2dd am: 600c15f9

parents 2857e23b 600c15f9
Loading
Loading
Loading
Loading
+2 −5
Original line number Diff line number Diff line
@@ -130,14 +130,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.
@@ -278,7 +278,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;
@@ -456,8 +455,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