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

Commit ee9445e3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topics "nem-low-prio-state", "nem-group-manager",...

Merge changes from topics "nem-low-prio-state", "nem-group-manager", "nem-remote-input-manager", "nem-media-manager", "nem-perform-remove", "nem-combine-remove-callbacks", "nem-callback-to-listener", "nem-alert-handling-listeners"

* changes:
  Moves minimization change handling into NotificationEntryListeners.
  Removes dependency of NotificationEntryManager on NotificationGroupManager.
  Makes NotificationRemoteInputManager a NotificationEntryListener.
  Removes circular dependency between NotificationMediaManager and NotificationEntryManager.
  Combines NotificationEntryManager listener interfaces (part 5).
  Combines NotificationEntryManager listener interfaces (part 4).
  Combines NotificationEntryManager listener interfaces (part 3).
  Combines NotificationEntryManager listener interfaces (part 2).
parents 3fb6a1be 5b9098dc
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
@@ -266,6 +267,8 @@ public class Dependency extends SystemUI {
    @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
    @Inject Lazy<BubbleController> mBubbleController;
    @Inject Lazy<NotificationEntryManager> mNotificationEntryManager;
    @Inject
    Lazy<NotificationAlertingManager> mNotificationAlertingManager;
    @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
    @Inject @Named(BG_LOOPER_NAME) Lazy<Looper> mBgLooper;
    @Inject @Named(BG_HANDLER_NAME) Lazy<Handler> mBgHandler;
@@ -439,6 +442,7 @@ public class Dependency extends SystemUI {
                mRemoteInputQuickSettingsDisabler::get);
        mProviders.put(BubbleController.class, mBubbleController::get);
        mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
        mProviders.put(NotificationAlertingManager.class, mNotificationAlertingManager::get);

        sDependency = this;
    }
+0 −30
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.car;

import android.content.Context;

import com.android.systemui.statusbar.NotificationMediaManager;

public class CarNotificationMediaManager extends NotificationMediaManager {
    public CarNotificationMediaManager(Context context) {
        super(context);
    }

    @Override
    public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
        // Do nothing, we don't want to display media art in the lock screen for a car.
    }
}
+44 −45
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.media.session.PlaybackState;
import android.os.Handler;
import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@@ -45,8 +46,8 @@ import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
@@ -64,6 +65,8 @@ import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;

import dagger.Lazy;

