HeadsUpManager.java revision fbe9a44a15addf9d94cd40da56835501241b8d3e
1b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek/* 2b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Copyright (C) 2011 The Android Open Source Project 3b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * 4b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Licensed under the Apache License, Version 2.0 (the "License"); 5b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * you may not use this file except in compliance with the License. 6b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * You may obtain a copy of the License at 7b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * 8b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * http://www.apache.org/licenses/LICENSE-2.0 9b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * 10b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Unless required by applicable law or agreed to in writing, software 11b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * distributed under the License is distributed on an "AS IS" BASIS, 12b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * See the License for the specific language governing permissions and 14b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * limitations under the License. 15b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 16b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 17b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekpackage com.android.systemui.statusbar.policy; 18b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 19b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.content.Context; 20b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.content.res.Resources; 21b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.database.ContentObserver; 22b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.os.Handler; 23b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.os.SystemClock; 24b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.provider.Settings; 25b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.util.ArrayMap; 26b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.util.Log; 27b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.util.Pools; 28b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.view.View; 29b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.view.ViewTreeObserver; 30b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport android.view.accessibility.AccessibilityEvent; 31b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 32b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.R; 33a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinekimport com.android.systemui.statusbar.ExpandableNotificationRow; 34b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.NotificationData; 35b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport com.android.systemui.statusbar.phone.PhoneStatusBar; 36b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 37b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport java.io.FileDescriptor; 38b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport java.io.PrintWriter; 39a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinekimport java.util.HashMap; 40b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport java.util.HashSet; 41b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinekimport java.util.Stack; 42a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinekimport java.util.TreeSet; 43b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 44a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinekpublic class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsListener { 45b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private static final String TAG = "HeadsUpManager"; 46b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private static final boolean DEBUG = false; 47b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms"; 48b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 49b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private final int mHeadsUpNotificationDecay; 50b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private final int mMinimumDisplayTime; 51b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 52b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private final int mTouchSensitivityDelay; 53b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private final ArrayMap<String, Long> mSnoozedPackages; 54b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private final HashSet<OnHeadsUpChangedListener> mListeners = new HashSet<>(); 55b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private final int mDefaultSnoozeLengthMs; 56b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private final Handler mHandler = new Handler(); 57b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private final Pools.Pool<HeadsUpEntry> mEntryPool = new Pools.Pool<HeadsUpEntry>() { 58b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 59b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private Stack<HeadsUpEntry> mPoolObjects = new Stack<>(); 60b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 61b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 62b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public HeadsUpEntry acquire() { 63b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (!mPoolObjects.isEmpty()) { 64b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mPoolObjects.pop(); 65b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 66b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return new HeadsUpEntry(); 67b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 68b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 69b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 70b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean release(HeadsUpEntry instance) { 71b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek instance.removeAutoCancelCallbacks(); 72b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mPoolObjects.push(instance); 73b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 74b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 75b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek }; 76b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 77b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 78b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private PhoneStatusBar mBar; 79b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private int mSnoozeLengthMs; 80b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private ContentObserver mSettingsObserver; 81a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private HashMap<String, HeadsUpEntry> mHeadsUpEntries = new HashMap<>(); 82a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private TreeSet<HeadsUpEntry> mSortedEntries = new TreeSet<>(); 83b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private HashSet<String> mSwipedOutKeys = new HashSet<>(); 84b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private int mUser; 85b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private Clock mClock; 86b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mReleaseOnExpandFinish; 87b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mTrackingHeadsUp; 88b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>(); 89b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mIsExpanded; 90b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean mHasPinnedHeadsUp; 91a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private int[] mTmpTwoArray = new int[2]; 92b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 93a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek public HeadsUpManager(final Context context, ViewTreeObserver observer) { 94b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek Resources resources = context.getResources(); 95b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTouchSensitivityDelay = resources.getInteger(R.integer.heads_up_sensitivity_delay); 96b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay); 97b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSnoozedPackages = new ArrayMap<>(); 98b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mDefaultSnoozeLengthMs = resources.getInteger(R.integer.heads_up_default_snooze_length_ms); 99b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSnoozeLengthMs = mDefaultSnoozeLengthMs; 100b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time); 101a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mHeadsUpNotificationDecay = 200000000/*resources.getInteger(R.integer.heads_up_notification_decay)*/;; 102b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mClock = new Clock(); 103b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek // TODO: shadow mSwipeHelper.setMaxSwipeProgress(mMaxAlpha); 104b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 105b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSnoozeLengthMs = Settings.Global.getInt(context.getContentResolver(), 106b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek SETTING_HEADS_UP_SNOOZE_LENGTH_MS, mDefaultSnoozeLengthMs); 107b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSettingsObserver = new ContentObserver(mHandler) { 108b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 109b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void onChange(boolean selfChange) { 110b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final int packageSnoozeLengthMs = Settings.Global.getInt( 111b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek context.getContentResolver(), SETTING_HEADS_UP_SNOOZE_LENGTH_MS, -1); 112b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (packageSnoozeLengthMs > -1 && packageSnoozeLengthMs != mSnoozeLengthMs) { 113b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSnoozeLengthMs = packageSnoozeLengthMs; 114b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (DEBUG) Log.v(TAG, "mSnoozeLengthMs = " + mSnoozeLengthMs); 115b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 116b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 117b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek }; 118b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek context.getContentResolver().registerContentObserver( 119b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false, 120b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSettingsObserver); 121b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (DEBUG) Log.v(TAG, "mSnoozeLengthMs = " + mSnoozeLengthMs); 122a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek observer.addOnComputeInternalInsetsListener(this); 123b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 124b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 125b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void setBar(PhoneStatusBar bar) { 126b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mBar = bar; 127b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 128b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 129b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void addListener(OnHeadsUpChangedListener listener) { 130b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mListeners.add(listener); 131b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 132b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 133b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public PhoneStatusBar getBar() { 134b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mBar; 135b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 136b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 137b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek /** 138b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Called when posting a new notification to the heads up. 139b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 140b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void showNotification(NotificationData.Entry headsUp) { 141b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (DEBUG) Log.v(TAG, "showNotification"); 142b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek addHeadsUpEntry(headsUp); 143b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek updateNotification(headsUp, true); 144b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek headsUp.setInterruption(); 145b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 146b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 147b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek /** 148b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Called when updating or posting a notification to the heads up. 149b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 150b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void updateNotification(NotificationData.Entry headsUp, boolean alert) { 151b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (DEBUG) Log.v(TAG, "updateNotification"); 152b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 153b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek headsUp.row.setChildrenExpanded(false /* expanded */, false /* animated */); 154b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek headsUp.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 155b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 156b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (alert) { 157b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(headsUp.key); 158b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek headsUpEntry.updateEntry(); 1591f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek setEntryToShade(headsUpEntry, mIsExpanded); 160b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 161b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 162b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 163b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void addHeadsUpEntry(NotificationData.Entry entry) { 164b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry headsUpEntry = mEntryPool.acquire(); 165a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek 166a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek // This will also add the entry to the sortedList 167b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek headsUpEntry.setEntry(entry); 168b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHeadsUpEntries.put(entry.key, headsUpEntry); 169a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek entry.row.setHeadsUp(true); 170a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek if (!entry.row.isInShade() && mIsExpanded) { 1711f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek setEntryToShade(headsUpEntry, true); 172a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 1731f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek updatePinnedHeadsUpState(false /*forceImmediate */); 174b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek for (OnHeadsUpChangedListener listener : mListeners) { 175b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek listener.OnHeadsUpStateChanged(entry, true); 176b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 177b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 178b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 179b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 1801f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek private void setEntryToShade(HeadsUpEntry headsUpEntry, boolean inShade) { 1811f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek ExpandableNotificationRow row = headsUpEntry.entry.row; 1821f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek if (row.isInShade() != inShade) { 1831f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek row.setInShade(inShade); 1841f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek updatePinnedHeadsUpState(false /* forceImmediate */); 1851f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek if (!inShade) { 1861f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek for (OnHeadsUpChangedListener listener :mListeners) { 1871f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek listener.OnHeadsUpPinned(row); 1881f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek } 1891f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek } 1901f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek } 1911f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek } 1921f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek 193b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void removeHeadsUpEntry(NotificationData.Entry entry) { 194b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key); 195a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mSortedEntries.remove(remove); 196b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mEntryPool.release(remove); 197b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 198b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek entry.row.setHeadsUp(false); 1991f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek updatePinnedHeadsUpState(false /* forceImmediate */); 200b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek for (OnHeadsUpChangedListener listener : mListeners) { 201b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek listener.OnHeadsUpStateChanged(entry, false); 202b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 203b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 204b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 205b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private void updatePinnedHeadsUpState(boolean forceImmediate) { 206b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek boolean hasPinnedHeadsUp = hasPinnedHeadsUpInternal(); 207b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (hasPinnedHeadsUp == mHasPinnedHeadsUp) { 208b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return; 209b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 210b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHasPinnedHeadsUp = hasPinnedHeadsUp; 211b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek for (OnHeadsUpChangedListener listener :mListeners) { 212b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek listener.OnPinnedHeadsUpExistChanged(hasPinnedHeadsUp, forceImmediate); 213b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 214b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 215b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 216b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek /** 217b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * React to the removal of the notification in the heads up. 218b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * 219b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * @return true if the notification was removed and false if it still needs to be kept around 220b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * for a bit since it wasn't shown long enough 221b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 222b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean removeNotification(String key) { 223b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (DEBUG) Log.v(TAG, "remove"); 224b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (wasShownLongEnough(key)) { 225b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek releaseImmediately(key); 226b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 227b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } else { 228b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek getHeadsUpEntry(key).hideAsSoonAsPossible(); 229b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 230b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 231b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 232b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 233b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean wasShownLongEnough(String key) { 234b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry headsUpEntry = getHeadsUpEntry(key); 235b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry topEntry = getTopEntry(); 236b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mSwipedOutKeys.contains(key)) { 237b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek // We always instantly dismiss views being manually swiped out. 238b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSwipedOutKeys.remove(key); 239b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 240b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 241b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (headsUpEntry != topEntry) { 242b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 243b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 244b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return headsUpEntry.wasShownLongEnough(); 245b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 246b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 247b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean isHeadsUp(String key) { 248b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mHeadsUpEntries.containsKey(key); 249b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 250b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 251b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 252b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek /** 253b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * Push any current Heads Up notification down into the shade. 254b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 255b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void releaseAllImmediately() { 256b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (DEBUG) Log.v(TAG, "releaseAllImmediately"); 257a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek HashSet<String> keys = new HashSet<>(mHeadsUpEntries.keySet()); 258a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek for (String key: keys) { 259b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek releaseImmediately(key); 260b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 261b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 262b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 263b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void releaseImmediately(String key) { 264b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry headsUpEntry = getHeadsUpEntry(key); 265b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (headsUpEntry == null) { 266b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return; 267b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 268b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek NotificationData.Entry shadeEntry = headsUpEntry.entry; 269b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek removeHeadsUpEntry(shadeEntry); 270b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 271b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 272b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean isSnoozed(String packageName) { 273b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek final String key = snoozeKey(packageName, mUser); 274b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek Long snoozedUntil = mSnoozedPackages.get(key); 275b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (snoozedUntil != null) { 276b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (snoozedUntil > SystemClock.elapsedRealtime()) { 277b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (DEBUG) Log.v(TAG, key + " snoozed"); 278b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 279b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 280b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSnoozedPackages.remove(packageName); 281b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 282b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 283b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 284b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 285b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void snooze() { 286b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek for (String key: mHeadsUpEntries.keySet()) { 287b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry entry = mHeadsUpEntries.get(key); 288b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek String packageName = entry.entry.notification.getPackageName(); 289b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSnoozedPackages.put(snoozeKey(packageName, mUser), 290b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek SystemClock.elapsedRealtime() + mSnoozeLengthMs); 291b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 292b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mReleaseOnExpandFinish = true; 293b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 294b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 295b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private static String snoozeKey(String packageName, int user) { 296b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return user + "," + packageName; 297b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 298b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 299b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private HeadsUpEntry getHeadsUpEntry(String key) { 300b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mHeadsUpEntries.get(key); 301b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 302b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 303b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public NotificationData.Entry getEntry(String key) { 304b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mHeadsUpEntries.get(key).entry; 305b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 306b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 307a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek public TreeSet<HeadsUpEntry> getSortedEntries() { 308a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek return mSortedEntries; 309b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 310b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 311b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public HeadsUpEntry getTopEntry() { 312a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek return mSortedEntries.isEmpty() ? null : mSortedEntries.first(); 313b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 314b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 315b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek /** 316b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * @param key the key of the touched notification 317b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek * @return whether the touch is valid and should not be discarded 318b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek */ 319b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean shouldSwallowClick(String key) { 320b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mClock.currentTimeMillis() < mHeadsUpEntries.get(key).postTime) { 321b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 322b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 323b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 324b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 325b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 326b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) { 327b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek // TODO: handle the shadow 328b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek //getBackground().setAlpha((int) (255 * swipeProgress)); 329b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 330b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 331b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 332b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { 333a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek if (!mIsExpanded && mHasPinnedHeadsUp) { 334a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek int minX = Integer.MAX_VALUE; 335a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek int maxX = 0; 336a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek int minY = Integer.MAX_VALUE; 337a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek int maxY = 0; 338a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek for (HeadsUpEntry entry: mSortedEntries) { 339a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek ExpandableNotificationRow row = entry.entry.row; 340a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek if (!row.isInShade()) { 341a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek row.getLocationOnScreen(mTmpTwoArray); 342a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek minX = Math.min(minX, mTmpTwoArray[0]); 343a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek minY = Math.min(minY, 0); 344a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek maxX = Math.max(maxX, mTmpTwoArray[0] + row.getWidth()); 345a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek maxY = Math.max(maxY, row.getHeadsUpHeight()); 346a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 347a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 348a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek 349a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); 350a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek info.touchableRegion.set(minX, minY, maxX, maxY); 351a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 352b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 353b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 354b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void setUser(int user) { 355b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mUser = user; 356b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 357b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 358b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 359b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pw.println("HeadsUpManager state:"); 360b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pw.print(" mTouchSensitivityDelay="); pw.println(mTouchSensitivityDelay); 361b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pw.print(" mSnoozeLengthMs="); pw.println(mSnoozeLengthMs); 362b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pw.print(" now="); pw.println(SystemClock.elapsedRealtime()); 363b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pw.print(" mUser="); pw.println(mUser); 364a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek for (HeadsUpEntry entry: mSortedEntries) { 365a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek pw.print(" HeadsUpEntry="); pw.println(entry.entry); 366b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 367b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek int N = mSnoozedPackages.size(); 368b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pw.println(" snoozed packages: " + N); 369b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek for (int i = 0; i < N; i++) { 370b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pw.print(" "); pw.print(mSnoozedPackages.valueAt(i)); 371b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek pw.print(", "); pw.println(mSnoozedPackages.keyAt(i)); 372b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 373b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 374b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 375b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean hasPinnedHeadsUp() { 376b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return mHasPinnedHeadsUp; 377b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 378b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 379b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private boolean hasPinnedHeadsUpInternal() { 380b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek for (String key: mHeadsUpEntries.keySet()) { 381b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry entry = mHeadsUpEntries.get(key); 382b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (!entry.entry.row.isInShade()) { 383b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return true; 384b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 385b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 386b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return false; 387b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 388b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 389b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void addSwipedOutKey(String key) { 390b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mSwipedOutKeys.add(key); 391b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 392b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 393b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public float getHighestPinnedHeadsUp() { 394b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek float max = 0; 395a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek for (HeadsUpEntry entry: mSortedEntries) { 396b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (!entry.entry.row.isInShade()) { 397b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek max = Math.max(max, entry.entry.row.getActualHeight()); 398b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 399b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 400b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return max; 401b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 402b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 403b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void releaseAllToShade() { 404b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek for (String key: mHeadsUpEntries.keySet()) { 405b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry entry = mHeadsUpEntries.get(key); 406b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek entry.entry.row.setInShade(true); 407b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 4081f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek updatePinnedHeadsUpState(true /* forceImmediate */); 409b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 410b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 411b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void onExpandingFinished() { 412b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (mReleaseOnExpandFinish) { 413b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek releaseAllImmediately(); 414b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mReleaseOnExpandFinish = false; 415b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } else { 416b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) { 417b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek removeHeadsUpEntry(entry); 418b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 419b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mEntriesToRemoveAfterExpand.clear(); 420b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 421b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 422b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 423b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void setTrackingHeadsUp(boolean trackingHeadsUp) { 424b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTrackingHeadsUp = trackingHeadsUp; 425b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 426b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 427b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void setIsExpanded(boolean isExpanded) { 4281f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek if (isExpanded != mIsExpanded) { 4291f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek mIsExpanded = isExpanded; 4301f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek if (isExpanded) { 4311f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek releaseAllToShade(); 4321f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek } 4331f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek } 434b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 435b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 436b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public int getTopHeadsUpHeight() { 437b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek HeadsUpEntry topEntry = getTopEntry(); 438b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return topEntry != null ? topEntry.entry.row.getHeadsUpHeight() : 0; 439b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 440b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 441fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek public int compare(NotificationData.Entry a, NotificationData.Entry b) { 442fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek HeadsUpEntry aEntry = getHeadsUpEntry(a.key); 443fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek HeadsUpEntry bEntry = getHeadsUpEntry(b.key); 444fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek if (aEntry == null || bEntry == null) { 445fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek return aEntry == null ? 1 : -1; 446fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek } 447fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek return aEntry.compareTo(bEntry); 448fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek } 449fbe9a44a15addf9d94cd40da56835501241b8d3eSelim Cinek 450b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public class HeadsUpEntry implements Comparable<HeadsUpEntry> { 451b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public NotificationData.Entry entry; 452b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public long postTime; 453b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public long earliestRemovaltime; 454b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek private Runnable mRemoveHeadsUpRunnable; 455b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 456b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void setEntry(final NotificationData.Entry entry) { 457b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek this.entry = entry; 458b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 459b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek // The actual post time will be just after the heads-up really slided in 460b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek postTime = mClock.currentTimeMillis() + mTouchSensitivityDelay; 461b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mRemoveHeadsUpRunnable = new Runnable() { 462b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 463b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void run() { 464b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek if (!mTrackingHeadsUp) { 465b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek removeHeadsUpEntry(entry); 466b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } else { 467b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mEntriesToRemoveAfterExpand.add(entry); 468b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 469b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 470b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek }; 471b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek updateEntry(); 472b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 473b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 474b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void updateEntry() { 475b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek long currentTime = mClock.currentTimeMillis(); 476b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek postTime = Math.max(postTime, currentTime); 477b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek long finishTime = postTime + mHeadsUpNotificationDecay; 478b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime); 479b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek earliestRemovaltime = currentTime + mMinimumDisplayTime; 480b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek removeAutoCancelCallbacks(); 481b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay); 482a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek updateSortOrder(HeadsUpEntry.this); 483b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 484b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 485b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek @Override 486b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public int compareTo(HeadsUpEntry o) { 487a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek return postTime < o.postTime ? 1 488b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek : postTime == o.postTime ? 0 489a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek : -1; 490b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 491b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 492b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void removeAutoCancelCallbacks() { 493b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHandler.removeCallbacks(mRemoveHeadsUpRunnable); 494b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 495b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 496b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public boolean wasShownLongEnough() { 497b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return earliestRemovaltime < mClock.currentTimeMillis(); 498b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 499b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 500b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public void hideAsSoonAsPossible() { 501b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek removeAutoCancelCallbacks(); 502b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mHandler.postDelayed(mRemoveHeadsUpRunnable, 503b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek earliestRemovaltime - mClock.currentTimeMillis()); 504b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 505b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 506b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 507a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek /** 508a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek * Update the sorted heads up order. 509a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek * 510a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek * @param headsUpEntry the headsUp that changed 511a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek */ 512a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private void updateSortOrder(HeadsUpEntry headsUpEntry) { 513a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mSortedEntries.remove(headsUpEntry); 514a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mSortedEntries.add(headsUpEntry); 515a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 516a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek 517b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public static class Clock { 518b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public long currentTimeMillis() { 519b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek return SystemClock.elapsedRealtime(); 520b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 521b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 522b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek 523b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek public interface OnHeadsUpChangedListener { 524b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly); 5251f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek void OnHeadsUpPinned(ExpandableNotificationRow headsUp); 526b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp); 527b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } 528b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek} 529