blob: a0cda693822febe68f04a09d1d147f9164df070e [file] [log] [blame]
yoshiki iguchi4e30e762018-02-06 12:09:23 +09001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar.phone;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.content.Context;
Adrian Roos22af6502018-02-22 16:57:08 +010022import android.content.res.Configuration;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090023import android.content.res.Resources;
Issei Suzuki43190bd2018-08-20 17:28:41 +020024import android.graphics.Rect;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090025import android.util.Log;
26import android.util.Pools;
Jorim Jaggi71aaa402018-06-06 17:22:56 +020027import android.view.DisplayCutout;
28import android.view.Gravity;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090029import android.view.View;
30import android.view.ViewTreeObserver;
31
Gus Prevasab336792018-11-14 13:52:20 -050032import androidx.collection.ArraySet;
33
Jason Monk1fd3fc32018-08-14 17:20:09 -040034import com.android.systemui.Dependency;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090035import com.android.systemui.Dumpable;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080036import com.android.systemui.R;
Jorim Jaggi71aaa402018-06-06 17:22:56 +020037import com.android.systemui.ScreenDecorations;
Beverly8fdb5332019-02-04 14:29:49 -050038import com.android.systemui.plugins.statusbar.StatusBarStateController;
39import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Jason Monk1fd3fc32018-08-14 17:20:09 -040040import com.android.systemui.statusbar.StatusBarState;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090041import com.android.systemui.statusbar.notification.VisualStabilityManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050042import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Gus Prevasab336792018-11-14 13:52:20 -050043import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Adrian Roos22af6502018-02-22 16:57:08 +010044import com.android.systemui.statusbar.policy.ConfigurationController;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090045import com.android.systemui.statusbar.policy.HeadsUpManager;
46import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
47
48import java.io.FileDescriptor;
49import java.io.PrintWriter;
50import java.util.HashSet;
51import java.util.Stack;
52
53/**
54 * A implementation of HeadsUpManager for phone and car.
55 */
56public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
James O'Learycbea84d2019-03-14 11:18:24 -040057 VisualStabilityManager.Callback, OnHeadsUpChangedListener,
58 ConfigurationController.ConfigurationListener, StateListener {
yoshiki iguchi4e30e762018-02-06 12:09:23 +090059 private static final String TAG = "HeadsUpManagerPhone";
yoshiki iguchi4e30e762018-02-06 12:09:23 +090060
61 private final View mStatusBarWindowView;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090062 private final NotificationGroupManager mGroupManager;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090063 private final VisualStabilityManager mVisualStabilityManager;
James O'Learycbea84d2019-03-14 11:18:24 -040064 private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090065 private boolean mReleaseOnExpandFinish;
Selim Cinekaa9db1f2018-02-27 17:35:47 -080066
67 private int mStatusBarHeight;
68 private int mHeadsUpInset;
Jorim Jaggi71aaa402018-06-06 17:22:56 +020069 private int mDisplayCutoutTouchableRegionSize;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090070 private boolean mTrackingHeadsUp;
71 private HashSet<String> mSwipedOutKeys = new HashSet<>();
Ned Burnsf81c4c42019-01-07 14:10:43 -050072 private HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
73 private ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
yoshiki iguchi4e30e762018-02-06 12:09:23 +090074 = new ArraySet<>();
75 private boolean mIsExpanded;
76 private int[] mTmpTwoArray = new int[2];
77 private boolean mHeadsUpGoingAway;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090078 private int mStatusBarState;
Winson Chung9cd21152019-05-28 15:04:08 -070079 private Rect mTouchableRegion = new Rect();
yoshiki iguchi4e30e762018-02-06 12:09:23 +090080
Jason Monke59dc402018-08-16 12:05:01 -040081 private AnimationStateHandler mAnimationStateHandler;
Jason Monk1fd3fc32018-08-14 17:20:09 -040082
yoshiki iguchi4e30e762018-02-06 12:09:23 +090083 private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() {
84 private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>();
85
86 @Override
87 public HeadsUpEntryPhone acquire() {
88 if (!mPoolObjects.isEmpty()) {
89 return mPoolObjects.pop();
90 }
91 return new HeadsUpEntryPhone();
92 }
93
94 @Override
95 public boolean release(@NonNull HeadsUpEntryPhone instance) {
96 mPoolObjects.push(instance);
97 return true;
98 }
99 };
100
101 ///////////////////////////////////////////////////////////////////////////////////////////////
102 // Constructor:
103
James O'Learycbea84d2019-03-14 11:18:24 -0400104 public HeadsUpManagerPhone(@NonNull final Context context,
105 @NonNull View statusBarWindowView,
106 @NonNull NotificationGroupManager groupManager,
107 @NonNull StatusBar bar,
108 @NonNull VisualStabilityManager visualStabilityManager) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900109 super(context);
110
111 mStatusBarWindowView = statusBarWindowView;
James O'Learycbea84d2019-03-14 11:18:24 -0400112 mStatusBarTouchableRegionManager = new StatusBarTouchableRegionManager(context, this, bar,
113 statusBarWindowView);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900114 mGroupManager = groupManager;
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900115 mVisualStabilityManager = visualStabilityManager;
116
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800117 initResources();
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900118
119 addListener(new OnHeadsUpChangedListener() {
120 @Override
121 public void onHeadsUpPinnedModeChanged(boolean hasPinnedNotification) {
Kevind4f66a42018-08-03 13:12:51 -0700122 if (Log.isLoggable(TAG, Log.WARN)) {
123 Log.w(TAG, "onHeadsUpPinnedModeChanged");
124 }
James O'Learycbea84d2019-03-14 11:18:24 -0400125 mStatusBarTouchableRegionManager.updateTouchableRegion();
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900126 }
127 });
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800128 Dependency.get(StatusBarStateController.class).addCallback(this);
Jason Monk1fd3fc32018-08-14 17:20:09 -0400129 }
130
Jason Monke59dc402018-08-16 12:05:01 -0400131 public void setAnimationStateHandler(AnimationStateHandler handler) {
132 mAnimationStateHandler = handler;
133 }
134
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800135 private void initResources() {
136 Resources resources = mContext.getResources();
137 mStatusBarHeight = resources.getDimensionPixelSize(
138 com.android.internal.R.dimen.status_bar_height);
139 mHeadsUpInset = mStatusBarHeight + resources.getDimensionPixelSize(
140 R.dimen.heads_up_status_bar_padding);
Jorim Jaggi71aaa402018-06-06 17:22:56 +0200141 mDisplayCutoutTouchableRegionSize = resources.getDimensionPixelSize(
Jeff Changb0a061e2019-03-11 11:39:54 +0800142 com.android.internal.R.dimen.display_cutout_touchable_region_size);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800143 }
144
145 @Override
146 public void onDensityOrFontScaleChanged() {
147 super.onDensityOrFontScaleChanged();
148 initResources();
149 }
150
Jorim Jaggi71aaa402018-06-06 17:22:56 +0200151 @Override
152 public void onOverlayChanged() {
153 initResources();
154 }
155
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900156 ///////////////////////////////////////////////////////////////////////////////////////////////
157 // Public methods:
158
159 /**
160 * Decides whether a click is invalid for a notification, i.e it has not been shown long enough
161 * that a user might have consciously clicked on it.
162 *
163 * @param key the key of the touched notification
164 * @return whether the touch is invalid and should be discarded
165 */
166 public boolean shouldSwallowClick(@NonNull String key) {
167 HeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
Kevind4f66a42018-08-03 13:12:51 -0700168 return entry != null && mClock.currentTimeMillis() < entry.mPostTime;
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900169 }
170
171 public void onExpandingFinished() {
172 if (mReleaseOnExpandFinish) {
173 releaseAllImmediately();
174 mReleaseOnExpandFinish = false;
175 } else {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500176 for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
Kevina97ea052018-09-11 13:53:18 -0700177 if (isAlerting(entry.key)) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900178 // Maybe the heads-up was removed already
Kevind4f66a42018-08-03 13:12:51 -0700179 removeAlertEntry(entry.key);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900180 }
181 }
182 }
183 mEntriesToRemoveAfterExpand.clear();
184 }
185
186 /**
187 * Sets the tracking-heads-up flag. If the flag is true, HeadsUpManager doesn't remove the entry
188 * from the list even after a Heads Up Notification is gone.
189 */
190 public void setTrackingHeadsUp(boolean trackingHeadsUp) {
191 mTrackingHeadsUp = trackingHeadsUp;
192 }
193
194 /**
195 * Notify that the status bar panel gets expanded or collapsed.
196 *
197 * @param isExpanded True to notify expanded, false to notify collapsed.
198 */
199 public void setIsPanelExpanded(boolean isExpanded) {
200 if (isExpanded != mIsExpanded) {
201 mIsExpanded = isExpanded;
202 if (isExpanded) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900203 mHeadsUpGoingAway = false;
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900204 }
James O'Learycbea84d2019-03-14 11:18:24 -0400205 mStatusBarTouchableRegionManager.setIsStatusBarExpanded(isExpanded);
206 mStatusBarTouchableRegionManager.updateTouchableRegion();
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900207 }
208 }
209
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800210 @Override
211 public void onStateChanged(int newState) {
212 mStatusBarState = newState;
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900213 }
214
215 /**
216 * Set that we are exiting the headsUp pinned mode, but some notifications might still be
217 * animating out. This is used to keep the touchable regions in a sane state.
218 */
219 public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
220 if (headsUpGoingAway != mHeadsUpGoingAway) {
221 mHeadsUpGoingAway = headsUpGoingAway;
222 if (!headsUpGoingAway) {
James O'Learycbea84d2019-03-14 11:18:24 -0400223 mStatusBarTouchableRegionManager.updateTouchableRegionAfterLayout();
224 } else {
225 mStatusBarTouchableRegionManager.updateTouchableRegion();
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900226 }
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900227 }
228 }
229
James O'Learycbea84d2019-03-14 11:18:24 -0400230 public boolean isHeadsUpGoingAway() {
231 return mHeadsUpGoingAway;
232 }
233
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900234 /**
235 * Notifies that a remote input textbox in notification gets active or inactive.
James O'Learycbea84d2019-03-14 11:18:24 -0400236 *
237 * @param entry The entry of the target notification.
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900238 * @param remoteInputActive True to notify active, False to notify inactive.
239 */
240 public void setRemoteInputActive(
Ned Burnsf81c4c42019-01-07 14:10:43 -0500241 @NonNull NotificationEntry entry, boolean remoteInputActive) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900242 HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.key);
243 if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
244 headsUpEntry.remoteInputActive = remoteInputActive;
245 if (remoteInputActive) {
246 headsUpEntry.removeAutoRemovalCallbacks();
247 } else {
248 headsUpEntry.updateEntry(false /* updatePostTime */);
249 }
250 }
251 }
252
Gus Prevas211181532018-12-13 14:49:33 -0500253 /**
254 * Sets whether an entry's menu row is exposed and therefore it should stick in the heads up
255 * area if it's pinned until it's hidden again.
256 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500257 public void setMenuShown(@NonNull NotificationEntry entry, boolean menuShown) {
Gus Prevas211181532018-12-13 14:49:33 -0500258 HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key);
259 if (headsUpEntry instanceof HeadsUpEntryPhone && entry.isRowPinned()) {
260 ((HeadsUpEntryPhone) headsUpEntry).setMenuShownPinned(menuShown);
261 }
262 }
263
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900264 ///////////////////////////////////////////////////////////////////////////////////////////////
265 // HeadsUpManager public methods overrides:
266
267 @Override
268 public boolean isTrackingHeadsUp() {
269 return mTrackingHeadsUp;
270 }
271
Kevind4f66a42018-08-03 13:12:51 -0700272 @Override
273 public void snooze() {
274 super.snooze();
275 mReleaseOnExpandFinish = true;
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900276 }
277
278 public void addSwipedOutNotification(@NonNull String key) {
279 mSwipedOutKeys.add(key);
280 }
281
282 ///////////////////////////////////////////////////////////////////////////////////////////////
283 // Dumpable overrides:
284
285 @Override
286 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
287 pw.println("HeadsUpManagerPhone state:");
288 dumpInternal(fd, pw, args);
289 }
290
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900291 /**
James O'Learycbea84d2019-03-14 11:18:24 -0400292 * Update touch insets to include any area needed for touching a heads up notification.
293 *
294 * @param info Insets that will include heads up notification touch area after execution.
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900295 */
James O'Learycbea84d2019-03-14 11:18:24 -0400296 @Nullable
297 public void updateTouchableRegion(ViewTreeObserver.InternalInsetsInfo info) {
298 info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
Winson Chung9cd21152019-05-28 15:04:08 -0700299 info.touchableRegion.set(calculateTouchableRegion());
300 }
James O'Learycbea84d2019-03-14 11:18:24 -0400301
Winson Chung9cd21152019-05-28 15:04:08 -0700302 public Rect calculateTouchableRegion() {
James O'Learycbea84d2019-03-14 11:18:24 -0400303 if (!hasPinnedHeadsUp()) {
Winson Chung9cd21152019-05-28 15:04:08 -0700304 mTouchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
305 updateRegionForNotch(mTouchableRegion);
James O'Learycbea84d2019-03-14 11:18:24 -0400306 } else {
Ned Burnsf81c4c42019-01-07 14:10:43 -0500307 NotificationEntry topEntry = getTopEntry();
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900308 if (topEntry.isChildInGroup()) {
James O'Learycbea84d2019-03-14 11:18:24 -0400309 final NotificationEntry groupSummary =
310 mGroupManager.getGroupSummary(topEntry.notification);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900311 if (groupSummary != null) {
312 topEntry = groupSummary;
313 }
314 }
Evan Laird94492852018-10-25 13:43:01 -0400315 ExpandableNotificationRow topRow = topEntry.getRow();
316 topRow.getLocationOnScreen(mTmpTwoArray);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900317 int minX = mTmpTwoArray[0];
Evan Laird94492852018-10-25 13:43:01 -0400318 int maxX = mTmpTwoArray[0] + topRow.getWidth();
319 int height = topRow.getIntrinsicHeight();
Winson Chung9cd21152019-05-28 15:04:08 -0700320 mTouchableRegion.set(minX, 0, maxX, mHeadsUpInset + height);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900321 }
Winson Chung9cd21152019-05-28 15:04:08 -0700322 return mTouchableRegion;
Jorim Jaggi71aaa402018-06-06 17:22:56 +0200323 }
324
Winson Chung9cd21152019-05-28 15:04:08 -0700325 private void updateRegionForNotch(Rect region) {
Jorim Jaggi71aaa402018-06-06 17:22:56 +0200326 DisplayCutout cutout = mStatusBarWindowView.getRootWindowInsets().getDisplayCutout();
327 if (cutout == null) {
328 return;
329 }
330
331 // Expand touchable region such that we also catch touches that just start below the notch
332 // area.
Issei Suzuki43190bd2018-08-20 17:28:41 +0200333 Rect bounds = new Rect();
334 ScreenDecorations.DisplayCutoutView.boundsFromDirection(cutout, Gravity.TOP, bounds);
335 bounds.offset(0, mDisplayCutoutTouchableRegionSize);
Winson Chung9cd21152019-05-28 15:04:08 -0700336 region.union(bounds);
Jorim Jaggi71aaa402018-06-06 17:22:56 +0200337 }
338
Adrian Roos22af6502018-02-22 16:57:08 +0100339 @Override
Selim Cinekbd559092019-01-28 19:38:58 -0800340 public boolean shouldExtendLifetime(NotificationEntry entry) {
341 // We should not defer the removal if reordering isn't allowed since otherwise
342 // these won't disappear until reordering is allowed again, which happens only once
343 // the notification panel is collapsed again.
344 return mVisualStabilityManager.isReorderingAllowed() && super.shouldExtendLifetime(entry);
345 }
346
347 @Override
Adrian Roos22af6502018-02-22 16:57:08 +0100348 public void onConfigChanged(Configuration newConfig) {
James O'Learycbea84d2019-03-14 11:18:24 -0400349 initResources();
Adrian Roos22af6502018-02-22 16:57:08 +0100350 }
351
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900352 ///////////////////////////////////////////////////////////////////////////////////////////////
353 // VisualStabilityManager.Callback overrides:
354
355 @Override
356 public void onReorderingAllowed() {
Jason Monke59dc402018-08-16 12:05:01 -0400357 mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500358 for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
Kevina97ea052018-09-11 13:53:18 -0700359 if (isAlerting(entry.key)) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900360 // Maybe the heads-up was removed already
Kevind4f66a42018-08-03 13:12:51 -0700361 removeAlertEntry(entry.key);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900362 }
363 }
364 mEntriesToRemoveWhenReorderingAllowed.clear();
Jason Monke59dc402018-08-16 12:05:01 -0400365 mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900366 }
367
368 ///////////////////////////////////////////////////////////////////////////////////////////////
369 // HeadsUpManager utility (protected) methods overrides:
370
371 @Override
Kevind4f66a42018-08-03 13:12:51 -0700372 protected HeadsUpEntry createAlertEntry() {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900373 return mEntryPool.acquire();
374 }
375
376 @Override
Kevind4f66a42018-08-03 13:12:51 -0700377 protected void onAlertEntryRemoved(AlertEntry alertEntry) {
378 super.onAlertEntryRemoved(alertEntry);
379 mEntryPool.release((HeadsUpEntryPhone) alertEntry);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900380 }
381
382 @Override
Ned Burnsf81c4c42019-01-07 14:10:43 -0500383 protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) {
James O'Learycbea84d2019-03-14 11:18:24 -0400384 return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
385 || super.shouldHeadsUpBecomePinned(entry);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900386 }
387
388 @Override
389 protected void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
390 super.dumpInternal(fd, pw, args);
James O'Learycbea84d2019-03-14 11:18:24 -0400391 pw.print(" mBarState=");
392 pw.println(mStatusBarState);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900393 }
394
395 ///////////////////////////////////////////////////////////////////////////////////////////////
396 // Private utility methods:
397
398 @Nullable
399 private HeadsUpEntryPhone getHeadsUpEntryPhone(@NonNull String key) {
Kevind4f66a42018-08-03 13:12:51 -0700400 return (HeadsUpEntryPhone) mAlertEntries.get(key);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900401 }
402
403 @Nullable
404 private HeadsUpEntryPhone getTopHeadsUpEntryPhone() {
405 return (HeadsUpEntryPhone) getTopHeadsUpEntry();
406 }
407
Kevina5ff1fa2018-08-21 16:35:48 -0700408 @Override
409 protected boolean canRemoveImmediately(@NonNull String key) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900410 if (mSwipedOutKeys.contains(key)) {
411 // We always instantly dismiss views being manually swiped out.
412 mSwipedOutKeys.remove(key);
413 return true;
414 }
415
416 HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(key);
417 HeadsUpEntryPhone topEntry = getTopHeadsUpEntryPhone();
Kevina5ff1fa2018-08-21 16:35:48 -0700418
419 return headsUpEntry == null || headsUpEntry != topEntry || super.canRemoveImmediately(key);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900420 }
421
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900422 ///////////////////////////////////////////////////////////////////////////////////////////////
423 // HeadsUpEntryPhone:
424
425 protected class HeadsUpEntryPhone extends HeadsUpManager.HeadsUpEntry {
Gus Prevas211181532018-12-13 14:49:33 -0500426
427 private boolean mMenuShownPinned;
428
429 @Override
430 protected boolean isSticky() {
431 return super.isSticky() || mMenuShownPinned;
432 }
433
Ned Burnsf81c4c42019-01-07 14:10:43 -0500434 public void setEntry(@NonNull final NotificationEntry entry) {
James O'Learycbea84d2019-03-14 11:18:24 -0400435 Runnable removeHeadsUpRunnable = () -> {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900436 if (!mVisualStabilityManager.isReorderingAllowed()) {
437 mEntriesToRemoveWhenReorderingAllowed.add(entry);
438 mVisualStabilityManager.addReorderingAllowedCallback(
439 HeadsUpManagerPhone.this);
440 } else if (!mTrackingHeadsUp) {
Kevind4f66a42018-08-03 13:12:51 -0700441 removeAlertEntry(entry.key);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900442 } else {
443 mEntriesToRemoveAfterExpand.add(entry);
444 }
445 };
446
Kevind4f66a42018-08-03 13:12:51 -0700447 setEntry(entry, removeHeadsUpRunnable);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900448 }
449
450 @Override
451 public void updateEntry(boolean updatePostTime) {
452 super.updateEntry(updatePostTime);
453
Kevind4f66a42018-08-03 13:12:51 -0700454 if (mEntriesToRemoveAfterExpand.contains(mEntry)) {
455 mEntriesToRemoveAfterExpand.remove(mEntry);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900456 }
Kevind4f66a42018-08-03 13:12:51 -0700457 if (mEntriesToRemoveWhenReorderingAllowed.contains(mEntry)) {
458 mEntriesToRemoveWhenReorderingAllowed.remove(mEntry);
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900459 }
460 }
461
462 @Override
Kevind4f66a42018-08-03 13:12:51 -0700463 public void setExpanded(boolean expanded) {
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900464 if (this.expanded == expanded) {
465 return;
466 }
467
468 this.expanded = expanded;
469 if (expanded) {
470 removeAutoRemovalCallbacks();
471 } else {
472 updateEntry(false /* updatePostTime */);
473 }
474 }
Gus Prevas211181532018-12-13 14:49:33 -0500475
476 public void setMenuShownPinned(boolean menuShownPinned) {
477 if (mMenuShownPinned == menuShownPinned) {
478 return;
479 }
480
481 mMenuShownPinned = menuShownPinned;
482 if (menuShownPinned) {
483 removeAutoRemovalCallbacks();
484 } else {
485 updateEntry(false /* updatePostTime */);
486 }
487 }
488
489 @Override
490 public void reset() {
491 super.reset();
492 mMenuShownPinned = false;
493 }
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900494 }
Jason Monke59dc402018-08-16 12:05:01 -0400495
496 public interface AnimationStateHandler {
497 void setHeadsUpGoingAwayAnimationsAllowed(boolean allowed);
498 }
yoshiki iguchi4e30e762018-02-06 12:09:23 +0900499}