Merge "Controls - Remove support for mock" into rvc-dev
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index f18aaa5..cd10457 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -930,8 +930,6 @@
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informOnePackage was called");
- // TODO(b/149254662): This is gross. We should consider changing statsd
- // internals to use std::string.
String16 utf16App = String16(app.c_str());
String16 utf16VersionString = String16(versionString.c_str());
String16 utf16Installer = String16(installer.c_str());
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.cpp b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
index 02291181..b632d04 100644
--- a/cmds/statsd/src/anomaly/AlarmMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
@@ -38,8 +38,6 @@
void AlarmMonitor::setStatsCompanionService(
shared_ptr<IStatsCompanionService> statsCompanionService) {
std::lock_guard<std::mutex> lock(mLock);
- // TODO(b/149254662): determine if tmpForLock is needed now that we have moved
- // from sp to shared_ptr
shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
mStatsCompanionService = statsCompanionService;
if (statsCompanionService == nullptr) {
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 9bdb588..6d9c644 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -54,20 +54,22 @@
shared_ptr<IPendingIntentRef> mPir;
};
-static void configReceiverDied(void* cookie) {
+void ConfigManager::configReceiverDied(void* cookie) {
auto cookie_ = static_cast<ConfigReceiverDeathCookie*>(cookie);
- sp<ConfigManager> configManager = cookie_->mConfigManager;
- ConfigKey configKey = cookie_->mConfigKey;
- shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
+ sp<ConfigManager>& thiz = cookie_->mConfigManager;
+ ConfigKey& configKey = cookie_->mConfigKey;
+ shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
- // TODO(b/149254662): Fix threading. This currently fails if a new
- // pir gets set between the get and the remove.
- if (configManager->GetConfigReceiver(configKey) == pir) {
- configManager->RemoveConfigReceiver(configKey);
+ // Erase the mapping from the config key to the config receiver (pir) if the
+ // mapping still exists.
+ lock_guard<mutex> lock(thiz->mMutex);
+ auto it = thiz->mConfigReceivers.find(configKey);
+ if (it != thiz->mConfigReceivers.end() && it->second == pir) {
+ thiz->mConfigReceivers.erase(configKey);
}
- // The death recipient corresponding to this specific pir can never
- // be triggered again, so free up resources.
- // TODO(b/149254662): Investigate other options to manage the memory.
+
+ // The death recipient corresponding to this specific pir can never be
+ // triggered again, so free up resources.
delete cookie_;
}
@@ -83,26 +85,29 @@
shared_ptr<IPendingIntentRef> mPir;
};
-static void activeConfigChangedReceiverDied(void* cookie) {
+void ConfigManager::activeConfigChangedReceiverDied(void* cookie) {
auto cookie_ = static_cast<ActiveConfigChangedReceiverDeathCookie*>(cookie);
- sp<ConfigManager> configManager = cookie_->mConfigManager;
+ sp<ConfigManager>& thiz = cookie_->mConfigManager;
int uid = cookie_->mUid;
- shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
+ shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
- // TODO(b/149254662): Fix threading. This currently fails if a new
- // pir gets set between the get and the remove.
- if (configManager->GetActiveConfigsChangedReceiver(uid) == pir) {
- configManager->RemoveActiveConfigsChangedReceiver(uid);
+ // Erase the mapping from the config key to the active config changed
+ // receiver (pir) if the mapping still exists.
+ lock_guard<mutex> lock(thiz->mMutex);
+ auto it = thiz->mActiveConfigsChangedReceivers.find(uid);
+ if (it != thiz->mActiveConfigsChangedReceivers.end() && it->second == pir) {
+ thiz->mActiveConfigsChangedReceivers.erase(uid);
}
+
// The death recipient corresponding to this specific pir can never
// be triggered again, so free up resources.
delete cookie_;
}
-ConfigManager::ConfigManager():
+ConfigManager::ConfigManager() :
mConfigReceiverDeathRecipient(AIBinder_DeathRecipient_new(configReceiverDied)),
mActiveConfigChangedReceiverDeathRecipient(
- AIBinder_DeathRecipient_new(activeConfigChangedReceiverDied)) {
+ AIBinder_DeathRecipient_new(activeConfigChangedReceiverDied)) {
}
ConfigManager::~ConfigManager() {
@@ -189,8 +194,10 @@
void ConfigManager::SetActiveConfigsChangedReceiver(const int uid,
const shared_ptr<IPendingIntentRef>& pir) {
- lock_guard<mutex> lock(mMutex);
- mActiveConfigsChangedReceivers[uid] = pir;
+ {
+ lock_guard<mutex> lock(mMutex);
+ mActiveConfigsChangedReceivers[uid] = pir;
+ }
AIBinder_linkToDeath(pir->asBinder().get(), mActiveConfigChangedReceiverDeathRecipient.get(),
new ActiveConfigChangedReceiverDeathCookie(this, uid, pir));
}
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 824e588..40146b1 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -161,6 +161,19 @@
// IPendingIntentRef dies.
::ndk::ScopedAIBinder_DeathRecipient mConfigReceiverDeathRecipient;
::ndk::ScopedAIBinder_DeathRecipient mActiveConfigChangedReceiverDeathRecipient;
+
+ /**
+ * Death recipient callback that is called when a config receiver dies.
+ * The cookie is a pointer to a ConfigReceiverDeathCookie.
+ */
+ static void configReceiverDied(void* cookie);
+
+ /**
+ * Death recipient callback that is called when an active config changed
+ * receiver dies. The cookie is a pointer to an
+ * ActiveConfigChangedReceiverDeathCookie.
+ */
+ static void activeConfigChangedReceiverDied(void* cookie);
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 1c38542..0115ba2 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -85,12 +85,9 @@
return;
}
- // TODO(b/149254662): Why are we creating a copy here? This is different
- // from the other places where we create a copy because we don't reassign
- // mStatsCompanionService so a destructor can't implicitly be called...
- shared_ptr<IStatsCompanionService> statsCompanionServiceCopy = mStatsCompanionService;
- if (statsCompanionServiceCopy != nullptr) {
- statsCompanionServiceCopy->setPullingAlarm(mNextPullTimeNs / 1000000);
+ // TODO(b/151045771): do not hold a lock while making a binder call
+ if (mStatsCompanionService != nullptr) {
+ mStatsCompanionService->setPullingAlarm(mNextPullTimeNs / 1000000);
} else {
VLOG("StatsCompanionService not available. Alarm not set.");
}
@@ -99,8 +96,6 @@
void StatsPullerManager::SetStatsCompanionService(
shared_ptr<IStatsCompanionService> statsCompanionService) {
- // TODO(b/149254662): Why are we using AutoMutex instead of lock_guard?
- // Additionally, do we need the temporary shared_ptr to prevent deadlocks?
AutoMutex _l(mLock);
shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
mStatsCompanionService = statsCompanionService;
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index 93af5e9..c915ef3 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -39,33 +39,47 @@
shared_ptr<IPendingIntentRef> mPir;
};
-static void broadcastSubscriberDied(void* cookie) {
- BroadcastSubscriberDeathCookie* cookie_ = (BroadcastSubscriberDeathCookie*)cookie;
- ConfigKey configKey = cookie_->mConfigKey;
+void SubscriberReporter::broadcastSubscriberDied(void* cookie) {
+ auto cookie_ = static_cast<BroadcastSubscriberDeathCookie*>(cookie);
+ ConfigKey& configKey = cookie_->mConfigKey;
int64_t subscriberId = cookie_->mSubscriberId;
- shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
+ shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
- // TODO(b/149254662): Fix threading. This currently fails if a new pir gets
- // set between the get and the unset.
- if (SubscriberReporter::getInstance().getBroadcastSubscriber(configKey, subscriberId) == pir) {
- SubscriberReporter::getInstance().unsetBroadcastSubscriber(configKey, subscriberId);
+ SubscriberReporter& thiz = getInstance();
+
+ // Erase the mapping from a (config_key, subscriberId) to a pir if the
+ // mapping exists.
+ lock_guard<mutex> lock(thiz.mLock);
+ auto subscriberMapIt = thiz.mIntentMap.find(configKey);
+ if (subscriberMapIt != thiz.mIntentMap.end()) {
+ auto subscriberMap = subscriberMapIt->second;
+ auto pirIt = subscriberMap.find(subscriberId);
+ if (pirIt != subscriberMap.end() && pirIt->second == pir) {
+ subscriberMap.erase(subscriberId);
+ if (subscriberMap.empty()) {
+ thiz.mIntentMap.erase(configKey);
+ }
+ }
}
+
// The death recipient corresponding to this specific pir can never be
// triggered again, so free up resources.
delete cookie_;
}
-static ::ndk::ScopedAIBinder_DeathRecipient sBroadcastSubscriberDeathRecipient(
- AIBinder_DeathRecipient_new(broadcastSubscriberDied));
+SubscriberReporter::SubscriberReporter() :
+ mBroadcastSubscriberDeathRecipient(AIBinder_DeathRecipient_new(broadcastSubscriberDied)) {
+}
void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId,
const shared_ptr<IPendingIntentRef>& pir) {
VLOG("SubscriberReporter::setBroadcastSubscriber called.");
- lock_guard<mutex> lock(mLock);
- mIntentMap[configKey][subscriberId] = pir;
- // TODO(b/149254662): Is it ok to call linkToDeath while holding a lock?
- AIBinder_linkToDeath(pir->asBinder().get(), sBroadcastSubscriberDeathRecipient.get(),
+ {
+ lock_guard<mutex> lock(mLock);
+ mIntentMap[configKey][subscriberId] = pir;
+ }
+ AIBinder_linkToDeath(pir->asBinder().get(), mBroadcastSubscriberDeathRecipient.get(),
new BroadcastSubscriberDeathCookie(configKey, subscriberId, pir));
}
@@ -103,8 +117,6 @@
}
int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
- // TODO(b/149254662): Is there a way to convert a RepeatedPtrField into a
- // vector without copying?
vector<string> cookies;
cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 0f97d39..4fe4281 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -78,7 +78,7 @@
int64_t subscriberId);
private:
- SubscriberReporter() {};
+ SubscriberReporter();
mutable mutex mLock;
@@ -94,6 +94,14 @@
const Subscription& subscription,
const vector<string>& cookies,
const MetricDimensionKey& dimKey) const;
+
+ ::ndk::ScopedAIBinder_DeathRecipient mBroadcastSubscriberDeathRecipient;
+
+ /**
+ * Death recipient callback that is called when a broadcast subscriber dies.
+ * The cookie is a pointer to a BroadcastSubscriberDeathCookie.
+ */
+ static void broadcastSubscriberDied(void* cookie);
};
} // namespace statsd
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 22c3acf..6f985a4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -24,6 +24,7 @@
import com.android.keyguard.KeyguardViewController;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
+import com.android.systemui.car.CarNotificationInterruptionStateProvider;
import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
@@ -40,6 +41,7 @@
import com.android.systemui.statusbar.car.CarStatusBar;
import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
@@ -63,6 +65,10 @@
@Module(includes = {DividerModule.class})
abstract class CarSystemUIModule {
+ @Binds
+ abstract NotificationInterruptionStateProvider bindNotificationInterruptionStateProvider(
+ CarNotificationInterruptionStateProvider notificationInterruptionStateProvider);
+
@Singleton
@Provides
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
new file mode 100644
index 0000000..447e579
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
@@ -0,0 +1,54 @@
+/*
+ * 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.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */
+@Singleton
+public class CarNotificationInterruptionStateProvider extends
+ NotificationInterruptionStateProvider {
+
+ @Inject
+ public CarNotificationInterruptionStateProvider(Context context,
+ NotificationFilter filter,
+ StatusBarStateController stateController,
+ BatteryController batteryController) {
+ super(context, filter, stateController, batteryController);
+ }
+
+ @Override
+ public boolean shouldHeadsUp(NotificationEntry entry) {
+ // 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 not pinning any
+ // notification if the shade is already opened.
+ if (!getPresenter().isPresenterFullyCollapsed()) {
+ return false;
+ }
+
+ return super.shouldHeadsUp(entry);
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index de768cb..b2e2104 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -95,14 +95,13 @@
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -250,9 +249,10 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptStateProvider notificationInterruptStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
+ NotificationAlertingManager notificationAlertingManager,
DisplayMetrics displayMetrics,
MetricsLogger metricsLogger,
@UiBackground Executor uiBgExecutor,
@@ -335,9 +335,10 @@
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationInterruptStateProvider,
+ notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
+ notificationAlertingManager,
displayMetrics,
metricsLogger,
uiBgExecutor,
@@ -487,22 +488,6 @@
.isCurrentUserSetupInProgress();
}
});
-
- mNotificationInterruptStateProvider.addSuppressor(new NotificationInterruptSuppressor() {
- @Override
- public String getName() {
- return TAG;
- }
-
- @Override
- public boolean suppressInterruptions(NotificationEntry entry) {
- // 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 not allowing any interruptions (ie: pinning any notifications) if
- // the shade is already opened.
- return !getPresenter().isPresenterFullyCollapsed();
- }
- });
}
@Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 9a53584..4754118 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -62,12 +62,13 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationRowModule;
@@ -145,9 +146,10 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
+ NotificationAlertingManager notificationAlertingManager,
DisplayMetrics displayMetrics,
MetricsLogger metricsLogger,
@UiBackground Executor uiBgExecutor,
@@ -232,6 +234,7 @@
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
+ notificationAlertingManager,
displayMetrics,
metricsLogger,
uiBgExecutor,
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index ff0c6a7..92ae1b9 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -1,71 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
-<ScrollView
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/global_actions_container"
android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/global_actions_grid_root"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+>
+ <com.android.systemui.globalactions.GlobalActionsFlatLayout
+ android:id="@id/global_actions_view"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:theme="@style/qs_theme"
+ android:gravity="top | center_horizontal"
android:clipChildren="false"
android:clipToPadding="false"
- android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
- android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset">
-
- <com.android.systemui.globalactions.GlobalActionsFlatLayout
- android:id="@id/global_actions_view"
- android:layout_width="match_parent"
+ android:layout_marginTop="@dimen/global_actions_top_margin"
+ >
+ <LinearLayout
+ android:id="@android:id/list"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/global_actions_grid_side_margin"
+ android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+ android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
android:orientation="horizontal"
- android:theme="@style/qs_theme"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- android:gravity="top | center_horizontal"
+ android:gravity="left"
+ android:translationZ="@dimen/global_actions_translate"
+ />
+ </com.android.systemui.globalactions.GlobalActionsFlatLayout>
+
+ <com.android.systemui.globalactions.MinHeightScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
+ android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset"
+ android:orientation="vertical"
+ >
+ <LinearLayout
+ android:id="@+id/global_actions_grid_root"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:clipChildren="false"
+ android:orientation="vertical"
android:clipToPadding="false"
- android:layout_marginTop="@dimen/global_actions_top_margin">
+ >
<LinearLayout
- android:id="@android:id/list"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/global_actions_grid_side_margin"
- android:layout_marginRight="@dimen/global_actions_grid_side_margin"
- android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
- android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
- android:paddingTop="@dimen/global_actions_grid_vertical_padding"
- android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
- android:orientation="horizontal"
- android:gravity="left"
- android:translationZ="@dimen/global_actions_translate" />
- </com.android.systemui.globalactions.GlobalActionsFlatLayout>
-
- <LinearLayout
- android:id="@+id/global_actions_panel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@id/global_actions_view">
-
- <FrameLayout
- android:id="@+id/global_actions_panel_container"
+ android:id="@+id/global_actions_panel"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- </LinearLayout>
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ >
+ <FrameLayout
+ android:id="@+id/global_actions_panel_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+ </LinearLayout>
- <LinearLayout
- android:id="@+id/global_actions_controls"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toBottomOf="@id/global_actions_panel"
- app:layout_constraintBottom_toBottomOf="parent" />
- </androidx.constraintlayout.widget.ConstraintLayout>
-</ScrollView>
+ <LinearLayout
+ android:id="@+id/global_actions_controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginRight="@dimen/global_actions_grid_horizontal_padding"
+ android:layout_marginLeft="@dimen/global_actions_grid_horizontal_padding"
+ />
+ </LinearLayout>
+ </com.android.systemui.globalactions.MinHeightScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
deleted file mode 100644
index d441070..0000000
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.android.systemui.HardwareUiLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@id/global_actions_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top|right"
- android:layout_marginBottom="0dp"
- android:orientation="vertical"
- android:paddingTop="@dimen/global_actions_top_padding"
- android:clipToPadding="false"
- android:theme="@style/qs_theme"
- android:clipChildren="false">
-
- <!-- Global actions is right-aligned to be physically near power button -->
- <LinearLayout
- android:id="@android:id/list"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|right"
- android:gravity="center"
- android:orientation="vertical"
- android:padding="@dimen/global_actions_padding"
- android:translationZ="@dimen/global_actions_translate" />
-
- <!-- For separated button-->
- <FrameLayout
- android:id="@+id/separated_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|right"
- android:layout_marginTop="6dp"
- android:gravity="center"
- android:orientation="vertical"
- android:padding="@dimen/global_actions_padding"
- android:translationZ="@dimen/global_actions_translate" />
-
-</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index b6152da..a868cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -71,11 +71,12 @@
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -288,6 +289,7 @@
@Inject Lazy<NotificationLogger> mNotificationLogger;
@Inject Lazy<NotificationViewHierarchyManager> mNotificationViewHierarchyManager;
@Inject Lazy<NotificationFilter> mNotificationFilter;
+ @Inject Lazy<NotificationInterruptionStateProvider> mNotificationInterruptionStateProvider;
@Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
@Inject Lazy<SmartReplyController> mSmartReplyController;
@Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
@@ -487,6 +489,8 @@
mProviders.put(NotificationViewHierarchyManager.class,
mNotificationViewHierarchyManager::get);
mProviders.put(NotificationFilter.class, mNotificationFilter::get);
+ mProviders.put(NotificationInterruptionStateProvider.class,
+ mNotificationInterruptionStateProvider::get);
mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get);
mProviders.put(SmartReplyController.class, mSmartReplyController::get);
mProviders.put(RemoteInputQuickSettingsDisabler.class,
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
deleted file mode 100644
index ad2e002..0000000
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui;
-
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.ViewTreeObserver;
-import android.widget.LinearLayout;
-
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.leak.RotationUtils;
-
-/**
- * Layout for placing two containers at a specific physical position on the device, relative to the
- * device's hardware, regardless of screen rotation.
- */
-public class HardwareUiLayout extends MultiListLayout implements Tunable {
-
- private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
- private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
- private final int[] mTmp2 = new int[2];
- private ViewGroup mList;
- private ViewGroup mSeparatedView;
- private int mOldHeight;
- private boolean mAnimating;
- private AnimatorSet mAnimation;
- private View mDivision;
- private HardwareBgDrawable mListBackground;
- private HardwareBgDrawable mSeparatedViewBackground;
- private Animator mAnimator;
- private boolean mCollapse;
- private int mEndPoint;
- private boolean mEdgeBleed;
- private boolean mRoundedDivider;
- private boolean mRotatedBackground;
- private boolean mSwapOrientation = true;
-
- public HardwareUiLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- // Manually re-initialize mRotation to portrait-mode, since this view must always
- // be constructed in portrait mode and rotated into the correct initial position.
- mRotation = ROTATION_NONE;
- updateSettings();
- }
-
- @Override
- protected ViewGroup getSeparatedView() {
- return findViewById(com.android.systemui.R.id.separated_button);
- }
-
- @Override
- protected ViewGroup getListView() {
- return findViewById(android.R.id.list);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- updateSettings();
- Dependency.get(TunerService.class).addTunable(this, EDGE_BLEED, ROUNDED_DIVIDER);
- getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
- Dependency.get(TunerService.class).removeTunable(this);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- updateSettings();
- }
-
- private void updateSettings() {
- mEdgeBleed = Settings.Secure.getInt(getContext().getContentResolver(),
- EDGE_BLEED, 0) != 0;
- mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(),
- ROUNDED_DIVIDER, 0) != 0;
- updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
- mListBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
- mSeparatedViewBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed,
- getContext());
- if (mList != null) {
- mList.setBackground(mListBackground);
- mSeparatedView.setBackground(mSeparatedViewBackground);
- requestLayout();
- }
- }
-
- private void updateEdgeMargin(int edge) {
- if (mList != null) {
- MarginLayoutParams params = (MarginLayoutParams) mList.getLayoutParams();
- if (mRotation == ROTATION_LANDSCAPE) {
- params.topMargin = edge;
- } else if (mRotation == ROTATION_SEASCAPE) {
- params.bottomMargin = edge;
- } else {
- params.rightMargin = edge;
- }
- mList.setLayoutParams(params);
- }
-
- if (mSeparatedView != null) {
- MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
- if (mRotation == ROTATION_LANDSCAPE) {
- params.topMargin = edge;
- } else if (mRotation == ROTATION_SEASCAPE) {
- params.bottomMargin = edge;
- } else {
- params.rightMargin = edge;
- }
- mSeparatedView.setLayoutParams(params);
- }
- }
-
- private int getEdgePadding() {
- return getContext().getResources().getDimensionPixelSize(R.dimen.edge_margin);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mList == null) {
- if (getChildCount() != 0) {
- mList = getListView();
- mList.setBackground(mListBackground);
- mSeparatedView = getSeparatedView();
- mSeparatedView.setBackground(mSeparatedViewBackground);
- updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
- mOldHeight = mList.getMeasuredHeight();
-
- // Must be called to initialize view rotation correctly.
- // Requires LayoutParams, hence why this isn't called during the constructor.
- updateRotation();
- } else {
- return;
- }
- }
- int newHeight = mList.getMeasuredHeight();
- if (newHeight != mOldHeight) {
- animateChild(mOldHeight, newHeight);
- }
-
- post(() -> updatePaddingAndGravityIfTooTall());
- post(() -> updatePosition());
- }
-
- public void setSwapOrientation(boolean swapOrientation) {
- mSwapOrientation = swapOrientation;
- }
-
- private void updateRotation() {
- int rotation = RotationUtils.getRotation(getContext());
- if (rotation != mRotation) {
- rotate(mRotation, rotation);
- mRotation = rotation;
- }
- }
-
- /**
- * Requires LayoutParams to be set to work correctly, and therefore must be run after after
- * the HardwareUILayout has been added to the view hierarchy.
- */
- protected void rotate(int from, int to) {
- super.rotate(from, to);
- if (from != ROTATION_NONE && to != ROTATION_NONE) {
- // Rather than handling this confusing case, just do 2 rotations.
- rotate(from, ROTATION_NONE);
- rotate(ROTATION_NONE, to);
- return;
- }
- if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
- rotateRight();
- } else {
- rotateLeft();
- }
- if (mAdapter.hasSeparatedItems()) {
- if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
- // Separated view has top margin, so seascape separated view need special rotation,
- // not a full left or right rotation.
- swapLeftAndTop(mSeparatedView);
- } else if (from == ROTATION_LANDSCAPE) {
- rotateRight(mSeparatedView);
- } else {
- rotateLeft(mSeparatedView);
- }
- }
- if (to != ROTATION_NONE) {
- if (mList instanceof LinearLayout) {
- mRotatedBackground = true;
- mListBackground.setRotatedBackground(true);
- mSeparatedViewBackground.setRotatedBackground(true);
- LinearLayout linearLayout = (LinearLayout) mList;
- if (mSwapOrientation) {
- linearLayout.setOrientation(LinearLayout.HORIZONTAL);
- setOrientation(LinearLayout.HORIZONTAL);
- }
- swapDimens(mList);
- swapDimens(mSeparatedView);
- }
- } else {
- if (mList instanceof LinearLayout) {
- mRotatedBackground = false;
- mListBackground.setRotatedBackground(false);
- mSeparatedViewBackground.setRotatedBackground(false);
- LinearLayout linearLayout = (LinearLayout) mList;
- if (mSwapOrientation) {
- linearLayout.setOrientation(LinearLayout.VERTICAL);
- setOrientation(LinearLayout.VERTICAL);
- }
- swapDimens(mList);
- swapDimens(mSeparatedView);
- }
- }
- }
-
- @Override
- public void onUpdateList() {
- super.onUpdateList();
-
- for (int i = 0; i < mAdapter.getCount(); i++) {
- ViewGroup parent;
- boolean separated = mAdapter.shouldBeSeparated(i);
- if (separated) {
- parent = getSeparatedView();
- } else {
- parent = getListView();
- }
- View v = mAdapter.getView(i, null, parent);
- parent.addView(v);
- }
- }
-
- private void rotateRight() {
- rotateRight(this);
- rotateRight(mList);
- swapDimens(this);
-
- LayoutParams p = (LayoutParams) mList.getLayoutParams();
- p.gravity = rotateGravityRight(p.gravity);
- mList.setLayoutParams(p);
-
- LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
- separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
- mSeparatedView.setLayoutParams(separatedViewLayoutParams);
-
- setGravity(rotateGravityRight(getGravity()));
- }
-
- private void swapDimens(View v) {
- ViewGroup.LayoutParams params = v.getLayoutParams();
- int h = params.width;
- params.width = params.height;
- params.height = h;
- v.setLayoutParams(params);
- }
-
- private int rotateGravityRight(int gravity) {
- int retGravity = 0;
- int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
- final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- retGravity |= Gravity.CENTER_VERTICAL;
- break;
- case Gravity.RIGHT:
- retGravity |= Gravity.BOTTOM;
- break;
- case Gravity.LEFT:
- default:
- retGravity |= Gravity.TOP;
- break;
- }
-
- switch (verticalGravity) {
- case Gravity.CENTER_VERTICAL:
- retGravity |= Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.BOTTOM:
- retGravity |= Gravity.LEFT;
- break;
- case Gravity.TOP:
- default:
- retGravity |= Gravity.RIGHT;
- break;
- }
- return retGravity;
- }
-
- private void rotateLeft() {
- rotateLeft(this);
- rotateLeft(mList);
- swapDimens(this);
-
- LayoutParams p = (LayoutParams) mList.getLayoutParams();
- p.gravity = rotateGravityLeft(p.gravity);
- mList.setLayoutParams(p);
-
- LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
- separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
- mSeparatedView.setLayoutParams(separatedViewLayoutParams);
-
- setGravity(rotateGravityLeft(getGravity()));
- }
-
- private int rotateGravityLeft(int gravity) {
- if (gravity == -1) {
- gravity = Gravity.TOP | Gravity.START;
- }
- int retGravity = 0;
- int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
- final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- retGravity |= Gravity.CENTER_VERTICAL;
- break;
- case Gravity.RIGHT:
- retGravity |= Gravity.TOP;
- break;
- case Gravity.LEFT:
- default:
- retGravity |= Gravity.BOTTOM;
- break;
- }
-
- switch (verticalGravity) {
- case Gravity.CENTER_VERTICAL:
- retGravity |= Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.BOTTOM:
- retGravity |= Gravity.RIGHT;
- break;
- case Gravity.TOP:
- default:
- retGravity |= Gravity.LEFT;
- break;
- }
- return retGravity;
- }
-
- private void rotateLeft(View v) {
- v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
- v.getPaddingLeft());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
- params.leftMargin);
- v.setLayoutParams(params);
- }
-
- private void rotateRight(View v) {
- v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
- v.getPaddingRight());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
- params.rightMargin);
- v.setLayoutParams(params);
- }
-
- private void swapLeftAndTop(View v) {
- v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
- v.getPaddingRight());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
- params.rightMargin);
- v.setLayoutParams(params);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- post(() -> updatePosition());
-
- }
-
- private void animateChild(int oldHeight, int newHeight) {
- if (true) return;
- if (mAnimating) {
- mAnimation.cancel();
- }
- mAnimating = true;
- mAnimation = new AnimatorSet();
- mAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimating = false;
- }
- });
- int fromTop = mList.getTop();
- int fromBottom = mList.getBottom();
- int toTop = fromTop - ((newHeight - oldHeight) / 2);
- int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
- ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop);
- top.addUpdateListener(animation -> mListBackground.invalidateSelf());
- mAnimation.playTogether(top,
- ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom));
- }
-
- public void setDivisionView(View v) {
- mDivision = v;
- if (mDivision != null) {
- mDivision.addOnLayoutChangeListener(
- (v1, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
- updatePosition());
- }
- updatePosition();
- }
-
- private void updatePosition() {
- if (mList == null) return;
- // If got separated button, setRotatedBackground to false,
- // all items won't get white background.
- boolean separated = mAdapter.hasSeparatedItems();
- mListBackground.setRotatedBackground(separated);
- mSeparatedViewBackground.setRotatedBackground(separated);
- if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
- int index = mRotatedBackground ? 0 : 1;
- mDivision.getLocationOnScreen(mTmp2);
- float trans = mRotatedBackground ? mDivision.getTranslationX()
- : mDivision.getTranslationY();
- int viewTop = (int) (mTmp2[index] + trans);
- mList.getLocationOnScreen(mTmp2);
- viewTop -= mTmp2[index];
- setCutPoint(viewTop);
- } else {
- setCutPoint(mList.getMeasuredHeight());
- }
- }
-
- private void setCutPoint(int point) {
- int curPoint = mListBackground.getCutPoint();
- if (curPoint == point) return;
- if (getAlpha() == 0 || curPoint == 0) {
- mListBackground.setCutPoint(point);
- return;
- }
- if (mAnimator != null) {
- if (mEndPoint == point) {
- return;
- }
- mAnimator.cancel();
- }
- mEndPoint = point;
- mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point);
- if (mCollapse) {
- mAnimator.setStartDelay(300);
- mCollapse = false;
- }
- mAnimator.start();
- }
-
- // If current power menu height larger then screen height, remove padding to break power menu
- // alignment and set menu center vertical within the screen.
- private void updatePaddingAndGravityIfTooTall() {
- int defaultTopPadding;
- int viewsTotalHeight;
- int separatedViewTopMargin;
- int screenHeight;
- int totalHeight;
- int targetGravity;
- boolean separated = mAdapter.hasSeparatedItems();
- MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
- switch (RotationUtils.getRotation(getContext())) {
- case RotationUtils.ROTATION_LANDSCAPE:
- defaultTopPadding = getPaddingLeft();
- viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
- separatedViewTopMargin = separated ? params.leftMargin : 0;
- screenHeight = getMeasuredWidth();
- targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
- break;
- case RotationUtils.ROTATION_SEASCAPE:
- defaultTopPadding = getPaddingRight();
- viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
- separatedViewTopMargin = separated ? params.leftMargin : 0;
- screenHeight = getMeasuredWidth();
- targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
- break;
- default: // Portrait
- defaultTopPadding = getPaddingTop();
- viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
- separatedViewTopMargin = separated ? params.topMargin : 0;
- screenHeight = getMeasuredHeight();
- targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
- break;
- }
- totalHeight = defaultTopPadding + viewsTotalHeight + separatedViewTopMargin;
- if (totalHeight >= screenHeight) {
- setPadding(0, 0, 0, 0);
- setGravity(targetGravity);
- }
- }
-
- @Override
- public ViewOutlineProvider getOutlineProvider() {
- return super.getOutlineProvider();
- }
-
- public void setCollapse() {
- mCollapse = true;
- }
-
- private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
- if (mHasOutsideTouch || (mList == null)) {
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
- return;
- }
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
- inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
- 0, getBottom() - mList.getBottom());
- };
-
- private float getAnimationDistance() {
- return getContext().getResources().getDimension(
- com.android.systemui.R.dimen.global_actions_panel_width) / 2;
- }
-
- @Override
- public float getAnimationOffsetX() {
- if (RotationUtils.getRotation(mContext) == ROTATION_NONE) {
- return getAnimationDistance();
- }
- return 0;
- }
-
- @Override
- public float getAnimationOffsetY() {
- switch (RotationUtils.getRotation(getContext())) {
- case RotationUtils.ROTATION_LANDSCAPE:
- return -getAnimationDistance();
- case RotationUtils.ROTATION_SEASCAPE:
- return getAnimationDistance();
- default: // Portrait
- return 0;
- }
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index f873f42..48457f6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -83,11 +83,11 @@
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -169,7 +169,7 @@
// Callback that updates BubbleOverflowActivity on data change.
@Nullable private Runnable mOverflowCallback = null;
- private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+ private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private IStatusBarService mBarService;
// Used for determining view rect for touch interaction
@@ -279,7 +279,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
+ NotificationInterruptionStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
@@ -304,7 +304,7 @@
BubbleData data,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
+ NotificationInterruptionStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
@@ -316,7 +316,7 @@
dumpManager.registerDumpable(TAG, this);
mContext = context;
mShadeController = shadeController;
- mNotificationInterruptStateProvider = interruptionStateProvider;
+ mNotificationInterruptionStateProvider = interruptionStateProvider;
mNotifUserManager = notifUserManager;
mZenModeController = zenModeController;
mFloatingContentCoordinator = floatingContentCoordinator;
@@ -632,7 +632,7 @@
for (NotificationEntry e :
mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
if (savedBubbleKeys.contains(e.getKey())
- && mNotificationInterruptStateProvider.shouldBubbleUp(e)
+ && mNotificationInterruptionStateProvider.shouldBubbleUp(e)
&& canLaunchInActivityView(mContext, e)) {
updateBubble(e, /* suppressFlyout= */ true);
}
@@ -894,7 +894,7 @@
boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
mContext, entry, previouslyUserCreated, userBlocked);
- if (mNotificationInterruptStateProvider.shouldBubbleUp(entry)
+ if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted)) {
if (wasAdjusted && !previouslyUserCreated) {
// Gotta treat the auto-bubbled / whitelisted packaged bubbles as usercreated
@@ -910,7 +910,7 @@
boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
mContext, entry, previouslyUserCreated, userBlocked);
- boolean shouldBubble = mNotificationInterruptStateProvider.shouldBubbleUp(entry)
+ boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted);
if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
// It was previously a bubble but no longer a bubble -- lets remove it
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index b81665c..6a647f0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -118,8 +118,11 @@
/** Whether or not the stack's start position has been set. */
private boolean mStackMovedToStartPosition = false;
- /** The most recent position in which the stack was resting on the edge of the screen. */
- @Nullable private PointF mRestingStackPosition;
+ /**
+ * The stack's most recent position along the edge of the screen. This is saved when the last
+ * bubble is removed, so that the stack can be restored in its previous position.
+ */
+ private PointF mRestingStackPosition;
/** The height of the most recently visible IME. */
private float mImeHeight = 0f;
@@ -465,7 +468,6 @@
.addEndListener((animation, canceled, endValue, endVelocity) -> {
if (!canceled) {
- mRestingStackPosition = new PointF();
mRestingStackPosition.set(mStackPosition);
springFirstBubbleWithStackFollowing(property, spring, endVelocity,
@@ -853,7 +855,12 @@
public void setStackPosition(PointF pos) {
Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y));
mStackPosition.set(pos.x, pos.y);
- mRestingStackPosition = mStackPosition;
+
+ if (mRestingStackPosition == null) {
+ mRestingStackPosition = new PointF();
+ }
+
+ mRestingStackPosition.set(mStackPosition);
// If we're not the active controller, we don't want to physically move the bubble views.
if (isActiveController()) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index 27c9e98..ac97d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -25,8 +25,8 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -54,7 +54,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
+ NotificationInterruptionStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 3a4b273..6c502d2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -90,7 +90,7 @@
/** */
@Provides
- public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) {
+ public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
return new AmbientDisplayConfiguration(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 24f505d..786ad2c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1574,7 +1574,6 @@
private ControlsUiController mControlsUiController;
private ViewGroup mControlsView;
- private ViewGroup mContainerView;
ActionsDialog(Context context, MyAdapter adapter,
GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils,
@@ -1671,7 +1670,6 @@
mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls);
mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
- ((View) mGlobalActionsLayout.getParent()).setOnClickListener(view -> dismiss());
mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public boolean dispatchPopulateAccessibilityEvent(
@@ -1684,6 +1682,15 @@
mGlobalActionsLayout.setRotationListener(this::onRotate);
mGlobalActionsLayout.setAdapter(mAdapter);
+ View globalActionsParent = (View) mGlobalActionsLayout.getParent();
+ globalActionsParent.setOnClickListener(v -> dismiss());
+
+ // add fall-through dismiss handling to root view
+ View rootView = findViewById(com.android.systemui.R.id.global_actions_grid_root);
+ if (rootView != null) {
+ rootView.setOnClickListener(v -> dismiss());
+ }
+
if (shouldUsePanel()) {
initializePanel();
}
@@ -1692,14 +1699,6 @@
mScrimAlpha = ScrimController.BUSY_SCRIM_ALPHA;
}
getWindow().setBackgroundDrawable(mBackgroundDrawable);
-
- if (mControlsView != null) {
- mContainerView = findViewById(com.android.systemui.R.id.global_actions_container);
- mContainerView.setOnTouchListener((v, e) -> {
- dismiss();
- return true;
- });
- }
}
private void fixNavBarClipping() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
new file mode 100644
index 0000000..622fa65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.globalactions;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * When measured, this view sets the minimum height of its first child to be equal to its own
+ * target height.
+ *
+ * This ensures fall-through click handlers can be placed on this view's child component.
+ */
+public class MinHeightScrollView extends ScrollView {
+ public MinHeightScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ View firstChild = getChildAt(0);
+ if (firstChild != null) {
+ firstChild.setMinimumHeight(MeasureSpec.getSize(heightMeasureSpec));
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index 88888d1..269a7a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.statusbar.notification.interruption
+package com.android.systemui.statusbar.notification
import android.content.Context
import android.media.MediaMetadata
@@ -24,7 +24,6 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index b572502..df21f0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification.interruption;
+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.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
@@ -27,9 +27,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -42,7 +39,7 @@
private final NotificationRemoteInputManager mRemoteInputManager;
private final VisualStabilityManager mVisualStabilityManager;
private final StatusBarStateController mStatusBarStateController;
- private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+ private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final NotificationListener mNotificationListener;
private HeadsUpManager mHeadsUpManager;
@@ -55,13 +52,13 @@
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
- NotificationInterruptStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationListener notificationListener,
HeadsUpManager headsUpManager) {
mRemoteInputManager = remoteInputManager;
mVisualStabilityManager = visualStabilityManager;
mStatusBarStateController = statusBarStateController;
- mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mNotificationListener = notificationListener;
mHeadsUpManager = headsUpManager;
@@ -97,7 +94,7 @@
if (entry.getRow().getPrivateLayout().getHeadsUpChild() != null) {
// 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 (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) {
+ if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
mHeadsUpManager.showNotification(entry);
if (!mStatusBarStateController.isDozing()) {
// Mark as seen immediately
@@ -112,7 +109,7 @@
private void updateAlertState(NotificationEntry entry) {
boolean alertAgain = alertAgain(entry, entry.getSbn().getNotification());
// includes check for whether this notification should be filtered:
- boolean shouldAlert = mNotificationInterruptStateProvider.shouldHeadsUp(entry);
+ boolean shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.getKey());
if (wasAlerting) {
if (shouldAlert) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 46d5044..bbf2dde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -14,35 +14,33 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification.interruption;
+package com.android.systemui.statusbar.notification;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import android.app.NotificationManager;
-import android.content.ContentResolver;
+import android.content.Context;
import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.Dependency;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import java.util.ArrayList;
-import java.util.List;
-
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -50,84 +48,120 @@
* Provides heads-up and pulsing state for notification entries.
*/
@Singleton
-public class NotificationInterruptStateProviderImpl implements NotificationInterruptStateProvider {
+public class NotificationInterruptionStateProvider {
+
private static final String TAG = "InterruptionStateProvider";
- private static final boolean DEBUG = true; //false;
+ private static final boolean DEBUG = false;
private static final boolean DEBUG_HEADS_UP = true;
private static final boolean ENABLE_HEADS_UP = true;
private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
- private final List<NotificationInterruptSuppressor> mSuppressors = new ArrayList<>();
private final StatusBarStateController mStatusBarStateController;
private final NotificationFilter mNotificationFilter;
- private final ContentResolver mContentResolver;
+ private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+
+ private final Context mContext;
private final PowerManager mPowerManager;
private final IDreamManager mDreamManager;
- private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final BatteryController mBatteryController;
- private final ContentObserver mHeadsUpObserver;
- private HeadsUpManager mHeadsUpManager;
+ private NotificationPresenter mPresenter;
+ private HeadsUpManager mHeadsUpManager;
+ private HeadsUpSuppressor mHeadsUpSuppressor;
+
+ private ContentObserver mHeadsUpObserver;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
+ private boolean mDisableNotificationAlerts;
@Inject
- public NotificationInterruptStateProviderImpl(
- ContentResolver contentResolver,
+ public NotificationInterruptionStateProvider(Context context, NotificationFilter filter,
+ StatusBarStateController stateController, BatteryController batteryController) {
+ this(context,
+ (PowerManager) context.getSystemService(Context.POWER_SERVICE),
+ IDreamManager.Stub.asInterface(
+ ServiceManager.checkService(DreamService.DREAM_SERVICE)),
+ new AmbientDisplayConfiguration(context),
+ filter,
+ batteryController,
+ stateController);
+ }
+
+ @VisibleForTesting
+ protected NotificationInterruptionStateProvider(
+ Context context,
PowerManager powerManager,
IDreamManager dreamManager,
AmbientDisplayConfiguration ambientDisplayConfiguration,
NotificationFilter notificationFilter,
BatteryController batteryController,
- StatusBarStateController statusBarStateController,
- HeadsUpManager headsUpManager,
- @Main Handler mainHandler) {
- mContentResolver = contentResolver;
+ StatusBarStateController statusBarStateController) {
+ mContext = context;
mPowerManager = powerManager;
mDreamManager = dreamManager;
mBatteryController = batteryController;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mNotificationFilter = notificationFilter;
mStatusBarStateController = statusBarStateController;
- mHeadsUpManager = headsUpManager;
- mHeadsUpObserver = new ContentObserver(mainHandler) {
- @Override
- public void onChange(boolean selfChange) {
- boolean wasUsing = mUseHeadsUp;
- mUseHeadsUp = ENABLE_HEADS_UP
- && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
- mContentResolver,
- Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
- Settings.Global.HEADS_UP_OFF);
- Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
- if (wasUsing != mUseHeadsUp) {
- if (!mUseHeadsUp) {
- Log.d(TAG, "dismissing any existing heads up notification on "
- + "disable event");
- mHeadsUpManager.releaseAllImmediately();
+ }
+
+ /** Sets up late-binding dependencies for this component. */
+ public void setUpWithPresenter(
+ NotificationPresenter notificationPresenter,
+ HeadsUpManager headsUpManager,
+ HeadsUpSuppressor headsUpSuppressor) {
+ setUpWithPresenter(notificationPresenter, headsUpManager, headsUpSuppressor,
+ new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
+ @Override
+ public void onChange(boolean selfChange) {
+ boolean wasUsing = mUseHeadsUp;
+ mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
+ && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+ Settings.Global.HEADS_UP_OFF);
+ Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
+ if (wasUsing != mUseHeadsUp) {
+ if (!mUseHeadsUp) {
+ Log.d(TAG,
+ "dismissing any existing heads up notification on disable"
+ + " event");
+ mHeadsUpManager.releaseAllImmediately();
+ }
+ }
}
- }
- }
- };
+ });
+ }
+
+ /** Sets up late-binding dependencies for this component. */
+ public void setUpWithPresenter(
+ NotificationPresenter notificationPresenter,
+ HeadsUpManager headsUpManager,
+ HeadsUpSuppressor headsUpSuppressor,
+ ContentObserver observer) {
+ mPresenter = notificationPresenter;
+ mHeadsUpManager = headsUpManager;
+ mHeadsUpSuppressor = headsUpSuppressor;
+ mHeadsUpObserver = observer;
if (ENABLE_HEADS_UP) {
- mContentResolver.registerContentObserver(
+ mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED),
true,
mHeadsUpObserver);
- mContentResolver.registerContentObserver(
+ mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
mHeadsUpObserver);
}
mHeadsUpObserver.onChange(true); // set up
}
- @Override
- public void addSuppressor(NotificationInterruptSuppressor suppressor) {
- mSuppressors.add(suppressor);
- }
-
- @Override
+ /**
+ * Whether the notification should appear as a bubble with a fly-out on top of the screen.
+ *
+ * @param entry the entry to check
+ * @return true if the entry should bubble up, false otherwise
+ */
public boolean shouldBubbleUp(NotificationEntry entry) {
final StatusBarNotification sbn = entry.getSbn();
@@ -167,8 +201,12 @@
return true;
}
-
- @Override
+ /**
+ * Whether the notification should peek in from the top and alert the user.
+ *
+ * @param entry the entry to check
+ * @return true if the entry should heads up, false otherwise
+ */
public boolean shouldHeadsUp(NotificationEntry entry) {
if (mStatusBarStateController.isDozing()) {
return shouldHeadsUpWhenDozing(entry);
@@ -177,17 +215,6 @@
}
}
- /**
- * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
- * incoming calls.
- */
- @Override
- public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
- return entry.getSbn().getNotification().fullScreenIntent != null
- && (!shouldHeadsUp(entry)
- || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
- }
-
private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
@@ -244,15 +271,13 @@
return false;
}
- for (int i = 0; i < mSuppressors.size(); i++) {
- if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: aborted by suppressor: "
- + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
- }
- return false;
+ if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No heads up: aborted by suppressor: " + sbn.getKey());
}
+ return false;
}
+
return true;
}
@@ -300,7 +325,7 @@
}
return false;
}
- return true;
+ return true;
}
/**
@@ -309,7 +334,8 @@
* @param entry the entry to check
* @return true if these checks pass, false if the notification should not alert
*/
- private boolean canAlertCommon(NotificationEntry entry) {
+ @VisibleForTesting
+ public boolean canAlertCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
if (mNotificationFilter.shouldFilterOut(entry)) {
@@ -326,16 +352,6 @@
}
return false;
}
-
- for (int i = 0; i < mSuppressors.size(); i++) {
- if (mSuppressors.get(i).suppressInterruptions(entry)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: aborted by suppressor: "
- + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
- }
- return false;
- }
- }
return true;
}
@@ -345,17 +361,15 @@
* @param entry the entry to check
* @return true if these checks pass, false if the notification should not alert
*/
- private boolean canAlertAwakeCommon(NotificationEntry entry) {
+ @VisibleForTesting
+ public boolean canAlertAwakeCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- for (int i = 0; i < mSuppressors.size(); i++) {
- if (mSuppressors.get(i).suppressAwakeInterruptions(entry)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: aborted by suppressor: "
- + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
- }
- return false;
+ if (mPresenter.isDeviceInVrMode()) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No alerting: no huns or vr mode");
}
+ return false;
}
if (isSnoozedPackage(sbn)) {
@@ -378,4 +392,54 @@
private boolean isSnoozedPackage(StatusBarNotification sbn) {
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
}
+
+ /** Sets whether to disable all alerts. */
+ public void setDisableNotificationAlerts(boolean disableNotificationAlerts) {
+ mDisableNotificationAlerts = disableNotificationAlerts;
+ mHeadsUpObserver.onChange(true);
+ }
+
+ /** Whether all alerts are disabled. */
+ @VisibleForTesting
+ public boolean areNotificationAlertsDisabled() {
+ return mDisableNotificationAlerts;
+ }
+
+ /** Whether HUNs should be used. */
+ @VisibleForTesting
+ public boolean getUseHeadsUp() {
+ return mUseHeadsUp;
+ }
+
+ protected NotificationPresenter getPresenter() {
+ return mPresenter;
+ }
+
+ /**
+ * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
+ * incoming calls.
+ *
+ * @param entry the entry that was added
+ * @return {@code true} if we should launch the full screen intent
+ */
+ public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
+ return entry.getSbn().getNotification().fullScreenIntent != null
+ && (!shouldHeadsUp(entry)
+ || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
+ }
+
+ /** A component which can suppress heads-up notifications due to the overall state of the UI. */
+ public interface HeadsUpSuppressor {
+ /**
+ * Returns false if the provided notification is ineligible for heads-up according to this
+ * component.
+ *
+ * @param entry entry of the notification that might be heads upped
+ * @param sbn notification that might be heads upped
+ * @return false if the notification can not be heads upped
+ */
+ boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn);
+
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 2747696..8a23e37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification
import android.animation.ObjectAnimator
+import android.content.Context
import android.util.FloatProperty
import com.android.systemui.Interpolators
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -25,10 +26,10 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.PanelExpansionListener
-import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import javax.inject.Inject
@@ -36,14 +37,15 @@
@Singleton
class NotificationWakeUpCoordinator @Inject constructor(
- private val mHeadsUpManager: HeadsUpManager,
- private val statusBarStateController: StatusBarStateController,
- private val bypassController: KeyguardBypassController,
- private val dozeParameters: DozeParameters
-) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener {
+ private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
+ private val statusBarStateController: StatusBarStateController,
+ private val bypassController: KeyguardBypassController,
+ private val dozeParameters: DozeParameters)
+ : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
+ PanelExpansionListener {
- private val mNotificationVisibility = object : FloatProperty<NotificationWakeUpCoordinator>(
- "notificationVisibility") {
+ private val mNotificationVisibility
+ = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) {
coordinator.setVisibilityAmount(value)
@@ -76,10 +78,10 @@
field = value
willWakeUp = false
if (value) {
- if (mNotificationsVisible && !mNotificationsVisibleForExpansion &&
- !bypassController.bypassEnabled) {
+ if (mNotificationsVisible && !mNotificationsVisibleForExpansion
+ && !bypassController.bypassEnabled) {
// We're waking up while pulsing, let's make sure the animation looks nice
- mStackScroller.wakeUpFromPulse()
+ mStackScroller.wakeUpFromPulse();
}
if (bypassController.bypassEnabled && !mNotificationsVisible) {
// Let's make sure our huns become visible once we are waking up in case
@@ -98,7 +100,7 @@
}
private var collapsedEnoughToHide: Boolean = false
- lateinit var iconAreaController: NotificationIconAreaController
+ lateinit var iconAreaController : NotificationIconAreaController
var pulsing: Boolean = false
set(value) {
@@ -130,8 +132,8 @@
var canShow = pulsing
if (bypassController.bypassEnabled) {
// We also allow pulsing on the lock screen!
- canShow = canShow || (wakingUp || willWakeUp || fullyAwake) &&
- statusBarStateController.state == StatusBarState.KEYGUARD
+ canShow = canShow || (wakingUp || willWakeUp || fullyAwake)
+ && statusBarStateController.state == StatusBarState.KEYGUARD
// We want to hide the notifications when collapsed too much
if (collapsedEnoughToHide) {
canShow = false
@@ -141,7 +143,7 @@
}
init {
- mHeadsUpManager.addListener(this)
+ mHeadsUpManagerPhone.addListener(this)
statusBarStateController.addCallback(this)
addListener(object : WakeUpListener {
override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
@@ -153,7 +155,7 @@
increaseSpeed = false)
}
}
- })
+ });
}
fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
@@ -176,55 +178,46 @@
* @param animate should this change be animated
* @param increaseSpeed should the speed be increased of the animation
*/
- fun setNotificationsVisibleForExpansion(
- visible: Boolean,
- animate: Boolean,
- increaseSpeed: Boolean
- ) {
+ fun setNotificationsVisibleForExpansion(visible: Boolean, animate: Boolean,
+ increaseSpeed: Boolean) {
mNotificationsVisibleForExpansion = visible
updateNotificationVisibility(animate, increaseSpeed)
if (!visible && mNotificationsVisible) {
// If we stopped expanding and we're still visible because we had a pulse that hasn't
// times out, let's release them all to make sure were not stuck in a state where
// notifications are visible
- mHeadsUpManager.releaseAllImmediately()
+ mHeadsUpManagerPhone.releaseAllImmediately()
}
}
fun addListener(listener: WakeUpListener) {
- wakeUpListeners.add(listener)
+ wakeUpListeners.add(listener);
}
fun removeListener(listener: WakeUpListener) {
- wakeUpListeners.remove(listener)
+ wakeUpListeners.remove(listener);
}
- private fun updateNotificationVisibility(
- animate: Boolean,
- increaseSpeed: Boolean
- ) {
+ private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) {
// TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore
- var visible = mNotificationsVisibleForExpansion || mHeadsUpManager.hasNotifications()
+ var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications()
visible = visible && canShowPulsingHuns
if (!visible && mNotificationsVisible && (wakingUp || willWakeUp) && mDozeAmount != 0.0f) {
// let's not make notifications invisible while waking up, otherwise the animation
// is strange
- return
+ return;
}
setNotificationsVisible(visible, animate, increaseSpeed)
}
- private fun setNotificationsVisible(
- visible: Boolean,
- animate: Boolean,
- increaseSpeed: Boolean
- ) {
+ private fun setNotificationsVisible(visible: Boolean, animate: Boolean,
+ increaseSpeed: Boolean) {
if (mNotificationsVisible == visible) {
return
}
mNotificationsVisible = visible
- mVisibilityAnimator?.cancel()
+ mVisibilityAnimator?.cancel();
if (animate) {
notifyAnimationStart(visible)
startVisibilityAnimation(increaseSpeed)
@@ -237,8 +230,8 @@
if (updateDozeAmountIfBypass()) {
return
}
- if (linear != 1.0f && linear != 0.0f &&
- (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
+ if (linear != 1.0f && linear != 0.0f
+ && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
// Let's notify the scroller that an animation started
notifyAnimationStart(mLinearDozeAmount == 1.0f)
}
@@ -252,17 +245,17 @@
mStackScroller.setDozeAmount(mDozeAmount)
updateHideAmount()
if (changed && linear == 0.0f) {
- setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
+ setNotificationsVisible(visible = false, animate = false, increaseSpeed = false);
setNotificationsVisibleForExpansion(visible = false, animate = false,
increaseSpeed = false)
}
}
override fun onStateChanged(newState: Int) {
- updateDozeAmountIfBypass()
+ updateDozeAmountIfBypass();
if (bypassController.bypassEnabled &&
- newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
- (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
+ newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED
+ && (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
// We're leaving shade locked. Let's animate the notifications away
setNotificationsVisible(visible = true, increaseSpeed = false, animate = false)
setNotificationsVisible(visible = false, increaseSpeed = false, animate = true)
@@ -273,23 +266,23 @@
override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
val collapsedEnough = expansion <= 0.9f
if (collapsedEnough != this.collapsedEnoughToHide) {
- val couldShowPulsingHuns = canShowPulsingHuns
+ val couldShowPulsingHuns = canShowPulsingHuns;
this.collapsedEnoughToHide = collapsedEnough
if (couldShowPulsingHuns && !canShowPulsingHuns) {
updateNotificationVisibility(animate = true, increaseSpeed = true)
- mHeadsUpManager.releaseAllImmediately()
+ mHeadsUpManagerPhone.releaseAllImmediately()
}
}
}
private fun updateDozeAmountIfBypass(): Boolean {
if (bypassController.bypassEnabled) {
- var amount = 1.0f
- if (statusBarStateController.state == StatusBarState.SHADE ||
- statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
- amount = 0.0f
+ var amount = 1.0f;
+ if (statusBarStateController.state == StatusBarState.SHADE
+ || statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
+ amount = 0.0f;
}
- setDozeAmount(amount, amount)
+ setDozeAmount(amount, amount)
return true
}
return false
@@ -307,7 +300,7 @@
visibilityAnimator.setInterpolator(Interpolators.LINEAR)
var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
if (increaseSpeed) {
- duration = (duration.toFloat() / 1.5F).toLong()
+ duration = (duration.toFloat() / 1.5F).toLong();
}
visibilityAnimator.setDuration(duration)
visibilityAnimator.start()
@@ -318,7 +311,7 @@
mLinearVisibilityAmount = visibilityAmount
mVisibilityAmount = mVisibilityInterpolator.getInterpolation(
visibilityAmount)
- handleAnimationFinished()
+ handleAnimationFinished();
updateHideAmount()
}
@@ -329,7 +322,7 @@
}
}
- fun getWakeUpHeight(): Float {
+ fun getWakeUpHeight() : Float {
return mStackScroller.wakeUpHeight
}
@@ -337,7 +330,7 @@
val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount)
mStackScroller.setHideAmount(linearAmount, amount)
- notificationsFullyHidden = linearAmount == 1.0f
+ notificationsFullyHidden = linearAmount == 1.0f;
}
private fun notifyAnimationStart(awake: Boolean) {
@@ -368,7 +361,7 @@
// if we animate, we see the shelf briefly visible. Instead we fully animate
// the notification and its background out
animate = false
- } else if (!wakingUp && !willWakeUp) {
+ } else if (!wakingUp && !willWakeUp){
// TODO: look that this is done properly and not by anyone else
entry.setHeadsUpAnimatingAway(true)
mEntrySetToClearWhenFinished.add(entry)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 4beeede..e8a62e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -37,8 +37,8 @@
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationClicker;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
@@ -66,7 +66,7 @@
private static final String TAG = "NotificationViewManager";
- private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+ private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final Context mContext;
private final NotifBindPipeline mNotifBindPipeline;
@@ -97,7 +97,7 @@
StatusBarStateController statusBarStateController,
NotificationGroupManager notificationGroupManager,
NotificationGutsManager notificationGutsManager,
- NotificationInterruptStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
Provider<RowInflaterTask> rowInflaterTaskProvider,
ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) {
mContext = context;
@@ -106,7 +106,7 @@
mMessagingUtil = notificationMessagingUtil;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mNotificationLockscreenUserManager = notificationLockscreenUserManager;
- mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mRowInflaterTaskProvider = rowInflaterTaskProvider;
mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
}
@@ -243,7 +243,7 @@
params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
params.setUseLowPriority(entry.isAmbient());
- if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) {
+ if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
}
//TODO: Replace this API with RowContentBindParams directly
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index cd6affd..3c0ac7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -31,8 +31,10 @@
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
@@ -42,9 +44,6 @@
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
-import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -57,7 +56,6 @@
import javax.inject.Singleton;
-import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -127,7 +125,7 @@
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
- NotificationInterruptStateProvider notificationInterruptStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationListener notificationListener,
HeadsUpManager headsUpManager) {
return new NotificationAlertingManager(
@@ -135,7 +133,7 @@
remoteInputManager,
visualStabilityManager,
statusBarStateController,
- notificationInterruptStateProvider,
+ notificationInterruptionStateProvider,
notificationListener,
headsUpManager);
}
@@ -201,9 +199,4 @@
NotificationEntryManager entryManager) {
return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager;
}
-
- /** */
- @Binds
- NotificationInterruptStateProvider bindNotificationInterruptStateProvider(
- NotificationInterruptStateProviderImpl notificationInterruptStateProviderImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
deleted file mode 100644
index 3292a8f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2020 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.interruption;
-
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-/**
- * Provides bubble-up and heads-up state for notification entries.
- *
- * When a notification is heads-up when dozing, this is also called "pulsing."
- */
-public interface NotificationInterruptStateProvider {
- /**
- * If the device is awake (not dozing):
- * Whether the notification should peek in from the top and alert the user.
- *
- * If the device is dozing:
- * Whether the notification should show the ambient view of the notification ("pulse").
- *
- * @param entry the entry to check
- * @return true if the entry should heads up, false otherwise
- */
- boolean shouldHeadsUp(NotificationEntry entry);
-
- /**
- * Whether the notification should appear as a bubble with a fly-out on top of the screen.
- *
- * @param entry the entry to check
- * @return true if the entry should bubble up, false otherwise
- */
- boolean shouldBubbleUp(NotificationEntry entry);
-
- /**
- * Whether to launch the entry's full screen intent when the entry is added.
- *
- * @param entry the entry that was added
- * @return {@code true} if we should launch the full screen intent
- */
- boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry);
-
- /**
- * Add a component that can suppress visual interruptions.
- */
- void addSuppressor(NotificationInterruptSuppressor suppressor);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java
deleted file mode 100644
index c19f8bd..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2020 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.interruption;
-
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-/** A component which can suppress visual interruptions of notifications such as heads-up and
- * bubble-up.
- */
-public interface NotificationInterruptSuppressor {
- /**
- * A unique name to identify this suppressor.
- */
- default String getName() {
- return this.getClass().getName();
- }
-
- /**
- * Returns true if the provided notification is, when the device is awake, ineligible for
- * heads-up according to this component.
- *
- * @param entry entry of the notification that might heads-up
- * @return true if the heads up interruption should be suppressed when the device is awake
- */
- default boolean suppressAwakeHeadsUp(NotificationEntry entry) {
- return false;
- }
-
- /**
- * Returns true if the provided notification is, when the device is awake, ineligible for
- * heads-up or bubble-up according to this component.
- *
- * @param entry entry of the notification that might heads-up or bubble-up
- * @return true if interruptions should be suppressed when the device is awake
- */
- default boolean suppressAwakeInterruptions(NotificationEntry entry) {
- return false;
- }
-
- /**
- * Returns true if the provided notification is, regardless of awake/dozing state,
- * ineligible for heads-up or bubble-up according to this component.
- *
- * @param entry entry of the notification that might heads-up or bubble-up
- * @return true if interruptions should be suppressed
- */
- default boolean suppressInterruptions(NotificationEntry entry) {
- return false;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 287ede4..b3a62d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -185,14 +185,15 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -403,9 +404,10 @@
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
+ private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final NotificationViewHierarchyManager mViewHierarchyManager;
private final KeyguardViewMediator mKeyguardViewMediator;
- protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+ private final NotificationAlertingManager mNotificationAlertingManager;
// for disabling the status bar
private int mDisabled1 = 0;
@@ -619,9 +621,10 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptStateProvider notificationInterruptStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
+ NotificationAlertingManager notificationAlertingManager,
DisplayMetrics displayMetrics,
MetricsLogger metricsLogger,
@UiBackground Executor uiBgExecutor,
@@ -698,9 +701,10 @@
mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
- mNotificationInterruptStateProvider = notificationInterruptStateProvider;
+ mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mViewHierarchyManager = notificationViewHierarchyManager;
mKeyguardViewMediator = keyguardViewMediator;
+ mNotificationAlertingManager = notificationAlertingManager;
mDisplayMetrics = displayMetrics;
mMetricsLogger = metricsLogger;
mUiBgExecutor = uiBgExecutor;
@@ -1234,9 +1238,9 @@
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController,
mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
- mKeyguardStateController, mKeyguardIndicationController,
- this /* statusBar */, mShadeController, mCommandQueue, mInitController,
- mNotificationInterruptStateProvider);
+ mNotificationAlertingManager, mKeyguardStateController,
+ mKeyguardIndicationController,
+ this /* statusBar */, mShadeController, mCommandQueue, mInitController);
mNotificationShelf.setOnActivatedListener(mPresenter);
mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
@@ -1585,9 +1589,8 @@
}
if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
- if (areNotificationAlertsDisabled()) {
- mHeadsUpManager.releaseAllImmediately();
- }
+ mNotificationInterruptionStateProvider.setDisableNotificationAlerts(
+ (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0);
}
if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
@@ -1602,10 +1605,6 @@
}
}
- boolean areNotificationAlertsDisabled() {
- return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
- }
-
protected H createHandler() {
return new StatusBar.H();
}
@@ -2333,7 +2332,7 @@
void checkBarModes() {
if (mDemoMode) return;
- if (mNotificationShadeWindowViewController != null) {
+ if (mNotificationShadeWindowViewController != null && getStatusBarTransitions() != null) {
checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions());
}
mNavigationBarController.checkNavBarModes(mDisplayId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 53fa263..e1a20b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -68,12 +68,12 @@
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
@@ -108,7 +108,7 @@
private final NotifCollection mNotifCollection;
private final FeatureFlags mFeatureFlags;
private final StatusBarStateController mStatusBarStateController;
- private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+ private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final MetricsLogger mMetricsLogger;
private final Context mContext;
private final NotificationPanelViewController mNotificationPanel;
@@ -142,7 +142,7 @@
NotificationLockscreenUserManager lockscreenUserManager,
ShadeController shadeController, StatusBar statusBar,
KeyguardStateController keyguardStateController,
- NotificationInterruptStateProvider notificationInterruptStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils,
Handler mainThreadHandler, Handler backgroundHandler, Executor uiBgExecutor,
ActivityIntentHelper activityIntentHelper, BubbleController bubbleController,
@@ -167,7 +167,7 @@
mActivityStarter = activityStarter;
mEntryManager = entryManager;
mStatusBarStateController = statusBarStateController;
- mNotificationInterruptStateProvider = notificationInterruptStateProvider;
+ mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mMetricsLogger = metricsLogger;
mAssistManagerLazy = assistManagerLazy;
mGroupManager = groupManager;
@@ -436,7 +436,7 @@
}
private void handleFullScreenIntent(NotificationEntry entry) {
- if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
+ if (mNotificationInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
if (shouldSuppressFullScreenIntent(entry)) {
if (DEBUG) {
Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + entry.getKey());
@@ -603,7 +603,7 @@
private final ActivityIntentHelper mActivityIntentHelper;
private final BubbleController mBubbleController;
private NotificationPanelViewController mNotificationPanelViewController;
- private NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+ private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final ShadeController mShadeController;
private NotificationPresenter mNotificationPresenter;
private ActivityLaunchAnimator mActivityLaunchAnimator;
@@ -626,7 +626,7 @@
NotificationGroupManager groupManager,
NotificationLockscreenUserManager lockscreenUserManager,
KeyguardStateController keyguardStateController,
- NotificationInterruptStateProvider notificationInterruptStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
MetricsLogger metricsLogger,
LockPatternUtils lockPatternUtils,
@Main Handler mainThreadHandler,
@@ -654,7 +654,7 @@
mGroupManager = groupManager;
mLockscreenUserManager = lockscreenUserManager;
mKeyguardStateController = keyguardStateController;
- mNotificationInterruptStateProvider = notificationInterruptStateProvider;
+ mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mMetricsLogger = metricsLogger;
mLockPatternUtils = lockPatternUtils;
mMainThreadHandler = mainThreadHandler;
@@ -712,7 +712,7 @@
mShadeController,
mStatusBar,
mKeyguardStateController,
- mNotificationInterruptStateProvider,
+ mNotificationInterruptionStateProvider,
mMetricsLogger,
mLockPatternUtils,
mMainThreadHandler,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 79cea91..30d6b507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -60,13 +60,13 @@
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -98,6 +98,8 @@
(SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
private final NotificationEntryManager mEntryManager =
Dependency.get(NotificationEntryManager.class);
+ private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
+ Dependency.get(NotificationInterruptionStateProvider.class);
private final NotificationMediaManager mMediaManager =
Dependency.get(NotificationMediaManager.class);
private final VisualStabilityManager mVisualStabilityManager =
@@ -138,13 +140,13 @@
ScrimController scrimController,
ActivityLaunchAnimator activityLaunchAnimator,
DynamicPrivacyController dynamicPrivacyController,
+ NotificationAlertingManager notificationAlertingManager,
KeyguardStateController keyguardStateController,
KeyguardIndicationController keyguardIndicationController,
StatusBar statusBar,
ShadeController shadeController,
CommandQueue commandQueue,
- InitController initController,
- NotificationInterruptStateProvider notificationInterruptStateProvider) {
+ InitController initController) {
mContext = context;
mKeyguardStateController = keyguardStateController;
mNotificationPanel = panel;
@@ -214,7 +216,8 @@
mEntryManager.addNotificationLifetimeExtender(mGutsManager);
mEntryManager.addNotificationLifetimeExtenders(
remoteInputManager.getLifetimeExtenders());
- notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor);
+ mNotificationInterruptionStateProvider.setUpWithPresenter(
+ this, mHeadsUpManager, this::canHeadsUp);
mLockscreenUserManager.setUpWithPresenter(this);
mMediaManager.setUpWithPresenter(this);
mVisualStabilityManager.setUpWithPresenter(this);
@@ -333,6 +336,39 @@
return mEntryManager.hasActiveNotifications();
}
+ public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
+ if (mStatusBar.isOccluded()) {
+ boolean devicePublic = mLockscreenUserManager.
+ isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
+ boolean userPublic = devicePublic
+ || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
+ boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
+ if (userPublic && needsRedaction) {
+ // TODO(b/135046837): we can probably relax this with dynamic privacy
+ return false;
+ }
+ }
+
+ if (!mCommandQueue.panelsEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
+ }
+ return false;
+ }
+
+ if (sbn.getNotification().fullScreenIntent != null) {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
+ return false;
+ } else {
+ // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
+ return !mKeyguardStateController.isShowing()
+ || mStatusBar.isOccluded();
+ }
+ }
+ return true;
+ }
+
@Override
public void onUserSwitched(int newUserId) {
// Begin old BaseStatusBar.userSwitched
@@ -471,66 +507,4 @@
}
}
};
-
- private final NotificationInterruptSuppressor mInterruptSuppressor =
- new NotificationInterruptSuppressor() {
- @Override
- public String getName() {
- return TAG;
- }
-
- @Override
- public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
- final StatusBarNotification sbn = entry.getSbn();
- if (mStatusBar.isOccluded()) {
- boolean devicePublic = mLockscreenUserManager
- .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
- boolean userPublic = devicePublic
- || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
- boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
- if (userPublic && needsRedaction) {
- // TODO(b/135046837): we can probably relax this with dynamic privacy
- return true;
- }
- }
-
- if (!mCommandQueue.panelsEnabled()) {
- if (DEBUG) {
- Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
- }
- return true;
- }
-
- if (sbn.getNotification().fullScreenIntent != null) {
- // we don't allow head-up on the lockscreen (unless there's a
- // "showWhenLocked" activity currently showing) if
- // the potential HUN has a fullscreen intent
- if (mKeyguardStateController.isShowing() && !mStatusBar.isOccluded()) {
- if (DEBUG) {
- Log.d(TAG, "No heads up: entry has fullscreen intent on lockscreen "
- + sbn.getKey());
- }
- return true;
- }
-
- if (mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) {
- Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
- }
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean suppressAwakeInterruptions(NotificationEntry entry) {
- return isDeviceInVrMode();
- }
-
- @Override
- public boolean suppressInterruptions(NotificationEntry entry) {
- return mStatusBar.areNotificationAlertsDisabled();
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 824e0f0..eec8d50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -56,12 +56,13 @@
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -138,9 +139,10 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptStateProvider notificationInterruptStateProvider,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
+ NotificationAlertingManager notificationAlertingManager,
DisplayMetrics displayMetrics,
MetricsLogger metricsLogger,
@UiBackground Executor uiBgExecutor,
@@ -216,9 +218,10 @@
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationInterruptStateProvider,
+ notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
+ notificationAlertingManager,
displayMetrics,
metricsLogger,
uiBgExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index 2276ba1..812a1e4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -358,7 +358,7 @@
targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
cancelAnimations()
magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
- animateStuckToTarget(targetObjectIsInMagneticFieldOf!!, velX, velY, false)
+ animateStuckToTarget(targetObjectIsInMagneticFieldOf, velX, velY, false)
vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
} else if (targetObjectIsInMagneticFieldOf == null && objectStuckToTarget) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 977d0bb..742e652 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -45,11 +45,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.res.Resources;
-import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.service.dreams.IDreamManager;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -65,12 +61,14 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -229,17 +227,15 @@
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
- new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
- mock(PowerManager.class),
- mock(IDreamManager.class),
- mock(AmbientDisplayConfiguration.class),
+ TestableNotificationInterruptionStateProvider interruptionStateProvider =
+ new TestableNotificationInterruptionStateProvider(mContext,
mock(NotificationFilter.class),
mock(StatusBarStateController.class),
- mock(BatteryController.class),
- mock(HeadsUpManager.class),
- mock(Handler.class)
- );
+ mock(BatteryController.class));
+ interruptionStateProvider.setUpWithPresenter(
+ mock(NotificationPresenter.class),
+ mock(HeadsUpManager.class),
+ mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
mBubbleData = new BubbleData(mContext);
when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mBubbleController = new TestableBubbleController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 7fc83da..22ef3f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -41,11 +41,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.res.Resources;
-import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.service.dreams.IDreamManager;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -61,10 +57,12 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -218,17 +216,15 @@
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
- new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
- mock(PowerManager.class),
- mock(IDreamManager.class),
- mock(AmbientDisplayConfiguration.class),
+ TestableNotificationInterruptionStateProvider interruptionStateProvider =
+ new TestableNotificationInterruptionStateProvider(mContext,
mock(NotificationFilter.class),
mock(StatusBarStateController.class),
- mock(BatteryController.class),
- mock(HeadsUpManager.class),
- mock(Handler.class)
- );
+ mock(BatteryController.class));
+ interruptionStateProvider.setUpWithPresenter(
+ mock(NotificationPresenter.class),
+ mock(HeadsUpManager.class),
+ mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
mBubbleData = new BubbleData(mContext);
when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
mBubbleController = new TestableBubbleController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index d3d90c4..de1fb41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -23,8 +23,8 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -44,7 +44,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptStateProvider interruptionStateProvider,
+ NotificationInterruptionStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
NotificationGroupManager groupManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
deleted file mode 100644
index 17dc76b..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2020 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.bubbles;
-
-import android.content.ContentResolver;
-import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.service.dreams.IDreamManager;
-
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-
-public class TestableNotificationInterruptStateProviderImpl
- extends NotificationInterruptStateProviderImpl {
-
- TestableNotificationInterruptStateProviderImpl(
- ContentResolver contentResolver,
- PowerManager powerManager,
- IDreamManager dreamManager,
- AmbientDisplayConfiguration ambientDisplayConfiguration,
- NotificationFilter filter,
- StatusBarStateController statusBarStateController,
- BatteryController batteryController,
- HeadsUpManager headsUpManager,
- Handler mainHandler) {
- super(contentResolver,
- powerManager,
- dreamManager,
- ambientDisplayConfiguration,
- filter,
- batteryController,
- statusBarStateController,
- headsUpManager,
- mainHandler);
- mUseHeadsUp = true;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java
new file mode 100644
index 0000000..5d192b2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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.bubbles;
+
+import android.content.Context;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+public class TestableNotificationInterruptionStateProvider
+ extends NotificationInterruptionStateProvider {
+
+ TestableNotificationInterruptionStateProvider(Context context,
+ NotificationFilter filter, StatusBarStateController controller,
+ BatteryController batteryController) {
+ super(context, filter, controller, batteryController);
+ mUseHeadsUp = true;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
similarity index 63%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
index f9c62e1..1693e7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification.interruption;
+package com.android.systemui.statusbar;
import static android.app.Notification.FLAG_BUBBLE;
@@ -30,14 +30,15 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
@@ -49,6 +50,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -66,7 +68,7 @@
*/
@RunWith(AndroidTestingRunner.class)
@SmallTest
-public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
+public class NotificationInterruptionStateProviderTest extends SysuiTestCase {
@Mock
PowerManager mPowerManager;
@@ -79,36 +81,38 @@
@Mock
StatusBarStateController mStatusBarStateController;
@Mock
+ NotificationPresenter mPresenter;
+ @Mock
HeadsUpManager mHeadsUpManager;
@Mock
- BatteryController mBatteryController;
+ NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
@Mock
- Handler mMockHandler;
+ BatteryController mBatteryController;
- private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
+ private NotificationInterruptionStateProvider mNotifInterruptionStateProvider;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mNotifInterruptionStateProvider =
- new NotificationInterruptStateProviderImpl(
- mContext.getContentResolver(),
+ new TestableNotificationInterruptionStateProvider(mContext,
mPowerManager,
mDreamManager,
mAmbientDisplayConfiguration,
mNotificationFilter,
- mBatteryController,
mStatusBarStateController,
- mHeadsUpManager,
- mMockHandler);
+ mBatteryController);
- mNotifInterruptionStateProvider.mUseHeadsUp = true;
+ mNotifInterruptionStateProvider.setUpWithPresenter(
+ mPresenter,
+ mHeadsUpManager,
+ mHeadsUpSuppressor);
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptStateProviderImpl#canAlertCommon(NotificationEntry)} will
+ * {@link NotificationInterruptionStateProvider#canAlertCommon(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills group suppression check.
*/
private void ensureStateForAlertCommon() {
@@ -117,16 +121,17 @@
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptStateProviderImpl#canAlertAwakeCommon(NotificationEntry)} will
+ * {@link NotificationInterruptionStateProvider#canAlertAwakeCommon(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills launch fullscreen check.
*/
private void ensureStateForAlertAwakeCommon() {
+ when(mPresenter.isDeviceInVrMode()).thenReturn(false);
when(mHeadsUpManager.isSnoozed(any())).thenReturn(false);
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
+ * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & DND checks.
*/
private void ensureStateForHeadsUpWhenAwake() throws RemoteException {
@@ -136,11 +141,12 @@
when(mStatusBarStateController.isDozing()).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
+ * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & DND checks.
*/
private void ensureStateForHeadsUpWhenDozing() {
@@ -152,7 +158,7 @@
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptStateProviderImpl#shouldBubbleUp(NotificationEntry)} will
+ * {@link NotificationInterruptionStateProvider#shouldBubbleUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & bubble checks.
*/
private void ensureStateForBubbleUp() {
@@ -160,53 +166,75 @@
ensureStateForAlertAwakeCommon();
}
+ /**
+ * Ensure that the disabled state is set correctly.
+ */
@Test
- public void testDefaultSuppressorDoesNotSuppress() {
- // GIVEN a suppressor without any overrides
- final NotificationInterruptSuppressor defaultSuppressor =
- new NotificationInterruptSuppressor() {
- @Override
- public String getName() {
- return "defaultSuppressor";
- }
- };
+ public void testDisableNotificationAlerts() {
+ // Enabled by default
+ assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
+
+ // Disable alerts
+ mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
+ assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isTrue();
+
+ // Enable alerts
+ mNotifInterruptionStateProvider.setDisableNotificationAlerts(false);
+ assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
+ }
+
+ /**
+ * Ensure that the disabled alert state effects whether HUNs are enabled.
+ */
+ @Test
+ public void testHunSettingsChange_enabled_butAlertsDisabled() {
+ // Set up but without a mock change observer
+ mNotifInterruptionStateProvider.setUpWithPresenter(
+ mPresenter,
+ mHeadsUpManager,
+ mHeadsUpSuppressor);
+
+ // HUNs enabled by default
+ assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isTrue();
+
+ // Set alerts disabled
+ mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
+
+ // No more HUNs
+ assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
+ }
+
+ /**
+ * Alerts can happen.
+ */
+ @Test
+ public void testCanAlertCommon_true() {
+ ensureStateForAlertCommon();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
-
- // THEN this suppressor doesn't suppress anything by default
- assertThat(defaultSuppressor.suppressAwakeHeadsUp(entry)).isFalse();
- assertThat(defaultSuppressor.suppressAwakeInterruptions(entry)).isFalse();
- assertThat(defaultSuppressor.suppressInterruptions(entry)).isFalse();
+ assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isTrue();
}
+ /**
+ * Filtered out notifications don't alert.
+ */
@Test
- public void testShouldHeadsUpAwake() throws RemoteException {
- ensureStateForHeadsUpWhenAwake();
+ public void testCanAlertCommon_false_filteredOut() {
+ ensureStateForAlertCommon();
+ when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
- NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+ NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+ assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
}
+ /**
+ * Grouped notifications have different alerting behaviours, sometimes the alert for a
+ * grouped notification may be suppressed {@link android.app.Notification#GROUP_ALERT_CHILDREN}.
+ */
@Test
- public void testShouldNotHeadsUpAwake_flteredOut() throws RemoteException {
- // GIVEN state for "heads up when awake" is true
- ensureStateForHeadsUpWhenAwake();
+ public void testCanAlertCommon_false_suppressedForGroups() {
+ ensureStateForAlertCommon();
- // WHEN this entry should be filtered out
- NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- when(mNotificationFilter.shouldFilterOut(entry)).thenReturn(true);
-
- // THEN we shouldn't heads up this entry
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
- }
-
- @Test
- public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
- // GIVEN state for "heads up when awake" is true
- ensureStateForHeadsUpWhenAwake();
-
- // WHEN the alert for a grouped notification is suppressed
- // see {@link android.app.Notification#GROUP_ALERT_CHILDREN}
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
.setOpPkg("a")
@@ -219,40 +247,40 @@
.setImportance(IMPORTANCE_DEFAULT)
.build();
- // THEN this entry shouldn't HUN
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
}
+ /**
+ * HUNs while dozing can happen.
+ */
@Test
- public void testShouldHeadsUpWhenDozing() {
+ public void testShouldHeadsUpWhenDozing_true() {
ensureStateForHeadsUpWhenDozing();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
}
+ /**
+ * Ambient display can show HUNs for new notifications, this may be disabled.
+ */
@Test
- public void testShouldNotHeadsUpWhenDozing_pulseDisabled() {
- // GIVEN state for "heads up when dozing" is true
+ public void testShouldHeadsUpWhenDozing_false_pulseDisabled() {
ensureStateForHeadsUpWhenDozing();
-
- // WHEN pulsing (HUNs when dozing) is disabled
when(mAmbientDisplayConfiguration.pulseOnNotificationEnabled(anyInt())).thenReturn(false);
- // THEN this entry shouldn't HUN
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
+ /**
+ * If the device is not in ambient display or sleeping then we don't HUN.
+ */
@Test
- public void testShouldNotHeadsUpWhenDozing_notDozing() {
- // GIVEN state for "heads up when dozing" is true
+ public void testShouldHeadsUpWhenDozing_false_notDozing() {
ensureStateForHeadsUpWhenDozing();
-
- // WHEN we're not dozing (in ambient display or sleeping)
when(mStatusBarStateController.isDozing()).thenReturn(false);
- // THEN this entry shouldn't HUN
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
@@ -262,7 +290,7 @@
* {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT}.
*/
@Test
- public void testShouldNotHeadsUpWhenDozing_suppressingAmbient() {
+ public void testShouldHeadsUpWhenDozing_false_suppressingAmbient() {
ensureStateForHeadsUpWhenDozing();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
@@ -273,18 +301,23 @@
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
+ /**
+ * Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't
+ * get to pulse.
+ */
@Test
- public void testShouldNotHeadsUpWhenDozing_lessImportant() {
+ public void testShouldHeadsUpWhenDozing_false_lessImportant() {
ensureStateForHeadsUpWhenDozing();
- // Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't
- // get to pulse
NotificationEntry entry = createNotification(IMPORTANCE_LOW);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
+ /**
+ * Heads up can happen.
+ */
@Test
- public void testShouldHeadsUp() throws RemoteException {
+ public void testShouldHeadsUp_true() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -292,11 +325,38 @@
}
/**
+ * Heads up notifications can be disabled in general.
+ */
+ @Test
+ public void testShouldHeadsUp_false_noHunsAllowed() throws RemoteException {
+ ensureStateForHeadsUpWhenAwake();
+
+ // Set alerts disabled, this should cause heads up to be false
+ mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
+ assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
+
+ NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ }
+
+ /**
+ * If the device is dozing, we don't show as heads up.
+ */
+ @Test
+ public void testShouldHeadsUp_false_dozing() throws RemoteException {
+ ensureStateForHeadsUpWhenAwake();
+ when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+ NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ }
+
+ /**
* If the notification is a bubble, and the user is not on AOD / lockscreen, then
* the bubble is shown rather than the heads up.
*/
@Test
- public void testShouldNotHeadsUp_bubble() throws RemoteException {
+ public void testShouldHeadsUp_false_bubble() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
// Bubble bit only applies to interruption when we're in the shade
@@ -309,7 +369,7 @@
* If we're not allowed to alert in general, we shouldn't be shown as heads up.
*/
@Test
- public void testShouldNotHeadsUp_filtered() throws RemoteException {
+ public void testShouldHeadsUp_false_alertCommonFalse() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
// Make canAlertCommon false by saying it's filtered out
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
@@ -323,7 +383,7 @@
* {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK}.
*/
@Test
- public void testShouldNotHeadsUp_suppressPeek() throws RemoteException {
+ public void testShouldHeadsUp_false_suppressPeek() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -339,7 +399,7 @@
* to show as a heads up.
*/
@Test
- public void testShouldNotHeadsUp_lessImportant() throws RemoteException {
+ public void testShouldHeadsUp_false_lessImportant() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
@@ -350,7 +410,7 @@
* If the device is not in use then we shouldn't be shown as heads up.
*/
@Test
- public void testShouldNotHeadsUp_deviceNotInUse() throws RemoteException {
+ public void testShouldHeadsUp_false_deviceNotInUse() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -364,58 +424,61 @@
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
+ /**
+ * If something wants to suppress this heads up, then it shouldn't be shown as a heads up.
+ */
@Test
- public void testShouldNotHeadsUp_headsUpSuppressed() throws RemoteException {
+ public void testShouldHeadsUp_false_suppressed() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
-
- // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up.
- mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeHeadsUp);
+ when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(false);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ verify(mHeadsUpSuppressor).canHeadsUp(any(), any());
}
+ /**
+ * On screen alerts don't happen when the device is in VR Mode.
+ */
@Test
- public void testShouldNotHeadsUpAwake_awakeInterruptsSuppressed() throws RemoteException {
- ensureStateForHeadsUpWhenAwake();
+ public void testCanAlertAwakeCommon__false_vrMode() {
+ ensureStateForAlertAwakeCommon();
+ when(mPresenter.isDeviceInVrMode()).thenReturn(true);
- // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up.
- mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeInterruptions);
-
- NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+ assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
}
/**
* On screen alerts don't happen when the notification is snoozed.
*/
@Test
- public void testShouldNotHeadsUp_snoozedPackage() {
- NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+ public void testCanAlertAwakeCommon_false_snoozedPackage() {
ensureStateForAlertAwakeCommon();
+ when(mHeadsUpManager.isSnoozed(any())).thenReturn(true);
- when(mHeadsUpManager.isSnoozed(entry.getSbn().getPackageName())).thenReturn(true);
-
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+ assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
}
-
+ /**
+ * On screen alerts don't happen when that package has just launched fullscreen.
+ */
@Test
- public void testShouldNotHeadsUp_justLaunchedFullscreen() {
+ public void testCanAlertAwakeCommon_false_justLaunchedFullscreen() {
ensureStateForAlertAwakeCommon();
- // On screen alerts don't happen when that package has just launched fullscreen.
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
entry.notifyFullScreenIntentLaunched();
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
}
/**
* Bubbles can happen.
*/
@Test
- public void testShouldBubbleUp() {
+ public void testShouldBubbleUp_true() {
ensureStateForBubbleUp();
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isTrue();
}
@@ -424,7 +487,7 @@
* If the notification doesn't have permission to bubble, it shouldn't bubble.
*/
@Test
- public void shouldNotBubbleUp_notAllowedToBubble() {
+ public void shouldBubbleUp_false_notAllowedToBubble() {
ensureStateForBubbleUp();
NotificationEntry entry = createBubble();
@@ -439,7 +502,7 @@
* If the notification isn't a bubble, it should definitely not show as a bubble.
*/
@Test
- public void shouldNotBubbleUp_notABubble() {
+ public void shouldBubbleUp_false_notABubble() {
ensureStateForBubbleUp();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -454,7 +517,7 @@
* If the notification doesn't have bubble metadata, it shouldn't bubble.
*/
@Test
- public void shouldNotBubbleUp_invalidMetadata() {
+ public void shouldBubbleUp_false_invalidMetadata() {
ensureStateForBubbleUp();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -466,18 +529,24 @@
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(entry)).isFalse();
}
+ /**
+ * If the notification can't heads up in general, it shouldn't bubble.
+ */
@Test
- public void shouldNotBubbleUp_suppressedInterruptions() {
+ public void shouldBubbleUp_false_alertAwakeCommonFalse() {
ensureStateForBubbleUp();
- // If the notification can't heads up in general, it shouldn't bubble.
- mNotifInterruptionStateProvider.addSuppressor(mSuppressInterruptions);
+ // Make alert common return false by pretending we're in VR mode
+ when(mPresenter.isDeviceInVrMode()).thenReturn(true);
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isFalse();
}
+ /**
+ * If the notification can't heads up in general, it shouldn't bubble.
+ */
@Test
- public void shouldNotBubbleUp_filteredOut() {
+ public void shouldBubbleUp_false_alertCommonFalse() {
ensureStateForBubbleUp();
// Make canAlertCommon false by saying it's filtered out
@@ -523,45 +592,20 @@
.build();
}
- private final NotificationInterruptSuppressor
- mSuppressAwakeHeadsUp =
- new NotificationInterruptSuppressor() {
- @Override
- public String getName() {
- return "suppressAwakeHeadsUp";
- }
+ /**
+ * Testable class overriding constructor.
+ */
+ public static class TestableNotificationInterruptionStateProvider extends
+ NotificationInterruptionStateProvider {
- @Override
- public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
- return true;
+ TestableNotificationInterruptionStateProvider(Context context,
+ PowerManager powerManager, IDreamManager dreamManager,
+ AmbientDisplayConfiguration ambientDisplayConfiguration,
+ NotificationFilter notificationFilter,
+ StatusBarStateController statusBarStateController,
+ BatteryController batteryController) {
+ super(context, powerManager, dreamManager, ambientDisplayConfiguration,
+ notificationFilter, batteryController, statusBarStateController);
}
- };
-
- private final NotificationInterruptSuppressor
- mSuppressAwakeInterruptions =
- new NotificationInterruptSuppressor() {
- @Override
- public String getName() {
- return "suppressAwakeInterruptions";
- }
-
- @Override
- public boolean suppressAwakeInterruptions(NotificationEntry entry) {
- return true;
- }
- };
-
- private final NotificationInterruptSuppressor
- mSuppressInterruptions =
- new NotificationInterruptSuppressor() {
- @Override
- public String getName() {
- return "suppressInterruptions";
- }
-
- @Override
- public boolean suppressInterruptions(NotificationEntry entry) {
- return true;
- }
- };
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index a21a047..5d0349d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -56,12 +56,12 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -108,7 +108,7 @@
@Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
@Mock private HeadsUpManager mHeadsUpManager;
- @Mock private NotificationInterruptStateProvider mNotificationInterruptionStateProvider;
+ @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationGutsManager mGutsManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index b9c5b7c..1e4df27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -67,10 +67,10 @@
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -183,7 +183,7 @@
mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class),
mock(NotificationLockscreenUserManager.class),
mKeyguardStateController,
- mock(NotificationInterruptStateProvider.class), mock(MetricsLogger.class),
+ mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class),
mock(LockPatternUtils.class), mHandler, mHandler, mUiBgExecutor,
mActivityIntentHelper, mBubbleController, mShadeController, mFeatureFlags,
mNotifPipeline, mNotifCollection)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 318e9b8..b9d2d22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -16,9 +16,8 @@
import static android.view.Display.DEFAULT_DISPLAY;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -36,7 +35,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.FakeMetricsLogger;
-import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -50,12 +48,12 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -64,7 +62,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
@@ -75,9 +72,6 @@
private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
- private NotificationInterruptStateProvider mNotificationInterruptStateProvider =
- mock(NotificationInterruptStateProvider.class);
- private NotificationInterruptSuppressor mInterruptSuppressor;
private CommandQueue mCommandQueue;
private FakeMetricsLogger mMetricsLogger;
private ShadeController mShadeController = mock(ShadeController.class);
@@ -101,11 +95,11 @@
mDependency.injectMockDependency(NotificationViewHierarchyManager.class);
mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class);
mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
+ mDependency.injectMockDependency(NotificationInterruptionStateProvider.class);
mDependency.injectMockDependency(NotificationMediaManager.class);
mDependency.injectMockDependency(VisualStabilityManager.class);
mDependency.injectMockDependency(NotificationGutsManager.class);
mDependency.injectMockDependency(NotificationShadeWindowController.class);
- mDependency.injectMockDependency(ForegroundServiceNotificationListener.class);
NotificationEntryManager entryManager =
mDependency.injectMockDependency(NotificationEntryManager.class);
when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
@@ -113,25 +107,18 @@
NotificationShadeWindowView notificationShadeWindowView =
mock(NotificationShadeWindowView.class);
when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources());
-
mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext,
mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class),
notificationShadeWindowView, mock(NotificationListContainerViewGroup.class),
mock(DozeScrimController.class), mock(ScrimController.class),
mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
- mock(KeyguardStateController.class),
+ mock(NotificationAlertingManager.class), mock(KeyguardStateController.class),
mock(KeyguardIndicationController.class), mStatusBar,
- mock(ShadeControllerImpl.class), mCommandQueue, mInitController,
- mNotificationInterruptStateProvider);
- mInitController.executePostInitTasks();
- ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor =
- ArgumentCaptor.forClass(NotificationInterruptSuppressor.class);
- verify(mNotificationInterruptStateProvider).addSuppressor(suppressorCaptor.capture());
- mInterruptSuppressor = suppressorCaptor.getValue();
+ mock(ShadeControllerImpl.class), mCommandQueue, mInitController);
}
@Test
- public void testSuppressHeadsUp_disabledStatusBar() {
+ public void testHeadsUp_disabledStatusBar() {
Notification n = new Notification.Builder(getContext(), "a").build();
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
@@ -143,12 +130,12 @@
false /* animate */);
TestableLooper.get(this).processAllMessages();
- assertTrue("The panel should suppress heads up while disabled",
- mInterruptSuppressor.suppressAwakeHeadsUp(entry));
+ assertFalse("The panel shouldn't allow heads up while disabled",
+ mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
}
@Test
- public void testSuppressHeadsUp_disabledNotificationShade() {
+ public void testHeadsUp_disabledNotificationShade() {
Notification n = new Notification.Builder(getContext(), "a").build();
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
@@ -160,39 +147,8 @@
false /* animate */);
TestableLooper.get(this).processAllMessages();
- assertTrue("The panel should suppress interruptions while notification shade "
- + "disabled",
- mInterruptSuppressor.suppressAwakeHeadsUp(entry));
- }
-
- @Test
- public void testSuppressInterruptions_vrMode() {
- Notification n = new Notification.Builder(getContext(), "a").build();
- NotificationEntry entry = new NotificationEntryBuilder()
- .setPkg("a")
- .setOpPkg("a")
- .setTag("a")
- .setNotification(n)
- .build();
- mStatusBarNotificationPresenter.mVrMode = true;
-
- assertTrue("Vr mode should suppress interruptions",
- mInterruptSuppressor.suppressAwakeInterruptions(entry));
- }
-
- @Test
- public void testSuppressInterruptions_statusBarAlertsDisabled() {
- Notification n = new Notification.Builder(getContext(), "a").build();
- NotificationEntry entry = new NotificationEntryBuilder()
- .setPkg("a")
- .setOpPkg("a")
- .setTag("a")
- .setNotification(n)
- .build();
- when(mStatusBar.areNotificationAlertsDisabled()).thenReturn(true);
-
- assertTrue("StatusBar alerts disabled shouldn't allow interruptions",
- mInterruptSuppressor.suppressInterruptions(entry));
+ assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
+ mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
}
@Test
@@ -216,3 +172,4 @@
}
}
}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index d9f4d4b..0d7734e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -42,7 +42,7 @@
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
+import android.content.Context;
import android.content.IntentFilter;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
@@ -109,17 +109,18 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -128,7 +129,6 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
@@ -160,7 +160,7 @@
private StatusBar mStatusBar;
private FakeMetricsLogger mMetricsLogger;
private PowerManager mPowerManager;
- private TestableNotificationInterruptStateProviderImpl mNotificationInterruptStateProvider;
+ private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
@@ -178,6 +178,7 @@
@Mock private DozeScrimController mDozeScrimController;
@Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock private BiometricUnlockController mBiometricUnlockController;
+ @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private NotificationListener mNotificationListener;
@Mock private KeyguardViewMediator mKeyguardViewMediator;
@@ -190,9 +191,10 @@
@Mock private StatusBarNotificationPresenter mNotificationPresenter;
@Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationFilter mNotificationFilter;
- @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+ @Mock private NotificationAlertingManager mNotificationAlertingManager;
@Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock private NotificationShadeWindowView mNotificationShadeWindowView;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private AssistManager mAssistManager;
@@ -260,12 +262,10 @@
mPowerManager = new PowerManager(mContext, powerManagerService, thermalService,
Handler.createAsync(Looper.myLooper()));
- mNotificationInterruptStateProvider =
- new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
- mPowerManager,
+ mNotificationInterruptionStateProvider =
+ new TestableNotificationInterruptionStateProvider(mContext, mPowerManager,
mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
- mStatusBarStateController, mBatteryController, mHeadsUpManager,
- new Handler(TestableLooper.get(this).getLooper()));
+ mStatusBarStateController, mBatteryController);
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -298,6 +298,9 @@
return null;
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
+ mNotificationInterruptionStateProvider.setUpWithPresenter(mNotificationPresenter,
+ mHeadsUpManager, mHeadsUpSuppressor);
+
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle();
@@ -344,9 +347,10 @@
),
mNotificationGutsManager,
notificationLogger,
- mNotificationInterruptStateProvider,
+ mNotificationInterruptionStateProvider,
mNotificationViewHierarchyManager,
mKeyguardViewMediator,
+ mNotificationAlertingManager,
new DisplayMetrics(),
mMetricsLogger,
mUiBgExecutor,
@@ -557,6 +561,7 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a")
.setGroup("a")
@@ -572,7 +577,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
+ assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -581,6 +586,7 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a")
.setGroup("a")
@@ -596,7 +602,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
+ assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -605,6 +611,7 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a").build();
@@ -617,7 +624,7 @@
.setSuppressedVisualEffects(SUPPRESSED_EFFECT_PEEK)
.build();
- assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
+ assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -626,6 +633,7 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a").build();
@@ -637,7 +645,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
+ assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -863,21 +871,19 @@
verify(mDozeServiceHost).setDozeSuppressed(false);
}
- public static class TestableNotificationInterruptStateProviderImpl extends
- NotificationInterruptStateProviderImpl {
+ public static class TestableNotificationInterruptionStateProvider extends
+ NotificationInterruptionStateProvider {
- TestableNotificationInterruptStateProviderImpl(
- ContentResolver contentResolver,
+ TestableNotificationInterruptionStateProvider(
+ Context context,
PowerManager powerManager,
IDreamManager dreamManager,
AmbientDisplayConfiguration ambientDisplayConfiguration,
NotificationFilter filter,
StatusBarStateController controller,
- BatteryController batteryController,
- HeadsUpManager headsUpManager,
- Handler mainHandler) {
- super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
- batteryController, controller, headsUpManager, mainHandler);
+ BatteryController batteryController) {
+ super(context, powerManager, dreamManager, ambientDisplayConfiguration, filter,
+ batteryController, controller);
mUseHeadsUp = true;
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 644f0f7..91348aa 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2588,8 +2588,13 @@
return;
}
+ // if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze
+ if (app.frozen && app.shouldNotFreeze) {
+ mCachedAppOptimizer.unfreezeAppLocked(app);
+ }
+
// Use current adjustment when freezing, set adjustment when unfreezing.
- if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.frozen) {
+ if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.frozen && !app.shouldNotFreeze) {
mCachedAppOptimizer.freezeAppAsync(app);
} else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ && app.frozen) {
mCachedAppOptimizer.unfreezeAppLocked(app);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 984ae21..688c9ae 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1570,10 +1570,16 @@
mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId);
- mService.getPackageManagerInternalLocked().grantImplicitAccess(
- mStartActivity.mUserId, mIntent,
- UserHandle.getAppId(mStartActivity.info.applicationInfo.uid), mCallingUid,
- true /*direct*/);
+ if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) {
+ // we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
+ final PackageManagerInternal pmInternal =
+ mService.getPackageManagerInternalLocked();
+ final int resultToUid = pmInternal.getPackageUidInternal(
+ mStartActivity.resultTo.info.packageName, 0, mStartActivity.mUserId);
+ pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
+ UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
+ resultToUid /*visible*/, true /*direct*/);
+ }
if (newTask) {
EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
mStartActivity.getTask().mTaskId);
diff --git a/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java b/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java
new file mode 100644
index 0000000..2fbfeba
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 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.server;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.service.watchdog.ExplicitHealthCheckService;
+import android.service.watchdog.IExplicitHealthCheckService;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+
+public class ExplicitHealthCheckServiceTest {
+
+ private ExplicitHealthCheckService mExplicitHealthCheckService;
+ private static final String PACKAGE_NAME = "com.test.package";
+
+ @Before
+ public void setup() throws Exception {
+ mExplicitHealthCheckService = spy(ExplicitHealthCheckService.class);
+ }
+
+ /**
+ * Test to verify that the correct information is sent in the callback when a package has
+ * passed an explicit health check.
+ */
+ @Test
+ public void testNotifyHealthCheckPassed() throws Exception {
+ IBinder binder = mExplicitHealthCheckService.onBind(new Intent());
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ RemoteCallback callback = new RemoteCallback(result -> {
+ assertThat(result.get(ExplicitHealthCheckService.EXTRA_HEALTH_CHECK_PASSED_PACKAGE))
+ .isEqualTo(PACKAGE_NAME);
+ countDownLatch.countDown();
+ });
+ IExplicitHealthCheckService.Stub.asInterface(binder).setCallback(callback);
+ mExplicitHealthCheckService.notifyHealthCheckPassed(PACKAGE_NAME);
+ countDownLatch.await();
+ }
+}