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

Commit 0adf6a6d authored by yoshiki iguchi's avatar yoshiki iguchi
Browse files

Revert "Split HeadsUpManager implementation to HeadsUpManagerPhone"

This reverts commit 78db3d0b.

Reason for revert: Cause crash

Test: none
Change-Id: Iffdad2513158c0856a0d3b56f7667063f4bba91c
parent e83fee27
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -379,7 +379,7 @@ public class CarStatusBar extends StatusBar implements
        // Because space is usually constrained in the auto use-case, there should not be a
        // pinned notification when the shade has been expanded. Ensure this by removing all heads-
        // up notifications.
        mHeadsUpManager.releaseAllImmediately();
        mHeadsUpManager.removeAllHeadsUpEntries();
        super.animateExpandNotificationsPanel();
    }

+0 −455
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.phone;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.support.v4.util.ArraySet;
import android.util.Log;
import android.util.Pools;
import android.view.View;
import android.view.ViewTreeObserver;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Stack;

/**
 * A implementation of HeadsUpManager for phone and car.
 */
public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
       ViewTreeObserver.OnComputeInternalInsetsListener, VisualStabilityManager.Callback,
       OnHeadsUpChangedListener {
    private static final String TAG = "HeadsUpManagerPhone";
    private static final boolean DEBUG = false;

    private final View mStatusBarWindowView;
    private final int mStatusBarHeight;
    private final NotificationGroupManager mGroupManager;
    private final StatusBar mBar;
    private final VisualStabilityManager mVisualStabilityManager;

    private boolean mReleaseOnExpandFinish;
    private boolean mTrackingHeadsUp;
    private HashSet<String> mSwipedOutKeys = new HashSet<>();
    private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
    private ArraySet<NotificationData.Entry> mEntriesToRemoveWhenReorderingAllowed
            = new ArraySet<>();
    private boolean mIsExpanded;
    private int[] mTmpTwoArray = new int[2];
    private boolean mHeadsUpGoingAway;
    private boolean mWaitingOnCollapseWhenGoingAway;
    private boolean mIsObserving;
    private int mStatusBarState;

    private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() {
        private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>();

        @Override
        public HeadsUpEntryPhone acquire() {
            if (!mPoolObjects.isEmpty()) {
                return mPoolObjects.pop();
            }
            return new HeadsUpEntryPhone();
        }

        @Override
        public boolean release(@NonNull HeadsUpEntryPhone instance) {
            instance.reset();
            mPoolObjects.push(instance);
            return true;
        }
    };

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  Constructor:

    public HeadsUpManagerPhone(@NonNull final Context context, @NonNull View statusBarWindowView,
            @NonNull NotificationGroupManager groupManager, @NonNull StatusBar bar,
            @NonNull VisualStabilityManager visualStabilityManager) {
        super(context);

        mStatusBarWindowView = statusBarWindowView;
        mGroupManager = groupManager;
        mBar = bar;
        mVisualStabilityManager = visualStabilityManager;

        Resources resources = mContext.getResources();
        mStatusBarHeight = resources.getDimensionPixelSize(
                com.android.internal.R.dimen.status_bar_height);

        addListener(new OnHeadsUpChangedListener() {
            @Override
            public void onHeadsUpPinnedModeChanged(boolean hasPinnedNotification) {
                if (DEBUG) Log.w(TAG, "onHeadsUpPinnedModeChanged");
                updateTouchableRegionListener();
            }
        });
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  Public methods:

    /**
     * Decides whether a click is invalid for a notification, i.e it has not been shown long enough
     * that a user might have consciously clicked on it.
     *
     * @param key the key of the touched notification
     * @return whether the touch is invalid and should be discarded
     */
    public boolean shouldSwallowClick(@NonNull String key) {
        HeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
        if (entry != null && mClock.currentTimeMillis() < entry.postTime) {
            return true;
        }
        return false;
    }

    public void onExpandingFinished() {
        if (mReleaseOnExpandFinish) {
            releaseAllImmediately();
            mReleaseOnExpandFinish = false;
        } else {
            for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
                if (isHeadsUp(entry.key)) {
                    // Maybe the heads-up was removed already
                    removeHeadsUpEntry(entry);
                }
            }
        }
        mEntriesToRemoveAfterExpand.clear();
    }

    /**
     * Sets the tracking-heads-up flag. If the flag is true, HeadsUpManager doesn't remove the entry
     * from the list even after a Heads Up Notification is gone.
     */
    public void setTrackingHeadsUp(boolean trackingHeadsUp) {
        mTrackingHeadsUp = trackingHeadsUp;
    }

    /**
     * Notify that the status bar panel gets expanded or collapsed.
     *
     * @param isExpanded True to notify expanded, false to notify collapsed.
     */
    public void setIsPanelExpanded(boolean isExpanded) {
        if (isExpanded != mIsExpanded) {
            mIsExpanded = isExpanded;
            if (isExpanded) {
                // make sure our state is sane
                mWaitingOnCollapseWhenGoingAway = false;
                mHeadsUpGoingAway = false;
                updateTouchableRegionListener();
            }
        }
    }

    /**
     * Set the current state of the statusbar.
     */
    public void setStatusBarState(int statusBarState) {
        mStatusBarState = statusBarState;
    }

    /**
     * Set that we are exiting the headsUp pinned mode, but some notifications might still be
     * animating out. This is used to keep the touchable regions in a sane state.
     */
    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
        if (headsUpGoingAway != mHeadsUpGoingAway) {
            mHeadsUpGoingAway = headsUpGoingAway;
            if (!headsUpGoingAway) {
                waitForStatusBarLayout();
            }
            updateTouchableRegionListener();
        }
    }

    /**
     * Notifies that a remote input textbox in notification gets active or inactive.
     * @param entry The entry of the target notification.
     * @param remoteInputActive True to notify active, False to notify inactive.
     */
    public void setRemoteInputActive(
            @NonNull NotificationData.Entry entry, boolean remoteInputActive) {
        HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.key);
        if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
            headsUpEntry.remoteInputActive = remoteInputActive;
            if (remoteInputActive) {
                headsUpEntry.removeAutoRemovalCallbacks();
            } else {
                headsUpEntry.updateEntry(false /* updatePostTime */);
            }
        }
    }

    @VisibleForTesting
    public void removeMinimumDisplayTimeForTesting() {
        mMinimumDisplayTime = 1;
        mHeadsUpNotificationDecay = 1;
        mTouchAcceptanceDelay = 1;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  HeadsUpManager public methods overrides:

    @Override
    public boolean isTrackingHeadsUp() {
        return mTrackingHeadsUp;
    }

    @Override
    public void snooze() {
        super.snooze();
        mReleaseOnExpandFinish = true;
    }

    /**
     * React to the removal of the notification in the heads up.
     *
     * @return true if the notification was removed and false if it still needs to be kept around
     * for a bit since it wasn't shown long enough
     */
    @Override
    public boolean removeNotification(@NonNull String key, boolean ignoreEarliestRemovalTime) {
        if (wasShownLongEnough(key) || ignoreEarliestRemovalTime) {
            return super.removeNotification(key, ignoreEarliestRemovalTime);
        } else {
            HeadsUpEntryPhone entry = getHeadsUpEntryPhone(key);
            entry.removeAsSoonAsPossible();
            return false;
        }
    }

    public void addSwipedOutNotification(@NonNull String key) {
        mSwipedOutKeys.add(key);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  Dumpable overrides:

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("HeadsUpManagerPhone state:");
        dumpInternal(fd, pw, args);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  ViewTreeObserver.OnComputeInternalInsetsListener overrides:

    /**
     * Overridden from TreeObserver.
     */
    @Override
    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
        if (mIsExpanded || mBar.isBouncerShowing()) {
            // The touchable region is always the full area when expanded
            return;
        }
        if (hasPinnedHeadsUp()) {
            ExpandableNotificationRow topEntry = getTopEntry().row;
            if (topEntry.isChildInGroup()) {
                final ExpandableNotificationRow groupSummary
                        = mGroupManager.getGroupSummary(topEntry.getStatusBarNotification());
                if (groupSummary != null) {
                    topEntry = groupSummary;
                }
            }
            topEntry.getLocationOnScreen(mTmpTwoArray);
            int minX = mTmpTwoArray[0];
            int maxX = mTmpTwoArray[0] + topEntry.getWidth();
            int maxY = topEntry.getIntrinsicHeight();

            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
            info.touchableRegion.set(minX, 0, maxX, maxY);
        } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
            info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
        }
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  VisualStabilityManager.Callback overrides:

    @Override
    public void onReorderingAllowed() {
        mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(false);
        for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
            if (isHeadsUp(entry.key)) {
                // Maybe the heads-up was removed already
                removeHeadsUpEntry(entry);
            }
        }
        mEntriesToRemoveWhenReorderingAllowed.clear();
        mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(true);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  HeadsUpManager utility (protected) methods overrides:

    @Override
    protected HeadsUpEntry createHeadsUpEntry() {
        return mEntryPool.acquire();
    }

    @Override
    protected void releaseHeadsUpEntry(HeadsUpEntry entry) {
        mEntryPool.release((HeadsUpEntryPhone) entry);
    }

    @Override
    protected boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) {
          return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
                  || super.shouldHeadsUpBecomePinned(entry);
    }

    @Override
    protected void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
        super.dumpInternal(fd, pw, args);
        pw.print("  mStatusBarState="); pw.println(mStatusBarState);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  Protected utility methods:

    @Nullable
    protected HeadsUpEntryPhone getHeadsUpEntryPhone(@NonNull String key) {
        return (HeadsUpEntryPhone) getHeadsUpEntry(key);
    }

    @Nullable
    protected HeadsUpEntryPhone getTopHeadsUpEntryPhone() {
        return (HeadsUpEntryPhone) getTopHeadsUpEntry();
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  Private utility methods:

    private boolean wasShownLongEnough(@NonNull String key) {
        if (mSwipedOutKeys.contains(key)) {
            // We always instantly dismiss views being manually swiped out.
            mSwipedOutKeys.remove(key);
            return true;
        }

        HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(key);
        HeadsUpEntryPhone topEntry = getTopHeadsUpEntryPhone();
        if (headsUpEntry != topEntry) {
            return true;
        }
        return headsUpEntry.wasShownLongEnough();
    }

    /**
     * We need to wait on the whole panel to collapse, before we can remove the touchable region
     * listener.
     */
    private void waitForStatusBarLayout() {
        mWaitingOnCollapseWhenGoingAway = true;
        mStatusBarWindowView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom,
                    int oldLeft,
                    int oldTop, int oldRight, int oldBottom) {
                if (mStatusBarWindowView.getHeight() <= mStatusBarHeight) {
                    mStatusBarWindowView.removeOnLayoutChangeListener(this);
                    mWaitingOnCollapseWhenGoingAway = false;
                    updateTouchableRegionListener();
                }
            }
        });
    }

    private void updateTouchableRegionListener() {
        boolean shouldObserve = hasPinnedHeadsUp() || mHeadsUpGoingAway
                || mWaitingOnCollapseWhenGoingAway;
        if (shouldObserve == mIsObserving) {
            return;
        }
        if (shouldObserve) {
            mStatusBarWindowView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
            mStatusBarWindowView.requestLayout();
        } else {
            mStatusBarWindowView.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
        }
        mIsObserving = shouldObserve;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //  HeadsUpEntryPhone:

    protected class HeadsUpEntryPhone extends HeadsUpManager.HeadsUpEntry {
        public void setEntry(@NonNull final NotificationData.Entry entry) {
           Runnable removeHeadsUpRunnable = () -> {
                if (!mVisualStabilityManager.isReorderingAllowed()) {
                    mEntriesToRemoveWhenReorderingAllowed.add(entry);
                    mVisualStabilityManager.addReorderingAllowedCallback(
                            HeadsUpManagerPhone.this);
                } else if (!mTrackingHeadsUp) {
                    removeHeadsUpEntry(entry);
                } else {
                    mEntriesToRemoveAfterExpand.add(entry);
                }
            };

            super.setEntry(entry, removeHeadsUpRunnable);
        }

        public boolean wasShownLongEnough() {
            return earliestRemovaltime < mClock.currentTimeMillis();
        }

        @Override
        public void updateEntry(boolean updatePostTime) {
            super.updateEntry(updatePostTime);

            if (mEntriesToRemoveAfterExpand.contains(entry)) {
                mEntriesToRemoveAfterExpand.remove(entry);
            }
            if (mEntriesToRemoveWhenReorderingAllowed.contains(entry)) {
                mEntriesToRemoveWhenReorderingAllowed.remove(entry);
            }
        }

        @Override
        public void expanded(boolean expanded) {
            if (this.expanded == expanded) {
                return;
            }

            this.expanded = expanded;
            if (expanded) {
                removeAutoRemovalCallbacks();
            } else {
                updateEntry(false /* updatePostTime */);
            }
        }
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ import android.view.ViewConfiguration;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;

/**
@@ -31,7 +31,7 @@ import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 */
public class HeadsUpTouchHelper implements Gefingerpoken {

    private HeadsUpManagerPhone mHeadsUpManager;
    private HeadsUpManager mHeadsUpManager;
    private NotificationStackScrollLayout mStackScroller;
    private int mTrackingPointer;
    private float mTouchSlop;
@@ -43,7 +43,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
    private NotificationPanelView mPanel;
    private ExpandableNotificationRow mPickedChild;

    public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager,
    public HeadsUpTouchHelper(HeadsUpManager headsUpManager,
            NotificationStackScrollLayout stackScroller,
            NotificationPanelView notificationPanelView) {
        mHeadsUpManager = headsUpManager;
+6 −4
Original line number Diff line number Diff line
@@ -68,12 +68,14 @@ import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;

import java.util.List;
import java.util.Collection;

public class NotificationPanelView extends PanelView implements
        ExpandableView.OnHeightChangedListener,
@@ -1569,7 +1571,7 @@ public class NotificationPanelView extends PanelView implements
    private void updatePanelExpanded() {
        boolean isExpanded = !isFullyCollapsed();
        if (mPanelExpanded != isExpanded) {
            mHeadsUpManager.setIsPanelExpanded(isExpanded);
            mHeadsUpManager.setIsExpanded(isExpanded);
            mStatusBar.setPanelExpanded(isExpanded);
            mPanelExpanded = isExpanded;
        }
@@ -2336,7 +2338,7 @@ public class NotificationPanelView extends PanelView implements
    }

    @Override
    public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
        super.setHeadsUpManager(headsUpManager);
        mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, mNotificationStackScroller,
                this);
@@ -2628,8 +2630,8 @@ public class NotificationPanelView extends PanelView implements
        }
    }

    public void setPulsing(boolean pulsing) {
        mKeyguardStatusView.setPulsing(pulsing);
    public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) {
        mKeyguardStatusView.setPulsing(pulsing != null);
        positionClockAndNotifications();
        mNotificationStackScroller.setPulsing(pulsing, mKeyguardStatusView.getLocationOnScreen()[1]
                + mKeyguardStatusView.getClockBottom());
+3 −3
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.policy.HeadsUpManager;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -75,7 +75,7 @@ public abstract class PanelView extends FrameLayout {
    }

    protected StatusBar mStatusBar;
    protected HeadsUpManagerPhone mHeadsUpManager;
    protected HeadsUpManager mHeadsUpManager;

    private float mPeekHeight;
    private float mHintDistance;
@@ -1252,7 +1252,7 @@ public abstract class PanelView extends FrameLayout {
     */
    protected abstract int getClearAllHeight();

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

Loading