/**
 * Handles tasks and state related to media notifications. For example, there is a 'current' media
 * notification, which this class keeps track of.
@@ -83,9 +86,9 @@ public class NotificationMediaManager implements Dumpable {

    // Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
    @Nullable
    private ShadeController mShadeController;
    private Lazy<ShadeController> mShadeController;
    @Nullable
    private StatusBarWindowController mStatusBarWindowController;
    private Lazy<StatusBarWindowController> mStatusBarWindowController;

    @Nullable
    private BiometricUnlockController mBiometricUnlockController;
@@ -135,37 +138,34 @@ public class NotificationMediaManager implements Dumpable {
        }
    };

    @Nullable
    private ShadeController getShadeController() {
        if (mShadeController == null) {
            mShadeController = Dependency.get(ShadeController.class);
        }
        return mShadeController;
    }

    @Nullable
    private StatusBarWindowController getWindowController() {
        if (mStatusBarWindowController == null) {
            mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
        }
        return mStatusBarWindowController;
    }

    private NotificationEntryManager getEntryManager() {
        if (mEntryManager == null) {
            mEntryManager = Dependency.get(NotificationEntryManager.class);
        }
        return mEntryManager;
    }

    @Inject
    public NotificationMediaManager(Context context) {
    public NotificationMediaManager(
            Context context,
            Lazy<ShadeController> shadeController,
            Lazy<StatusBarWindowController> statusBarWindowController,
            NotificationEntryManager notificationEntryManager) {
        mContext = context;
        mMediaListeners = new ArrayList<>();
        mMediaSessionManager
                = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
        // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
        // in session state
        mShadeController = shadeController;
        mStatusBarWindowController = statusBarWindowController;
        mEntryManager = notificationEntryManager;
        notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
            @Override
            public void onEntryRemoved(
                    Entry entry,
                    String key,
                    StatusBarNotification old,
                    boolean lifetimeExtended,
                    boolean removedByUser) {
                if (!lifetimeExtended) {
                    onNotificationRemoved(key);
                }
            }
        });
    }

    public void setUpWithPresenter(NotificationPresenter presenter) {
@@ -191,9 +191,8 @@ public class NotificationMediaManager implements Dumpable {
        if (mMediaNotificationKey == null) {
            return null;
        }
        NotificationEntryManager manager = getEntryManager();
        synchronized (manager.getNotificationData()) {
            Entry entry = manager.getNotificationData().get(mMediaNotificationKey);
        synchronized (mEntryManager.getNotificationData()) {
            Entry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
            if (entry == null || entry.expandedIcon == null) {
                return null;
            }
@@ -214,10 +213,9 @@ public class NotificationMediaManager implements Dumpable {
    public void findAndUpdateMediaNotifications() {
        boolean metaDataChanged = false;

        NotificationEntryManager manager = getEntryManager();
        synchronized (manager.getNotificationData()) {
            ArrayList<Entry> activeNotifications = manager
                    .getNotificationData().getActiveNotifications();
        synchronized (mEntryManager.getNotificationData()) {
            ArrayList<Entry> activeNotifications =
                    mEntryManager.getNotificationData().getActiveNotifications();
            final int N = activeNotifications.size();

            // Promote the media notification with a controller in 'playing' state, if any.
@@ -305,7 +303,7 @@ public class NotificationMediaManager implements Dumpable {
        }

        if (metaDataChanged) {
            getEntryManager().updateNotifications();
            mEntryManager.updateNotifications();
        }

        dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
@@ -440,8 +438,9 @@ public class NotificationMediaManager implements Dumpable {
            }
        }

        boolean hideBecauseOccluded = getShadeController() != null
                && getShadeController().isOccluded();
        ShadeController shadeController = mShadeController.get();
        StatusBarWindowController windowController = mStatusBarWindowController.get();
        boolean hideBecauseOccluded = shadeController != null && shadeController.isOccluded();

        final boolean hasArtwork = artworkDrawable != null;
        mColorExtractor.setHasBackdrop(hasArtwork);
@@ -464,8 +463,8 @@ public class NotificationMediaManager implements Dumpable {
                    mBackdrop.animate().cancel();
                    mBackdrop.setAlpha(1f);
                }
                if (getWindowController() != null) {
                    getWindowController().setBackdropShowing(true);
                if (windowController != null) {
                    windowController.setBackdropShowing(true);
                }
                metaDataChanged = true;
                if (DEBUG_MEDIA) {
@@ -512,8 +511,8 @@ public class NotificationMediaManager implements Dumpable {
                if (DEBUG_MEDIA) {
                    Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
                }
                boolean cannotAnimateDoze = getShadeController() != null
                        && getShadeController().isDozing()
                boolean cannotAnimateDoze = shadeController != null
                        && shadeController.isDozing()
                        && !ScrimState.AOD.getAnimateChange();
                if (mBiometricUnlockController != null && mBiometricUnlockController.getMode()
                        == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
@@ -522,12 +521,12 @@ public class NotificationMediaManager implements Dumpable {
                    // We are unlocking directly - no animation!
                    mBackdrop.setVisibility(View.GONE);
                    mBackdropBack.setImageDrawable(null);
                    if (getWindowController() != null) {
                        getWindowController().setBackdropShowing(false);
                    if (windowController != null) {
                        windowController.setBackdropShowing(false);
                    }
                } else {
                    if (getWindowController() != null) {
                        getWindowController().setBackdropShowing(false);
                    if (windowController != null) {
                        windowController.setBackdropShowing(false);
                    }
                    mBackdrop.animate()
                            .alpha(0)
+44 −23
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@ package com.android.systemui.statusbar;

import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;

import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;

import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -26,6 +28,7 @@ import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -46,9 +49,9 @@ import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -60,8 +63,11 @@ import java.util.ArrayList;
import java.util.Set;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import dagger.Lazy;

/**
 * Class for handling remote input state over a set of notifications. This class handles things
 * like keeping notifications temporarily that were cancelled as a response to a remote input
@@ -100,15 +106,12 @@ public class NotificationRemoteInputManager implements Dumpable {
            new ArraySet<>();

    // Dependencies:
    protected final NotificationLockscreenUserManager mLockscreenUserManager =
            Dependency.get(NotificationLockscreenUserManager.class);
    protected final SmartReplyController mSmartReplyController =
            Dependency.get(SmartReplyController.class);
    private final NotificationEntryManager mEntryManager
            = Dependency.get(NotificationEntryManager.class);
    private final NotificationLockscreenUserManager mLockscreenUserManager;
    private final SmartReplyController mSmartReplyController;
    private final NotificationEntryManager mEntryManager;
    private final Handler mMainHandler;

    // Lazy
    private ShadeController mShadeController;
    private final Lazy<ShadeController> mShadeController;

    protected final Context mContext;
    private final UserManager mUserManager;
@@ -126,7 +129,7 @@ public class NotificationRemoteInputManager implements Dumpable {
        @Override
        public boolean onClickHandler(
                View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) {
            getShadeController().wakeUpIfDozing(SystemClock.uptimeMillis(), view);
            mShadeController.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view);

            if (handleRemoteInput(view, pendingIntent)) {
                return true;
@@ -226,21 +229,39 @@ public class NotificationRemoteInputManager implements Dumpable {
        }
    };

    private ShadeController getShadeController() {
        if (mShadeController == null) {
            mShadeController = Dependency.get(ShadeController.class);
        }
        return mShadeController;
    }

    @Inject
    public NotificationRemoteInputManager(Context context) {
    public NotificationRemoteInputManager(
            Context context,
            NotificationLockscreenUserManager lockscreenUserManager,
            SmartReplyController smartReplyController,
            NotificationEntryManager notificationEntryManager,
            Lazy<ShadeController> shadeController,
            @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
        mContext = context;
        mLockscreenUserManager = lockscreenUserManager;
        mSmartReplyController = smartReplyController;
        mEntryManager = notificationEntryManager;
        mShadeController = shadeController;
        mMainHandler = mainHandler;
        mBarService = IStatusBarService.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        addLifetimeExtenders();
        mKeyguardManager = context.getSystemService(KeyguardManager.class);

        notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
            @Override
            public void onEntryRemoved(
                    NotificationData.Entry entry,
                    String key,
                    StatusBarNotification old,
                    boolean lifetimeExtended,
                    boolean removedByUser) {
                if (removedByUser) {
                    onPerformRemoveNotification(entry, key);
                }
            }
        });
    }

    /** Initializes this component with the provided dependencies. */
@@ -258,7 +279,7 @@ public class NotificationRemoteInputManager implements Dumpable {
                    // view it is already canceled, so we'll need to cancel it on the apps behalf
                    // after sending - unless the app posts an update in the mean time, so wait a
                    // bit.
                    Dependency.get(Dependency.MAIN_HANDLER).postDelayed(() -> {
                    mMainHandler.postDelayed(() -> {
                        if (mEntriesKeptForRemoteInputActive.remove(entry)) {
                            mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
                        }
@@ -392,10 +413,10 @@ public class NotificationRemoteInputManager implements Dumpable {
        return mRemoteInputController;
    }

    public void onPerformRemoveNotification(StatusBarNotification n,
            NotificationData.Entry entry) {
        if (mKeysKeptForRemoteInputHistory.contains(n.getKey())) {
            mKeysKeptForRemoteInputHistory.remove(n.getKey());
    @VisibleForTesting
    void onPerformRemoveNotification(NotificationData.Entry entry, final String key) {
        if (mKeysKeptForRemoteInputHistory.contains(key)) {
            mKeysKeptForRemoteInputHistory.remove(key);
        }
        if (mRemoteInputController.isRemoteInputActive(entry)) {
            mRemoteInputController.removeRemoteInput(entry, null);
+186 −0
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.statusbar.notification;

import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;

import android.app.Notification;
import android.service.notification.StatusBarNotification;
import android.util.Log;

import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;

import javax.inject.Inject;
import javax.inject.Singleton;

import dagger.Lazy;

/** Handles heads-up and pulsing behavior driven by notification changes. */
@Singleton
public class NotificationAlertingManager {

    private static final String TAG = "NotifAlertManager";

    private final AmbientPulseManager mAmbientPulseManager;
    private final NotificationRemoteInputManager mRemoteInputManager;
    private final VisualStabilityManager mVisualStabilityManager;
    private final Lazy<ShadeController> mShadeController;
    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
    private final NotificationListener mNotificationListener;

    private HeadsUpManager mHeadsUpManager;

    @Inject
    public NotificationAlertingManager(
            NotificationEntryManager notificationEntryManager,
            AmbientPulseManager ambientPulseManager,
            NotificationRemoteInputManager remoteInputManager,
            VisualStabilityManager visualStabilityManager,
            Lazy<ShadeController> shadeController,
            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
            NotificationListener notificationListener) {
        mAmbientPulseManager = ambientPulseManager;
        mRemoteInputManager = remoteInputManager;
        mVisualStabilityManager = visualStabilityManager;
        mShadeController = shadeController;
        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
        mNotificationListener = notificationListener;

        notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
            @Override
            public void onEntryInflated(NotificationData.Entry entry, int inflatedFlags) {
                showAlertingView(entry, inflatedFlags);
            }

            @Override
            public void onEntryUpdated(NotificationData.Entry entry) {
                updateAlertState(entry);
            }

            @Override
            public void onEntryRemoved(
                    NotificationData.Entry entry,
                    String key,
                    StatusBarNotification old,
                    boolean lifetimeExtended,
                    boolean removedByUser) {
                stopAlerting(key);
            }
        });
    }

    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
        mHeadsUpManager = headsUpManager;
    }

    /**
     * Adds the entry to the respective alerting manager if the content view was inflated and
     * the entry should still alert.
     *
     * @param entry         entry to add
     * @param inflatedFlags flags representing content views that were inflated
     */
    private void showAlertingView(NotificationData.Entry entry,
            @NotificationInflater.InflationFlag int inflatedFlags) {
        if ((inflatedFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
            // Possible for shouldHeadsUp to change between the inflation starting and ending.
            // If it does and we no longer need to heads up, we should free the view.
            if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
                mHeadsUpManager.showNotification(entry);
                // Mark as seen immediately
                setNotificationShown(entry.notification);
            } else {
                entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
            }
        }
        if ((inflatedFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
            if (mNotificationInterruptionStateProvider.shouldPulse(entry)) {
                mAmbientPulseManager.showNotification(entry);
            } else {
                entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
            }
        }
    }

    private void updateAlertState(NotificationData.Entry entry) {
        boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
        AlertingNotificationManager alertManager;
        boolean shouldAlert;
        if (mShadeController.get().isDozing()) {
            alertManager = mAmbientPulseManager;
            shouldAlert = mNotificationInterruptionStateProvider.shouldPulse(entry);
        } else {
            alertManager = mHeadsUpManager;
            shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
        }
        final boolean wasAlerting = alertManager.isAlerting(entry.key);
        if (wasAlerting) {
            if (!shouldAlert) {
                // We don't want this to be interrupting anymore, let's remove it
                alertManager.removeNotification(entry.key,
                        false /* ignoreEarliestRemovalTime */);
            } else {
                alertManager.updateNotification(entry.key, alertAgain);
            }
        } else if (shouldAlert && alertAgain) {
            // This notification was updated to be alerting, show it!
            alertManager.showNotification(entry);
        }
    }

    private static boolean alertAgain(
            NotificationData.Entry oldEntry, Notification newNotification) {
        return oldEntry == null || !oldEntry.hasInterrupted()
                || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
    }

    private void setNotificationShown(StatusBarNotification n) {
        try {
            mNotificationListener.setNotificationsShown(new String[]{n.getKey()});
        } catch (RuntimeException e) {
            Log.d(TAG, "failed setNotificationsShown: ", e);
        }
    }

    private void stopAlerting(final String key) {
        // Attempt to remove notifications from their alert managers (heads up, ambient pulse).
        // Though the remove itself may fail, it lets the manager know to remove as soon as
        // possible.
        if (mHeadsUpManager.isAlerting(key)) {
            // A cancel() in response to a remote input shouldn't be delayed, as it makes the
            // sending look longer than it takes.
            // Also we should not defer the removal if reordering isn't allowed since otherwise
            // some notifications can't disappear before the panel is closed.
            boolean ignoreEarliestRemovalTime =
                    mRemoteInputManager.getController().isSpinning(key)
                            && !FORCE_REMOTE_INPUT_HISTORY
                            || !mVisualStabilityManager.isReorderingAllowed();
            mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
        }
        if (mAmbientPulseManager.isAlerting(key)) {
            mAmbientPulseManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
        }
    }
}
Loading