Merge "Show notification when routine battery mode activates"
diff --git a/Android.bp b/Android.bp
index eb9cbbb..93c94e3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -872,6 +872,7 @@
local_include_dir: "core/java",
srcs: [
"core/java/android/net/INetworkStackConnector.aidl",
+ "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
],
api_dir: "aidl/networkstack",
}
diff --git a/api/current.txt b/api/current.txt
index 850d9ac..faf7c24 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -42761,10 +42761,10 @@
ctor public CallRedirectionService();
method public final void cancelCall();
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
method public final boolean onUnbind(android.content.Intent);
method public final void placeCallUnmodified();
- method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
}
diff --git a/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl b/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl
new file mode 100644
index 0000000..7b8b9ee
--- /dev/null
+++ b/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl
@@ -0,0 +1,30 @@
+/**
+ *
+ * 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 android.net.dhcp;
+
+parcelable DhcpServingParamsParcel {
+ int serverAddr;
+ int serverAddrPrefixLength;
+ int[] defaultRouters;
+ int[] dnsServers;
+ int[] excludedAddrs;
+ long dhcpLeaseTimeSecs;
+ int linkMtu;
+ boolean metered;
+}
+
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index d979309..4c0ee6f 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -353,26 +353,6 @@
}
/**
- * Attempt to setup ANGLE with a (temporary) default rules file: b/121153494
- * True: Rules file was loaded.
- * False: Rules file was *not* loaded.
- */
- private boolean setupAngleRulesDebug(String packageName, String paths, String devOptIn) {
- // b/121153494
- // Skip APK rules file checking.
- if (!DEBUG) {
- Log.v(TAG, "Skipping loading the rules file.");
- // Fill in some default values for now, so the loader can get an answer when it asks.
- // Most importantly, we need to indicate which app we are init'ing and what the
- // developer options for it are so we can turn on ANGLE if needed.
- setAngleInfo(paths, packageName, devOptIn, null, 0, 0);
- return true;
- }
-
- return false;
- }
-
- /**
* Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
* True: APK rules file was loaded.
* False: APK rules file was *not* loaded.
@@ -450,12 +430,6 @@
return;
}
- // b/121153494
- if (setupAngleRulesDebug(packageName, paths, devOptIn)) {
- // We setup ANGLE with defaults, so we're done here.
- return;
- }
-
if (setupAngleRulesApk(anglePkgName, angleInfo, context, packageName, paths, devOptIn)) {
// We setup ANGLE with rules from the APK, so we're done here.
return;
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 5b7ae70..9170d6d 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -18,6 +18,7 @@
#include <private/hwui/WebViewFunctor.h>
#include "Properties.h"
+#include "renderthread/RenderThread.h"
#include <log/log.h>
#include <utils/Trace.h>
@@ -90,6 +91,10 @@
mHasContext = false;
ATRACE_NAME("WebViewFunctor::onContextDestroyed");
mCallbacks.onContextDestroyed(mFunctor, mData);
+
+ // grContext may be null in unit tests.
+ auto* grContext = renderthread::RenderThread::getInstance().getGrContext();
+ if (grContext) grContext->resetContext();
}
}
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 12666b3..5272227 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -123,6 +123,7 @@
friend class RenderProxy;
friend class DummyVsyncSource;
friend class android::uirenderer::TestUtils;
+ friend class android::uirenderer::WebViewFunctor;
RenderThread();
virtual ~RenderThread();
diff --git a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
index 1d3d607..5af7d43 100644
--- a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
@@ -31,7 +31,7 @@
class BitmapFillrate : public TestScene {
public:
- BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
void createContent(int width, int height, Canvas& canvas) override {
@@ -70,4 +70,4 @@
BitmapAllocationTestUtils::BitmapAllocator mAllocator;
std::vector<sp<RenderNode> > mNodes;
-};
\ No newline at end of file
+};
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index ad11a1d..5107660 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -26,7 +26,7 @@
class BitmapShaders : public TestScene {
public:
- BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
sp<RenderNode> card;
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index a64e844..286f5f1 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -48,7 +48,7 @@
class TvApp : public TestScene {
public:
- TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
sp<RenderNode> mBg;
@@ -232,7 +232,7 @@
class TvAppNoRoundedCorner : public TvApp {
public:
- TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
+ explicit TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
virtual float roundedCornerRadius() override { return dp(0); }
@@ -240,7 +240,7 @@
class TvAppColorFilter : public TvApp {
public:
- TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
+ explicit TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
virtual bool useOverlay() override { return false; }
@@ -248,7 +248,7 @@
class TvAppNoRoundedCornerColorFilter : public TvApp {
public:
- TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TvApp(allocator) {}
private:
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 479c462..635429d 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -44,7 +44,7 @@
static const int CANVAS_HEIGHT = 100;
class PropertyTestCanvas : public TestCanvasBase {
public:
- PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
+ explicit PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
: TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT), mCallback(callback) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
EXPECT_EQ(mDrawCounter++, 0);
diff --git a/libs/hwui/tests/unit/ThreadBaseTests.cpp b/libs/hwui/tests/unit/ThreadBaseTests.cpp
index 1168ff2..817c1f3 100644
--- a/libs/hwui/tests/unit/ThreadBaseTests.cpp
+++ b/libs/hwui/tests/unit/ThreadBaseTests.cpp
@@ -95,7 +95,7 @@
};
struct Counter {
- Counter(EventCount* count) : mCount(count) { mCount->construct++; }
+ explicit Counter(EventCount* count) : mCount(count) { mCount->construct++; }
Counter(const Counter& other) : mCount(other.mCount) {
if (mCount) mCount->copy++;
@@ -148,4 +148,4 @@
ASSERT_EQ(1, dummyObject->getStrongCount());
ASSERT_EQ(2, lifecycleTestHelper(dummyObject));
ASSERT_EQ(1, dummyObject->getStrongCount());
-}
\ No newline at end of file
+}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index f75f69b..fda0fc4 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -102,7 +102,7 @@
"libhidlbase",
"libhidlmemory",
- "libpowermanager", // Used by JWakeLock. Will be replace with public SDJ API.
+ "libpowermanager", // Used by JWakeLock. Will be replace with public SDK API.
"libmediametrics", // Used by MediaMetrics. Will be replaced with stable C API.
"libbinder", // Used by JWakeLock and MediaMetrics.
@@ -111,6 +111,7 @@
// NDK or NDK-compliant
"libandroid",
+ "libbinder_ndk",
"libmediandk",
"libnativehelper_compat_libc++",
"liblog",
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
index 62502ef..6d960d7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
@@ -18,8 +18,8 @@
import android.content.Context;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */
public class CarNotificationInterruptionStateProvider extends
@@ -29,7 +29,7 @@
}
@Override
- public boolean shouldHeadsUp(NotificationData.Entry entry) {
+ 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.
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 3cc9bb6..9d81064 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -56,12 +56,12 @@
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index b0b7e6c..96f216e 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -24,9 +24,9 @@
import android.util.Log;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -49,18 +49,18 @@
mForegroundServiceController = foregroundServiceController;
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onPendingEntryAdded(NotificationData.Entry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
addNotification(entry.notification, entry.importance);
}
@Override
- public void onEntryUpdated(NotificationData.Entry entry) {
+ public void onEntryUpdated(NotificationEntry entry) {
updateNotification(entry.notification, entry.importance);
}
@Override
public void onEntryRemoved(
- NotificationData.Entry entry,
+ NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
removeNotification(entry.notification);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 5347a5c..d0111cb 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -40,9 +40,9 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 6447233..7577609 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -35,9 +35,9 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.util.ArrayList;
@@ -180,7 +180,7 @@
/**
* Adds a bubble associated with the provided notification entry or updates it if it exists.
*/
- public void addBubble(NotificationData.Entry notif) {
+ public void addBubble(NotificationEntry notif) {
if (mBubbles.containsKey(notif.key)) {
// It's an update
BubbleView bubble = mBubbles.get(notif.key);
@@ -226,7 +226,7 @@
bv.getEntry().setBubbleDismissed(true);
}
- NotificationData.Entry entry = mNotificationEntryManager.getNotificationData().get(key);
+ NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
if (entry != null) {
entry.setBubbleDismissed(true);
if (!DEBUG_DEMOTE_TO_NOTIF) {
@@ -241,7 +241,7 @@
@SuppressWarnings("FieldCanBeLocal")
private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
@Override
- public void onPendingEntryAdded(NotificationData.Entry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
if (shouldAutoBubble(mContext, entry)) {
entry.setIsBubble(true);
}
@@ -275,7 +275,7 @@
}
ArrayList<BubbleView> viewsToRemove = new ArrayList<>();
for (BubbleView bv : mBubbles.values()) {
- NotificationData.Entry entry = bv.getEntry();
+ NotificationEntry entry = bv.getEntry();
if (entry != null) {
if (entry.isRowRemoved() || entry.isBubbleDismissed() || entry.isRowDismissed()) {
viewsToRemove.add(bv);
@@ -332,7 +332,7 @@
/**
* Whether the notification should bubble or not.
*/
- private static boolean shouldAutoBubble(Context context, NotificationData.Entry entry) {
+ private static boolean shouldAutoBubble(Context context, NotificationEntry entry) {
if (entry.isBubbleDismissed()) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index dfd18b2..d69e7b3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -40,7 +40,7 @@
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -247,7 +247,7 @@
* @param bubbleView the view to update in the stack.
* @param entry the entry to update it with.
*/
- public void updateBubble(BubbleView bubbleView, NotificationData.Entry entry) {
+ public void updateBubble(BubbleView bubbleView, NotificationEntry entry) {
// TODO - move to top of bubble stack, make it show its update if it makes sense
bubbleView.update(entry);
if (bubbleView.equals(mExpandedBubble)) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 6c47aac..3307992 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -31,7 +31,7 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
/**
@@ -43,7 +43,7 @@
private Context mContext;
private View mIconView;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private int mBubbleSize;
private int mIconSize;
@@ -72,7 +72,7 @@
*
* @param entry the notification to display as a bubble.
*/
- public void setNotif(NotificationData.Entry entry) {
+ public void setNotif(NotificationEntry entry) {
removeAllViews();
// TODO: migrate to inflater
mIconView = new ImageView(mContext);
@@ -89,7 +89,7 @@
/**
* Updates the UI based on the entry.
*/
- public void update(NotificationData.Entry entry) {
+ public void update(NotificationEntry entry) {
mEntry = entry;
Notification n = entry.notification.getNotification();
Icon ic = n.getLargeIcon() != null ? n.getLargeIcon() : n.getSmallIcon();
@@ -112,7 +112,7 @@
/**
* @return the notification entry associated with this bubble.
*/
- public NotificationData.Entry getEntry() {
+ public NotificationEntry getEntry() {
return mEntry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index bc38169..a776d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar;
-import static com.android.systemui.statusbar.notification.NotificationData.Entry;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
@@ -29,6 +27,7 @@
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import java.util.stream.Stream;
@@ -48,7 +47,7 @@
* NotificationManagerService side, but we keep it to prevent the UI from looking weird and
* will remove when possible. See {@link NotificationLifetimeExtender}
*/
- protected final ArraySet<Entry> mExtendedLifetimeAlertEntries = new ArraySet<>();
+ protected final ArraySet<NotificationEntry> mExtendedLifetimeAlertEntries = new ArraySet<>();
protected NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
protected int mMinimumDisplayTime;
@@ -61,7 +60,7 @@
* Adds the notification to be managed.
* @param entry entry to show
*/
- public void showNotification(@NonNull Entry entry) {
+ public void showNotification(@NonNull NotificationEntry entry) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "showNotification");
}
@@ -139,7 +138,7 @@
* @return the entry
*/
@Nullable
- public Entry getEntry(@NonNull String key) {
+ public NotificationEntry getEntry(@NonNull String key) {
AlertEntry entry = mAlertEntries.get(key);
return entry != null ? entry.mEntry : null;
}
@@ -149,7 +148,7 @@
* @return all entries
*/
@NonNull
- public Stream<Entry> getAllEntries() {
+ public Stream<NotificationEntry> getAllEntries() {
return mAlertEntries.values().stream().map(headsUpEntry -> headsUpEntry.mEntry);
}
@@ -180,7 +179,7 @@
* Add a new entry and begin managing it.
* @param entry the entry to add
*/
- protected final void addAlertEntry(@NonNull Entry entry) {
+ protected final void addAlertEntry(@NonNull NotificationEntry entry) {
AlertEntry alertEntry = createAlertEntry();
alertEntry.setEntry(entry);
mAlertEntries.put(entry.key, alertEntry);
@@ -203,7 +202,7 @@
if (alertEntry == null) {
return;
}
- Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
mAlertEntries.remove(key);
onAlertEntryRemoved(alertEntry);
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
@@ -250,12 +249,12 @@
}
@Override
- public boolean shouldExtendLifetime(Entry entry) {
+ public boolean shouldExtendLifetime(NotificationEntry entry) {
return !canRemoveImmediately(entry.key);
}
@Override
- public void setShouldManageLifetime(Entry entry, boolean shouldExtend) {
+ public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
if (shouldExtend) {
mExtendedLifetimeAlertEntries.add(entry);
} else {
@@ -265,17 +264,17 @@
///////////////////////////////////////////////////////////////////////////////////////////////
protected class AlertEntry implements Comparable<AlertEntry> {
- @Nullable public Entry mEntry;
+ @Nullable public NotificationEntry mEntry;
public long mPostTime;
public long mEarliestRemovaltime;
@Nullable protected Runnable mRemoveAlertRunnable;
- public void setEntry(@NonNull final Entry entry) {
+ public void setEntry(@NonNull final NotificationEntry entry) {
setEntry(entry, () -> removeAlertEntry(entry.key));
}
- public void setEntry(@NonNull final Entry entry,
+ public void setEntry(@NonNull final NotificationEntry entry,
@Nullable Runnable removeAlertRunnable) {
mEntry = entry;
mRemoveAlertRunnable = removeAlertRunnable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
index 9bfd4ee..a3beb96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
@@ -25,7 +25,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import javax.inject.Inject;
@@ -83,7 +83,7 @@
@Override
protected void onAlertEntryAdded(AlertEntry alertEntry) {
- NotificationData.Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
entry.setAmbientPulsing(true);
for (OnAmbientChangedListener listener : mListeners) {
listener.onAmbientStateChanged(entry, true);
@@ -92,7 +92,7 @@
@Override
protected void onAlertEntryRemoved(AlertEntry alertEntry) {
- NotificationData.Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
entry.setAmbientPulsing(false);
for (OnAmbientChangedListener listener : mListeners) {
listener.onAmbientStateChanged(entry, false);
@@ -131,7 +131,7 @@
* @param entry the entry that changed
* @param isPulsing true if the entry is now pulsing, false otherwise
*/
- void onAmbientStateChanged(NotificationData.Entry entry, boolean isPulsing);
+ void onAmbientStateChanged(NotificationEntry entry, boolean isPulsing);
}
private final class AmbientEntry extends AlertEntry {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index e217777..3f1ff33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -32,7 +32,7 @@
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.util.List;
@@ -50,7 +50,7 @@
private int mEndMargin;
private View mIconPlaceholder;
private TextView mTextView;
- private NotificationData.Entry mShowingEntry;
+ private NotificationEntry mShowingEntry;
private Rect mLayoutedIconRect = new Rect();
private int[] mTmpPosition = new int[2];
private boolean mFirstLayout = true;
@@ -162,7 +162,7 @@
mTextView = findViewById(R.id.text);
}
- public void setEntry(NotificationData.Entry entry) {
+ public void setEntry(NotificationEntry entry) {
if (entry != null) {
mShowingEntry = entry;
CharSequence text = entry.headsUpStatusBarText;
@@ -261,7 +261,7 @@
return super.fitSystemWindows(insets);
}
- public NotificationData.Entry getShowingEntry() {
+ public NotificationEntry getShowingEntry() {
return mShowingEntry;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
index ecd9814..0f295ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
@@ -2,7 +2,7 @@
import androidx.annotation.NonNull;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* Interface for anything that may need to keep notifications managed even after
@@ -24,7 +24,7 @@
* @param entry the entry containing the notification to check
* @return true if the notification lifetime should be extended
*/
- boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry);
+ boolean shouldExtendLifetime(@NonNull NotificationEntry entry);
/**
* Sets whether or not the lifetime should be managed by the extender. In practice, if
@@ -37,7 +37,7 @@
* @param entry the entry that needs an extended lifetime
* @param shouldManage true if the extender should manage the entry now, false otherwise
*/
- void setShouldManageLifetime(@NonNull NotificationData.Entry entry, boolean shouldManage);
+ void setShouldManageLifetime(@NonNull NotificationEntry entry, boolean shouldManage);
/**
* The callback for when the notification is now safe to remove (i.e. its lifetime has ended).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index bc662e3..f46ded4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -18,7 +18,7 @@
import android.service.notification.StatusBarNotification;
import android.util.SparseArray;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
public interface NotificationLockscreenUserManager {
String PERMISSION_SELF = "com.android.systemui.permission.SELF";
@@ -55,7 +55,7 @@
void updatePublicMode();
- boolean needsRedaction(Entry entry);
+ boolean needsRedaction(NotificationEntry entry);
boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index bba4369..d5f4d04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -46,9 +46,9 @@
import com.android.systemui.Dumpable;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -407,7 +407,7 @@
}
/** @return true if the entry needs redaction when on the lockscreen. */
- public boolean needsRedaction(NotificationData.Entry ent) {
+ public boolean needsRedaction(NotificationEntry ent) {
int userId = ent.notification.getUserId();
boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index e59bc2a..7412702 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -46,9 +46,9 @@
import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -156,7 +156,7 @@
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onEntryRemoved(
- Entry entry,
+ NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
onNotificationRemoved(entry.key);
@@ -188,7 +188,7 @@
return null;
}
synchronized (mEntryManager.getNotificationData()) {
- Entry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
+ NotificationEntry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
if (entry == null || entry.expandedIcon == null) {
return null;
}
@@ -210,15 +210,15 @@
boolean metaDataChanged = false;
synchronized (mEntryManager.getNotificationData()) {
- ArrayList<Entry> activeNotifications =
+ ArrayList<NotificationEntry> activeNotifications =
mEntryManager.getNotificationData().getActiveNotifications();
final int N = activeNotifications.size();
// Promote the media notification with a controller in 'playing' state, if any.
- Entry mediaNotification = null;
+ NotificationEntry mediaNotification = null;
MediaController controller = null;
for (int i = 0; i < N; i++) {
- final Entry entry = activeNotifications.get(i);
+ final NotificationEntry entry = activeNotifications.get(i);
if (entry.isMediaNotification()) {
final MediaSession.Token token =
@@ -258,7 +258,7 @@
final String pkg = aController.getPackageName();
for (int i = 0; i < N; i++) {
- final Entry entry = activeNotifications.get(i);
+ final NotificationEntry entry = activeNotifications.get(i);
if (entry.notification.getPackageName().equals(pkg)) {
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: found controller matching "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 1ab9c5c..7d6231f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -51,9 +51,9 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -103,7 +103,7 @@
* Notifications that are already removed but are kept around because the remote input is
* actively being used (i.e. user is typing in it). See {@link RemoteInputActiveExtender}.
*/
- protected final ArraySet<NotificationData.Entry> mEntriesKeptForRemoteInputActive =
+ protected final ArraySet<NotificationEntry> mEntriesKeptForRemoteInputActive =
new ArraySet<>();
// Dependencies:
@@ -253,7 +253,7 @@
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onEntryRemoved(
- @Nullable NotificationData.Entry entry,
+ @Nullable NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
if (removedByUser && entry != null) {
@@ -269,7 +269,7 @@
mRemoteInputController = new RemoteInputController(delegate);
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@Override
- public void onRemoteInputSent(NotificationData.Entry entry) {
+ public void onRemoteInputSent(NotificationEntry entry) {
if (FORCE_REMOTE_INPUT_HISTORY
&& isNotificationKeptForRemoteInputHistory(entry.key)) {
mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
@@ -413,7 +413,7 @@
}
@VisibleForTesting
- void onPerformRemoveNotification(NotificationData.Entry entry, final String key) {
+ void onPerformRemoveNotification(NotificationEntry entry, final String key) {
if (mKeysKeptForRemoteInputHistory.contains(key)) {
mKeysKeptForRemoteInputHistory.remove(key);
}
@@ -424,7 +424,7 @@
public void onPanelCollapsed() {
for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) {
- NotificationData.Entry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
+ NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
mRemoteInputController.removeRemoteInput(entry, null);
if (mNotificationLifetimeFinishedCallback != null) {
mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
@@ -437,7 +437,7 @@
return mKeysKeptForRemoteInputHistory.contains(key);
}
- public boolean shouldKeepForRemoteInputHistory(NotificationData.Entry entry) {
+ public boolean shouldKeepForRemoteInputHistory(NotificationEntry entry) {
if (entry.isDismissed()) {
return false;
}
@@ -447,7 +447,7 @@
return (mRemoteInputController.isSpinning(entry.key) || entry.hasJustSentRemoteInput());
}
- public boolean shouldKeepForSmartReplyHistory(NotificationData.Entry entry) {
+ public boolean shouldKeepForSmartReplyHistory(NotificationEntry entry) {
if (entry.isDismissed()) {
return false;
}
@@ -467,13 +467,13 @@
@VisibleForTesting
StatusBarNotification rebuildNotificationForCanceledSmartReplies(
- NotificationData.Entry entry) {
+ NotificationEntry entry) {
return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
false /* showSpinner */);
}
@VisibleForTesting
- StatusBarNotification rebuildNotificationWithRemoteInput(NotificationData.Entry entry,
+ StatusBarNotification rebuildNotificationWithRemoteInput(NotificationEntry entry,
CharSequence remoteInputText, boolean showSpinner) {
StatusBarNotification sbn = entry.notification;
@@ -530,7 +530,7 @@
}
@VisibleForTesting
- public Set<NotificationData.Entry> getEntriesKeptForRemoteInputActive() {
+ public Set<NotificationEntry> getEntriesKeptForRemoteInputActive() {
return mEntriesKeptForRemoteInputActive;
}
@@ -553,12 +553,12 @@
*/
protected class RemoteInputHistoryExtender extends RemoteInputExtender {
@Override
- public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
return shouldKeepForRemoteInputHistory(entry);
}
@Override
- public void setShouldManageLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationEntry entry,
boolean shouldExtend) {
if (shouldExtend) {
CharSequence remoteInputText = entry.remoteInputText;
@@ -599,12 +599,12 @@
*/
protected class SmartReplyHistoryExtender extends RemoteInputExtender {
@Override
- public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
return shouldKeepForSmartReplyHistory(entry);
}
@Override
- public void setShouldManageLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationEntry entry,
boolean shouldExtend) {
if (shouldExtend) {
StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
@@ -637,7 +637,7 @@
*/
protected class RemoteInputActiveExtender extends RemoteInputExtender {
@Override
- public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
if (entry.isDismissed()) {
return false;
}
@@ -645,7 +645,7 @@
}
@Override
- public void setShouldManageLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationEntry entry,
boolean shouldExtend) {
if (shouldExtend) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
index f23ae3f..f0d804d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
@@ -24,7 +24,7 @@
import androidx.annotation.VisibleForTesting;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.util.ArrayList;
import java.util.Arrays;
@@ -52,7 +52,7 @@
}
public static NotificationUiAdjustment extractFromNotificationEntry(
- NotificationData.Entry entry) {
+ NotificationEntry entry) {
return new NotificationUiAdjustment(
entry.key, entry.systemGeneratedSmartActions, entry.smartReplies);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 017a9c3..bf6caa0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -27,9 +27,9 @@
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.statusbar.notification.NotificationData;
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.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -150,13 +150,13 @@
*/
//TODO: Rewrite this to focus on Entries, or some other data object instead of views
public void updateNotificationViews() {
- ArrayList<NotificationData.Entry> activeNotifications = mEntryManager.getNotificationData()
+ ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
.getActiveNotifications();
ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
- ArrayList<NotificationData.Entry> toBubble = new ArrayList<>();
+ ArrayList<NotificationEntry> toBubble = new ArrayList<>();
final int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
- NotificationData.Entry ent = activeNotifications.get(i);
+ NotificationEntry ent = activeNotifications.get(i);
if (ent.isRowDismissed() || ent.isRowRemoved()) {
// we don't want to update removed notifications because they could
// temporarily become children if they were isolated before.
@@ -187,7 +187,7 @@
ent.getRow().setSensitive(sensitive, deviceSensitive);
ent.getRow().setNeedsRedaction(needsRedaction);
if (mGroupManager.isChildInGroupWithSummary(ent.notification)) {
- NotificationData.Entry summary = mGroupManager.getGroupSummary(ent.notification);
+ NotificationEntry summary = mGroupManager.getGroupSummary(ent.notification);
List<ExpandableNotificationRow> orderedChildren =
mTmpChildOrderMap.get(summary.getRow());
if (orderedChildren == null) {
@@ -271,7 +271,7 @@
for (int i = 0; i < toBubble.size(); i++) {
// TODO: might make sense to leave them in the shade and just reposition them
- NotificationData.Entry ent = toBubble.get(i);
+ NotificationEntry ent = toBubble.get(i);
mBubbleController.addBubble(ent);
}
@@ -385,7 +385,7 @@
}
while(!stack.isEmpty()) {
ExpandableNotificationRow row = stack.pop();
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
boolean isChildNotification =
mGroupManager.isChildInGroupWithSummary(entry.notification);
@@ -408,7 +408,7 @@
if (!showOnKeyguard) {
// min priority notifications should show if their summary is showing
if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
- NotificationData.Entry summary = mGroupManager.getLogicalGroupSummary(
+ NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
entry.notification);
if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(
summary.notification)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index e8abcc2..998cf52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -24,7 +24,7 @@
import android.util.Pair;
import com.android.internal.util.Preconditions;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.RemoteInputView;
import java.lang.ref.WeakReference;
@@ -38,7 +38,7 @@
private static final boolean ENABLE_REMOTE_INPUT =
SystemProperties.getBoolean("debug.enable_remote_input", true);
- private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen
+ private final ArrayList<Pair<WeakReference<NotificationEntry>, Object>> mOpen
= new ArrayList<>();
private final ArrayMap<String, Object> mSpinning = new ArrayMap<>();
private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
@@ -101,7 +101,7 @@
* @param entry the entry for which a remote input is now active.
* @param token a token identifying the view that is managing the remote input
*/
- public void addRemoteInput(NotificationData.Entry entry, Object token) {
+ public void addRemoteInput(NotificationEntry entry, Object token) {
Preconditions.checkNotNull(entry);
Preconditions.checkNotNull(token);
@@ -122,7 +122,7 @@
* the entry is only removed if the token matches the last added token for this
* entry. If null, the entry is removed regardless.
*/
- public void removeRemoteInput(NotificationData.Entry entry, Object token) {
+ public void removeRemoteInput(NotificationEntry entry, Object token) {
Preconditions.checkNotNull(entry);
pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
@@ -173,7 +173,7 @@
return mSpinning.get(key) == token;
}
- private void apply(NotificationData.Entry entry) {
+ private void apply(NotificationEntry entry) {
mDelegate.setRemoteInputActive(entry, isRemoteInputActive(entry));
boolean remoteInputActive = isRemoteInputActive();
int N = mCallbacks.size();
@@ -185,7 +185,7 @@
/**
* @return true if {@param entry} has an active RemoteInput
*/
- public boolean isRemoteInputActive(NotificationData.Entry entry) {
+ public boolean isRemoteInputActive(NotificationEntry entry) {
return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */,
null /* removeToken */);
}
@@ -208,10 +208,10 @@
* @return true if {@param contains} is in the set of active remote inputs
*/
private boolean pruneWeakThenRemoveAndContains(
- NotificationData.Entry contains, NotificationData.Entry remove, Object removeToken) {
+ NotificationEntry contains, NotificationEntry remove, Object removeToken) {
boolean found = false;
for (int i = mOpen.size() - 1; i >= 0; i--) {
- NotificationData.Entry item = mOpen.get(i).first.get();
+ NotificationEntry item = mOpen.get(i).first.get();
Object itemToken = mOpen.get(i).second;
boolean removeTokenMatches = (removeToken == null || itemToken == removeToken);
@@ -235,7 +235,7 @@
mCallbacks.add(callback);
}
- public void remoteInputSent(NotificationData.Entry entry) {
+ public void remoteInputSent(NotificationEntry entry) {
int N = mCallbacks.size();
for (int i = 0; i < N; i++) {
mCallbacks.get(i).onRemoteInputSent(entry);
@@ -248,16 +248,16 @@
}
// Make a copy because closing the remote inputs will modify mOpen.
- ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
+ ArrayList<NotificationEntry> list = new ArrayList<>(mOpen.size());
for (int i = mOpen.size() - 1; i >= 0; i--) {
- NotificationData.Entry entry = mOpen.get(i).first.get();
+ NotificationEntry entry = mOpen.get(i).first.get();
if (entry != null && entry.rowExists()) {
list.add(entry);
}
}
for (int i = list.size() - 1; i >= 0; i--) {
- NotificationData.Entry entry = list.get(i);
+ NotificationEntry entry = list.get(i);
if (entry.rowExists()) {
entry.closeRemoteInput();
}
@@ -268,31 +268,31 @@
mDelegate.requestDisallowLongPressAndDismiss();
}
- public void lockScrollTo(NotificationData.Entry entry) {
+ public void lockScrollTo(NotificationEntry entry) {
mDelegate.lockScrollTo(entry);
}
public interface Callback {
default void onRemoteInputActive(boolean active) {}
- default void onRemoteInputSent(NotificationData.Entry entry) {}
+ default void onRemoteInputSent(NotificationEntry entry) {}
}
public interface Delegate {
/**
* Activate remote input if necessary.
*/
- void setRemoteInputActive(NotificationData.Entry entry, boolean remoteInputActive);
+ void setRemoteInputActive(NotificationEntry entry, boolean remoteInputActive);
- /**
- * Request that the view does not dismiss nor perform long press for the current touch.
- */
- void requestDisallowLongPressAndDismiss();
+ /**
+ * Request that the view does not dismiss nor perform long press for the current touch.
+ */
+ void requestDisallowLongPressAndDismiss();
- /**
- * Request that the view is made visible by scrolling to it, and keep the scroll locked until
- * the user scrolls, or {@param v} loses focus or is detached.
- */
- void lockScrollTo(NotificationData.Entry entry);
+ /**
+ * Request that the view is made visible by scrolling to it, and keep the scroll locked until
+ * the user scrolls, or {@param entry} loses focus or is detached.
+ */
+ void lockScrollTo(NotificationEntry entry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 9e91133..573c1f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -21,8 +21,8 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.util.Set;
@@ -54,7 +54,7 @@
/**
* Notifies StatusBarService a smart reply is sent.
*/
- public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply,
+ public void smartReplySent(NotificationEntry entry, int replyIndex, CharSequence reply,
boolean generatedByAssistant) {
mCallback.onSmartReplySent(entry, reply);
mSendingKeys.add(entry.key);
@@ -70,7 +70,7 @@
* Notifies StatusBarService a smart action is clicked.
*/
public void smartActionClicked(
- NotificationData.Entry entry, int actionIndex, Notification.Action action,
+ NotificationEntry entry, int actionIndex, Notification.Action action,
boolean generatedByAssistant) {
final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
final int rank = mEntryManager.getNotificationData().getRank(entry.key);
@@ -95,7 +95,7 @@
/**
* Smart Replies and Actions have been added to the UI.
*/
- public void smartSuggestionsAdded(final NotificationData.Entry entry, int replyCount,
+ public void smartSuggestionsAdded(final NotificationEntry entry, int replyCount,
int actionCount, boolean generatedByAssistant) {
try {
mBarService.onNotificationSmartSuggestionsAdded(
@@ -105,7 +105,7 @@
}
}
- public void stopSending(final NotificationData.Entry entry) {
+ public void stopSending(final NotificationEntry entry) {
if (entry != null) {
mSendingKeys.remove(entry.notification.getKey());
}
@@ -121,6 +121,6 @@
* @param entry the entry for the notification
* @param reply the reply that was sent
*/
- void onSmartReplySent(NotificationData.Entry entry, CharSequence reply);
+ void onSmartReplySent(NotificationEntry entry, CharSequence reply);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 2bb0d5c..c24698d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -71,18 +72,18 @@
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onEntryInflated(NotificationData.Entry entry, int inflatedFlags) {
+ public void onEntryInflated(NotificationEntry entry, int inflatedFlags) {
showAlertingView(entry, inflatedFlags);
}
@Override
- public void onEntryUpdated(NotificationData.Entry entry) {
+ public void onEntryUpdated(NotificationEntry entry) {
updateAlertState(entry);
}
@Override
public void onEntryRemoved(
- NotificationData.Entry entry,
+ NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
stopAlerting(entry.key);
@@ -101,7 +102,7 @@
* @param entry entry to add
* @param inflatedFlags flags representing content views that were inflated
*/
- private void showAlertingView(NotificationData.Entry entry,
+ private void showAlertingView(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
if ((inflatedFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
// Possible for shouldHeadsUp to change between the inflation starting and ending.
@@ -123,7 +124,7 @@
}
}
- private void updateAlertState(NotificationData.Entry entry) {
+ private void updateAlertState(NotificationEntry entry) {
boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
AlertingNotificationManager alertManager;
boolean shouldAlert;
@@ -150,7 +151,7 @@
}
private static boolean alertAgain(
- NotificationData.Entry oldEntry, Notification newNotification) {
+ NotificationEntry oldEntry, Notification newNotification) {
return oldEntry == null || !oldEntry.hasInterrupted()
|| (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
deleted file mode 100644
index a51896e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ /dev/null
@@ -1,1072 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static android.app.Notification.CATEGORY_ALARM;
-import static android.app.Notification.CATEGORY_CALL;
-import static android.app.Notification.CATEGORY_EVENT;
-import static android.app.Notification.CATEGORY_MESSAGE;
-import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
-
-import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.Person;
-import android.content.Context;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.view.View;
-import android.widget.ImageView;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.InflationTask;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationGuts;
-import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * The list of currently displaying notifications.
- */
-public class NotificationData {
-
- private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
-
- /**
- * These dependencies are late init-ed
- */
- private KeyguardEnvironment mEnvironment;
- private NotificationMediaManager mMediaManager;
-
- private HeadsUpManager mHeadsUpManager;
-
- public static final class Entry {
- private static final long LAUNCH_COOLDOWN = 2000;
- private static final long REMOTE_INPUT_COOLDOWN = 500;
- private static final long INITIALIZATION_DELAY = 400;
- private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
- private static final int COLOR_INVALID = 1;
- public final String key;
- public StatusBarNotification notification;
- public NotificationChannel channel;
- public long lastAudiblyAlertedMs;
- public boolean noisy;
- public boolean ambient;
- public int importance;
- public StatusBarIconView icon;
- public StatusBarIconView expandedIcon;
- private boolean interruption;
- public boolean autoRedacted; // whether the redacted notification was generated by us
- public int targetSdk;
- private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
- public CharSequence remoteInputText;
- public List<SnoozeCriterion> snoozeCriteria;
- public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL;
- /** Smart Actions provided by the NotificationAssistantService. */
- @NonNull
- public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList();
- public CharSequence[] smartReplies = new CharSequence[0];
- @VisibleForTesting
- public int suppressedVisualEffects;
- public boolean suspended;
-
- private Entry parent; // our parent (if we're in a group)
- private ArrayList<Entry> children = new ArrayList<Entry>();
- private ExpandableNotificationRow row; // the outer expanded view
-
- private int mCachedContrastColor = COLOR_INVALID;
- private int mCachedContrastColorIsFor = COLOR_INVALID;
- private InflationTask mRunningTask = null;
- private Throwable mDebugThrowable;
- public CharSequence remoteInputTextWhenReset;
- public long lastRemoteInputSent = NOT_LAUNCHED_YET;
- public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
- public CharSequence headsUpStatusBarText;
- public CharSequence headsUpStatusBarTextPublic;
-
- private long initializationTime = -1;
-
- /**
- * Whether or not this row represents a system notification. Note that if this is
- * {@code null}, that means we were either unable to retrieve the info or have yet to
- * retrieve the info.
- */
- public Boolean mIsSystemNotification;
-
- /**
- * Has the user sent a reply through this Notification.
- */
- private boolean hasSentReply;
-
- /**
- * Whether this notification should be displayed as a bubble.
- */
- private boolean mIsBubble;
-
- /**
- * Whether the user has dismissed this notification when it was in bubble form.
- */
- private boolean mUserDismissedBubble;
-
- public Entry(StatusBarNotification n) {
- this(n, null);
- }
-
- public Entry(StatusBarNotification n, @Nullable Ranking ranking) {
- this.key = n.getKey();
- this.notification = n;
- if (ranking != null) {
- populateFromRanking(ranking);
- }
- }
-
- public void populateFromRanking(@NonNull Ranking ranking) {
- channel = ranking.getChannel();
- lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis();
- importance = ranking.getImportance();
- ambient = ranking.isAmbient();
- snoozeCriteria = ranking.getSnoozeCriteria();
- userSentiment = ranking.getUserSentiment();
- systemGeneratedSmartActions = ranking.getSmartActions() == null
- ? Collections.emptyList() : ranking.getSmartActions();
- smartReplies = ranking.getSmartReplies() == null
- ? new CharSequence[0]
- : ranking.getSmartReplies().toArray(new CharSequence[0]);
- suppressedVisualEffects = ranking.getSuppressedVisualEffects();
- suspended = ranking.isSuspended();
- }
-
- public void setInterruption() {
- interruption = true;
- }
-
- public boolean hasInterrupted() {
- return interruption;
- }
-
- public void setIsBubble(boolean bubbleable) {
- mIsBubble = bubbleable;
- }
-
- public boolean isBubble() {
- return mIsBubble;
- }
-
- public void setBubbleDismissed(boolean userDismissed) {
- mUserDismissedBubble = userDismissed;
- }
-
- public boolean isBubbleDismissed() {
- return mUserDismissedBubble;
- }
-
- /**
- * Resets the notification entry to be re-used.
- */
- public void reset() {
- if (row != null) {
- row.reset();
- }
- }
-
- public ExpandableNotificationRow getRow() {
- return row;
- }
-
- //TODO: This will go away when we have a way to bind an entry to a row
- public void setRow(ExpandableNotificationRow row) {
- this.row = row;
- }
-
- @Nullable
- public List<Entry> getChildren() {
- if (children.size() <= 0) {
- return null;
- }
-
- return children;
- }
-
- public void notifyFullScreenIntentLaunched() {
- setInterruption();
- lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
- }
-
- public boolean hasJustLaunchedFullScreenIntent() {
- return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
- }
-
- public boolean hasJustSentRemoteInput() {
- return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN;
- }
-
- public boolean hasFinishedInitialization() {
- return initializationTime == -1 ||
- SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
- }
-
- /**
- * Create the icons for a notification
- * @param context the context to create the icons with
- * @param sbn the notification
- * @throws InflationException
- */
- public void createIcons(Context context, StatusBarNotification sbn)
- throws InflationException {
- Notification n = sbn.getNotification();
- final Icon smallIcon = n.getSmallIcon();
- if (smallIcon == null) {
- throw new InflationException("No small icon in notification from "
- + sbn.getPackageName());
- }
-
- // Construct the icon.
- icon = new StatusBarIconView(context,
- sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
- icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
- // Construct the expanded icon.
- expandedIcon = new StatusBarIconView(context,
- sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
- expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
- final StatusBarIcon ic = new StatusBarIcon(
- sbn.getUser(),
- sbn.getPackageName(),
- smallIcon,
- n.iconLevel,
- n.number,
- StatusBarIconView.contentDescForNotification(context, n));
- if (!icon.set(ic) || !expandedIcon.set(ic)) {
- icon = null;
- expandedIcon = null;
- throw new InflationException("Couldn't create icon: " + ic);
- }
- expandedIcon.setVisibility(View.INVISIBLE);
- expandedIcon.setOnVisibilityChangedListener(
- newVisibility -> {
- if (row != null) {
- row.setIconsVisible(newVisibility != View.VISIBLE);
- }
- });
- }
-
- public void setIconTag(int key, Object tag) {
- if (icon != null) {
- icon.setTag(key, tag);
- expandedIcon.setTag(key, tag);
- }
- }
-
- /**
- * Update the notification icons.
- *
- * @param context the context to create the icons with.
- * @param sbn the notification to read the icon from.
- * @throws InflationException
- */
- public void updateIcons(Context context, StatusBarNotification sbn)
- throws InflationException {
- if (icon != null) {
- // Update the icon
- Notification n = sbn.getNotification();
- final StatusBarIcon ic = new StatusBarIcon(
- notification.getUser(),
- notification.getPackageName(),
- n.getSmallIcon(),
- n.iconLevel,
- n.number,
- StatusBarIconView.contentDescForNotification(context, n));
- icon.setNotification(sbn);
- expandedIcon.setNotification(sbn);
- if (!icon.set(ic) || !expandedIcon.set(ic)) {
- throw new InflationException("Couldn't update icon: " + ic);
- }
- }
- }
-
- public int getContrastedColor(Context context, boolean isLowPriority,
- int backgroundColor) {
- int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
- notification.getNotification().color;
- if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
- return mCachedContrastColor;
- }
- final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor,
- backgroundColor);
- mCachedContrastColorIsFor = rawColor;
- mCachedContrastColor = contrasted;
- return mCachedContrastColor;
- }
-
- /**
- * Abort all existing inflation tasks
- */
- public void abortTask() {
- if (mRunningTask != null) {
- mRunningTask.abort();
- mRunningTask = null;
- }
- }
-
- public void setInflationTask(InflationTask abortableTask) {
- // abort any existing inflation
- InflationTask existing = mRunningTask;
- abortTask();
- mRunningTask = abortableTask;
- if (existing != null && mRunningTask != null) {
- mRunningTask.supersedeTask(existing);
- }
- }
-
- public void onInflationTaskFinished() {
- mRunningTask = null;
- }
-
- @VisibleForTesting
- public InflationTask getRunningTask() {
- return mRunningTask;
- }
-
- /**
- * Set a throwable that is used for debugging
- *
- * @param debugThrowable the throwable to save
- */
- public void setDebugThrowable(Throwable debugThrowable) {
- mDebugThrowable = debugThrowable;
- }
-
- public Throwable getDebugThrowable() {
- return mDebugThrowable;
- }
-
- public void onRemoteInputInserted() {
- lastRemoteInputSent = NOT_LAUNCHED_YET;
- remoteInputTextWhenReset = null;
- }
-
- public void setHasSentReply() {
- hasSentReply = true;
- }
-
- public boolean isLastMessageFromReply() {
- if (!hasSentReply) {
- return false;
- }
- Bundle extras = notification.getNotification().extras;
- CharSequence[] replyTexts = extras.getCharSequenceArray(
- Notification.EXTRA_REMOTE_INPUT_HISTORY);
- if (!ArrayUtils.isEmpty(replyTexts)) {
- return true;
- }
- Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
- if (messages != null && messages.length > 0) {
- Parcelable message = messages[messages.length - 1];
- if (message instanceof Bundle) {
- Notification.MessagingStyle.Message lastMessage =
- Notification.MessagingStyle.Message.getMessageFromBundle(
- (Bundle) message);
- if (lastMessage != null) {
- Person senderPerson = lastMessage.getSenderPerson();
- if (senderPerson == null) {
- return true;
- }
- Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
- return Objects.equals(user, senderPerson);
- }
- }
- }
- return false;
- }
-
- public void setInitializationTime(long time) {
- if (initializationTime == -1) {
- initializationTime = time;
- }
- }
-
- public void sendAccessibilityEvent(int eventType) {
- if (row != null) {
- row.sendAccessibilityEvent(eventType);
- }
- }
-
- /**
- * Used by NotificationMediaManager to determine... things
- * @return {@code true} if we are a media notification
- */
- public boolean isMediaNotification() {
- if (row == null) return false;
-
- return row.isMediaRow();
- }
-
- /**
- * We are a top level child if our parent is the list of notifications duh
- * @return {@code true} if we're a top level notification
- */
- public boolean isTopLevelChild() {
- return row != null && row.isTopLevelChild();
- }
-
- public void resetUserExpansion() {
- if (row != null) row.resetUserExpansion();
- }
-
- public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
- if (row != null) row.freeContentViewWhenSafe(inflationFlag);
- }
-
- public void setAmbientPulsing(boolean pulsing) {
- if (row != null) row.setAmbientPulsing(pulsing);
- }
-
- public boolean rowExists() {
- return row != null;
- }
-
- public boolean isRowDismissed() {
- return row != null && row.isDismissed();
- }
-
- public boolean isRowRemoved() {
- return row != null && row.isRemoved();
- }
-
- /**
- * @return {@code true} if the row is null or removed
- */
- public boolean isRemoved() {
- //TODO: recycling invalidates this
- return row == null || row.isRemoved();
- }
-
- /**
- * @return {@code true} if the row is null or dismissed
- */
- public boolean isDismissed() {
- //TODO: recycling
- return row == null || row.isDismissed();
- }
-
- public boolean isRowPinned() {
- return row != null && row.isPinned();
- }
-
- public void setRowPinned(boolean pinned) {
- if (row != null) row.setPinned(pinned);
- }
-
- public boolean isRowAnimatingAway() {
- return row != null && row.isHeadsUpAnimatingAway();
- }
-
- public boolean isRowHeadsUp() {
- return row != null && row.isHeadsUp();
- }
-
- public void setHeadsUp(boolean shouldHeadsUp) {
- if (row != null) row.setHeadsUp(shouldHeadsUp);
- }
-
- public boolean mustStayOnScreen() {
- return row != null && row.mustStayOnScreen();
- }
-
- public void setHeadsUpIsVisible() {
- if (row != null) row.setHeadsUpIsVisible();
- }
-
- //TODO: i'm imagining a world where this isn't just the row, but I could be rwong
- public ExpandableNotificationRow getHeadsUpAnimationView() {
- return row;
- }
-
- public void setUserLocked(boolean userLocked) {
- if (row != null) row.setUserLocked(userLocked);
- }
-
- public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
- if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion);
- }
-
- public void setGroupExpansionChanging(boolean changing) {
- if (row != null) row.setGroupExpansionChanging(changing);
- }
-
- public void notifyHeightChanged(boolean needsAnimation) {
- if (row != null) row.notifyHeightChanged(needsAnimation);
- }
-
- public void closeRemoteInput() {
- if (row != null) row.closeRemoteInput();
- }
-
- public boolean areChildrenExpanded() {
- return row != null && row.areChildrenExpanded();
- }
-
- public boolean keepInParent() {
- return row != null && row.keepInParent();
- }
-
- //TODO: probably less confusing to say "is group fully visible"
- public boolean isGroupNotFullyVisible() {
- return row == null || row.isGroupNotFullyVisible();
- }
-
- public NotificationGuts getGuts() {
- if (row != null) return row.getGuts();
- return null;
- }
-
- public boolean hasLowPriorityStateUpdated() {
- return row != null && row.hasLowPriorityStateUpdated();
- }
-
- public void removeRow() {
- if (row != null) row.setRemoved();
- }
-
- public boolean isSummaryWithChildren() {
- return row != null && row.isSummaryWithChildren();
- }
-
- public void setKeepInParent(boolean keep) {
- if (row != null) row.setKeepInParent(keep);
- }
-
- public void onDensityOrFontScaleChanged() {
- if (row != null) row.onDensityOrFontScaleChanged();
- }
-
- public boolean areGutsExposed() {
- return row != null && row.getGuts() != null && row.getGuts().isExposed();
- }
-
- public boolean isChildInGroup() {
- return parent == null;
- }
-
- public void setLowPriorityStateUpdated(boolean updated) {
- if (row != null) row.setLowPriorityStateUpdated(updated);
- }
-
- /**
- * @return Can the underlying notification be cleared? This can be different from whether the
- * notification can be dismissed in case notifications are sensitive on the lockscreen.
- * @see #canViewBeDismissed()
- */
- public boolean isClearable() {
- if (notification == null || !notification.isClearable()) {
- return false;
- }
- if (children.size() > 0) {
- for (int i = 0; i < children.size(); i++) {
- Entry child = children.get(i);
- if (!child.isClearable()) {
- return false;
- }
- }
- }
- return true;
- }
-
- public boolean canViewBeDismissed() {
- if (row == null) return true;
- return row.canViewBeDismissed();
- }
-
- boolean isExemptFromDndVisualSuppression() {
- if (isNotificationBlockedByPolicy(notification.getNotification())) {
- return false;
- }
-
- if ((notification.getNotification().flags
- & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
- return true;
- }
- if (notification.getNotification().isMediaNotification()) {
- return true;
- }
- if (mIsSystemNotification != null && mIsSystemNotification) {
- return true;
- }
- return false;
- }
-
- private boolean shouldSuppressVisualEffect(int effect) {
- if (isExemptFromDndVisualSuppression()) {
- return false;
- }
- return (suppressedVisualEffects & effect) != 0;
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_FULL_SCREEN_INTENT}
- * is set for this entry.
- */
- public boolean shouldSuppressFullScreenIntent() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK}
- * is set for this entry.
- */
- public boolean shouldSuppressPeek() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_PEEK);
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_STATUS_BAR}
- * is set for this entry.
- */
- public boolean shouldSuppressStatusBar() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_STATUS_BAR);
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT}
- * is set for this entry.
- */
- public boolean shouldSuppressAmbient() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_AMBIENT);
- }
-
- /**
- * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST}
- * is set for this entry.
- */
- public boolean shouldSuppressNotificationList() {
- return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_NOTIFICATION_LIST);
- }
- }
-
- private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
- private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
- private final ArrayList<Entry> mFilteredForUser = new ArrayList<>();
-
- private final NotificationGroupManager mGroupManager
- = Dependency.get(NotificationGroupManager.class);
-
- private RankingMap mRankingMap;
- private final Ranking mTmpRanking = new Ranking();
-
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
- private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
- private final Ranking mRankingA = new Ranking();
- private final Ranking mRankingB = new Ranking();
-
- @Override
- public int compare(Entry a, Entry b) {
- final StatusBarNotification na = a.notification;
- final StatusBarNotification nb = b.notification;
- int aImportance = NotificationManager.IMPORTANCE_DEFAULT;
- int bImportance = NotificationManager.IMPORTANCE_DEFAULT;
- int aRank = 0;
- int bRank = 0;
-
- if (mRankingMap != null) {
- // RankingMap as received from NoMan
- getRanking(a.key, mRankingA);
- getRanking(b.key, mRankingB);
- aImportance = mRankingA.getImportance();
- bImportance = mRankingB.getImportance();
- aRank = mRankingA.getRank();
- bRank = mRankingB.getRank();
- }
-
- String mediaNotification = getMediaManager().getMediaNotificationKey();
-
- // IMPORTANCE_MIN media streams are allowed to drift to the bottom
- final boolean aMedia = a.key.equals(mediaNotification)
- && aImportance > NotificationManager.IMPORTANCE_MIN;
- final boolean bMedia = b.key.equals(mediaNotification)
- && bImportance > NotificationManager.IMPORTANCE_MIN;
-
- boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH &&
- isSystemNotification(na);
- boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH &&
- isSystemNotification(nb);
-
- boolean isHeadsUp = a.row.isHeadsUp();
- if (isHeadsUp != b.row.isHeadsUp()) {
- return isHeadsUp ? -1 : 1;
- } else if (isHeadsUp) {
- // Provide consistent ranking with headsUpManager
- return mHeadsUpManager.compare(a, b);
- } else if (a.row.isAmbientPulsing() != b.row.isAmbientPulsing()) {
- return a.row.isAmbientPulsing() ? -1 : 1;
- } else if (aMedia != bMedia) {
- // Upsort current media notification.
- return aMedia ? -1 : 1;
- } else if (aSystemMax != bSystemMax) {
- // Upsort PRIORITY_MAX system notifications
- return aSystemMax ? -1 : 1;
- } else if (aRank != bRank) {
- return aRank - bRank;
- } else {
- return Long.compare(nb.getNotification().when, na.getNotification().when);
- }
- }
- };
-
- private KeyguardEnvironment getEnvironment() {
- if (mEnvironment == null) {
- mEnvironment = Dependency.get(KeyguardEnvironment.class);
- }
- return mEnvironment;
- }
-
- private NotificationMediaManager getMediaManager() {
- if (mMediaManager == null) {
- mMediaManager = Dependency.get(NotificationMediaManager.class);
- }
- return mMediaManager;
- }
-
- /**
- * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
- *
- * <p>
- * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
- * when the environment changes.
- * <p>
- * Don't hold on to or modify the returned list.
- */
- public ArrayList<Entry> getActiveNotifications() {
- return mSortedAndFiltered;
- }
-
- public ArrayList<Entry> getNotificationsForCurrentUser() {
- mFilteredForUser.clear();
-
- synchronized (mEntries) {
- final int N = mEntries.size();
- for (int i = 0; i < N; i++) {
- Entry entry = mEntries.valueAt(i);
- final StatusBarNotification sbn = entry.notification;
- if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
- continue;
- }
- mFilteredForUser.add(entry);
- }
- }
- return mFilteredForUser;
- }
-
- public Entry get(String key) {
- return mEntries.get(key);
- }
-
- public void add(Entry entry) {
- synchronized (mEntries) {
- mEntries.put(entry.notification.getKey(), entry);
- }
- mGroupManager.onEntryAdded(entry);
-
- updateRankingAndSort(mRankingMap);
- }
-
- public Entry remove(String key, RankingMap ranking) {
- Entry removed;
- synchronized (mEntries) {
- removed = mEntries.remove(key);
- }
- if (removed == null) return null;
- mGroupManager.onEntryRemoved(removed);
- updateRankingAndSort(ranking);
- return removed;
- }
-
- /** Updates the given notification entry with the provided ranking. */
- public void update(Entry entry, RankingMap ranking, StatusBarNotification notification) {
- updateRanking(ranking);
- final StatusBarNotification oldNotification = entry.notification;
- entry.notification = notification;
- mGroupManager.onEntryUpdated(entry, oldNotification);
- }
-
- public void updateRanking(RankingMap ranking) {
- updateRankingAndSort(ranking);
- }
-
- public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
- synchronized (mEntries) {
- final int N = mEntries.size();
- for (int i = 0; i < N; i++) {
- Entry entry = mEntries.valueAt(i);
- if (uid == entry.notification.getUid()
- && pkg.equals(entry.notification.getPackageName())
- && key.equals(entry.key)) {
- if (showIcon) {
- entry.mActiveAppOps.add(appOp);
- } else {
- entry.mActiveAppOps.remove(appOp);
- }
- }
- }
- }
- }
-
- /**
- * Returns true if this notification should be displayed in the high-priority notifications
- * section (and on the lockscreen and status bar).
- */
- public boolean isHighPriority(StatusBarNotification statusBarNotification) {
- if (mRankingMap != null) {
- getRanking(statusBarNotification.getKey(), mTmpRanking);
- if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
- || statusBarNotification.getNotification().isForegroundService()
- || statusBarNotification.getNotification().hasMediaSession()) {
- return true;
- }
- if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
- for (Entry child : mGroupManager.getLogicalChildren(statusBarNotification)) {
- if (isHighPriority(child.notification)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- public boolean isAmbient(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.isAmbient();
- }
- return false;
- }
-
- public int getVisibilityOverride(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getVisibilityOverride();
- }
- return Ranking.VISIBILITY_NO_OVERRIDE;
- }
-
- /**
- * Categories that are explicitly called out on DND settings screens are always blocked, if
- * DND has flagged them, even if they are foreground or system notifications that might
- * otherwise visually bypass DND.
- */
- private static boolean isNotificationBlockedByPolicy(Notification n) {
- if (isCategory(CATEGORY_CALL, n)
- || isCategory(CATEGORY_MESSAGE, n)
- || isCategory(CATEGORY_ALARM, n)
- || isCategory(CATEGORY_EVENT, n)
- || isCategory(CATEGORY_REMINDER, n)) {
- return true;
- }
- return false;
- }
-
- private static boolean isCategory(String category, Notification n) {
- return Objects.equals(n.category, category);
- }
-
- public int getImportance(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getImportance();
- }
- return NotificationManager.IMPORTANCE_UNSPECIFIED;
- }
-
- public String getOverrideGroupKey(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getOverrideGroupKey();
- }
- return null;
- }
-
- public List<SnoozeCriterion> getSnoozeCriteria(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getSnoozeCriteria();
- }
- return null;
- }
-
- public NotificationChannel getChannel(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getChannel();
- }
- return null;
- }
-
- public int getRank(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.getRank();
- }
- return 0;
- }
-
- public boolean shouldHide(String key) {
- if (mRankingMap != null) {
- getRanking(key, mTmpRanking);
- return mTmpRanking.isSuspended();
- }
- return false;
- }
-
- private void updateRankingAndSort(RankingMap ranking) {
- if (ranking != null) {
- mRankingMap = ranking;
- synchronized (mEntries) {
- final int N = mEntries.size();
- for (int i = 0; i < N; i++) {
- Entry entry = mEntries.valueAt(i);
- if (!getRanking(entry.key, mTmpRanking)) {
- continue;
- }
- final StatusBarNotification oldSbn = entry.notification.cloneLight();
- final String overrideGroupKey = getOverrideGroupKey(entry.key);
- if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
- entry.notification.setOverrideGroupKey(overrideGroupKey);
- mGroupManager.onEntryUpdated(entry, oldSbn);
- }
- entry.populateFromRanking(mTmpRanking);
- }
- }
- }
- filterAndSort();
- }
-
- /**
- * Get the ranking from the current ranking map.
- *
- * @param key the key to look up
- * @param outRanking the ranking to populate
- *
- * @return {@code true} if the ranking was properly obtained.
- */
- @VisibleForTesting
- protected boolean getRanking(String key, Ranking outRanking) {
- return mRankingMap.getRanking(key, outRanking);
- }
-
- // TODO: This should not be public. Instead the Environment should notify this class when
- // anything changed, and this class should call back the UI so it updates itself.
- public void filterAndSort() {
- mSortedAndFiltered.clear();
-
- synchronized (mEntries) {
- final int N = mEntries.size();
- for (int i = 0; i < N; i++) {
- Entry entry = mEntries.valueAt(i);
-
- if (mNotificationFilter.shouldFilterOut(entry)) {
- continue;
- }
-
- mSortedAndFiltered.add(entry);
- }
- }
-
- Collections.sort(mSortedAndFiltered, mRankingComparator);
- }
-
- public void dump(PrintWriter pw, String indent) {
- int N = mSortedAndFiltered.size();
- pw.print(indent);
- pw.println("active notifications: " + N);
- int active;
- for (active = 0; active < N; active++) {
- NotificationData.Entry e = mSortedAndFiltered.get(active);
- dumpEntry(pw, indent, active, e);
- }
- synchronized (mEntries) {
- int M = mEntries.size();
- pw.print(indent);
- pw.println("inactive notifications: " + (M - active));
- int inactiveCount = 0;
- for (int i = 0; i < M; i++) {
- Entry entry = mEntries.valueAt(i);
- if (!mSortedAndFiltered.contains(entry)) {
- dumpEntry(pw, indent, inactiveCount, entry);
- inactiveCount++;
- }
- }
- }
- }
-
- private void dumpEntry(PrintWriter pw, String indent, int i, Entry e) {
- getRanking(e.key, mTmpRanking);
- pw.print(indent);
- pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
- StatusBarNotification n = e.notification;
- pw.print(indent);
- pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance=" +
- mTmpRanking.getImportance());
- pw.print(indent);
- pw.println(" notification=" + n.getNotification());
- }
-
- private static boolean isSystemNotification(StatusBarNotification sbn) {
- String sbnPackage = sbn.getPackageName();
- return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
- }
-
- /**
- * Provides access to keyguard state and user settings dependent data.
- */
- public interface KeyguardEnvironment {
- boolean isDeviceProvisioned();
- boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 2f60f11..c640760 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -19,6 +19,7 @@
import android.service.notification.StatusBarNotification;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
/**
@@ -29,25 +30,25 @@
* Called when a new notification is posted. At this point, the notification is "pending": its
* views haven't been inflated yet and most of the system pretends like it doesn't exist yet.
*/
- default void onPendingEntryAdded(NotificationData.Entry entry) {
+ default void onPendingEntryAdded(NotificationEntry entry) {
}
/**
* Called when a new entry is created.
*/
- default void onNotificationAdded(NotificationData.Entry entry) {
+ default void onNotificationAdded(NotificationEntry entry) {
}
/**
* Called when a notification was updated.
*/
- default void onEntryUpdated(NotificationData.Entry entry) {
+ default void onEntryUpdated(NotificationEntry entry) {
}
/**
* Called when a notification's views are inflated for the first time.
*/
- default void onEntryInflated(NotificationData.Entry entry,
+ default void onEntryInflated(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
}
@@ -57,7 +58,7 @@
*
* @param entry notification data entry that was reinflated.
*/
- default void onEntryReinflated(NotificationData.Entry entry) {
+ default void onEntryReinflated(NotificationEntry entry) {
}
/**
@@ -77,7 +78,7 @@
* @param removedByUser true if the notification was removed by a user action
*/
default void onEntryRemoved(
- NotificationData.Entry entry,
+ NotificationEntry entry,
@Nullable NotificationVisibility visibility,
boolean removedByUser) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 6b5e708..a4e3f33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -36,7 +36,9 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUpdateHandler;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
@@ -68,7 +70,7 @@
public static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
protected final Context mContext;
- protected final HashMap<String, NotificationData.Entry> mPendingNotifications = new HashMap<>();
+ protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
private final NotificationGutsManager mGutsManager =
Dependency.get(NotificationGutsManager.class);
@@ -113,7 +115,7 @@
if (mPendingNotifications.size() == 0) {
pw.println("null");
} else {
- for (NotificationData.Entry entry : mPendingNotifications.values()) {
+ for (NotificationEntry entry : mPendingNotifications.values()) {
pw.println(entry.notification);
}
}
@@ -205,11 +207,11 @@
private void abortExistingInflation(String key) {
if (mPendingNotifications.containsKey(key)) {
- NotificationData.Entry entry = mPendingNotifications.get(key);
+ NotificationEntry entry = mPendingNotifications.get(key);
entry.abortTask();
mPendingNotifications.remove(key);
}
- NotificationData.Entry addedEntry = mNotificationData.get(key);
+ NotificationEntry addedEntry = mNotificationData.get(key);
if (addedEntry != null) {
addedEntry.abortTask();
}
@@ -230,7 +232,7 @@
}
}
- private void maybeScheduleUpdateNotificationViews(NotificationData.Entry entry) {
+ private void maybeScheduleUpdateNotificationViews(NotificationEntry entry) {
long audibleAlertTimeout = RECENTLY_ALERTED_THRESHOLD_MS
- (System.currentTimeMillis() - entry.lastAudiblyAlertedMs);
if (audibleAlertTimeout > 0) {
@@ -240,7 +242,7 @@
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@InflationFlag int inflatedFlags) {
mPendingNotifications.remove(entry.key);
// If there was an async task started after the removal, we don't want to add it back to
@@ -279,7 +281,7 @@
@Nullable NotificationVisibility visibility,
boolean forceRemove,
boolean removedByUser) {
- final NotificationData.Entry entry = mNotificationData.get(key);
+ final NotificationEntry entry = mNotificationData.get(key);
abortExistingInflation(key);
@@ -337,19 +339,19 @@
*
*/
private void handleGroupSummaryRemoved(String key) {
- NotificationData.Entry entry = mNotificationData.get(key);
+ NotificationEntry entry = mNotificationData.get(key);
if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) {
if (entry.notification.getOverrideGroupKey() != null && !entry.isRowDismissed()) {
// We don't want to remove children for autobundled notifications as they are not
// always cancelled. We only remove them if they were dismissed by the user.
return;
}
- List<NotificationData.Entry> childEntries = entry.getChildren();
+ List<NotificationEntry> childEntries = entry.getChildren();
if (childEntries == null) {
return;
}
for (int i = 0; i < childEntries.size(); i++) {
- NotificationData.Entry childEntry = childEntries.get(i);
+ NotificationEntry childEntry = childEntries.get(i);
boolean isForeground = (entry.notification.getNotification().flags
& Notification.FLAG_FOREGROUND_SERVICE) != 0;
boolean keepForReply =
@@ -369,10 +371,10 @@
}
public void updateNotificationsOnDensityOrFontScaleChanged() {
- ArrayList<NotificationData.Entry> userNotifications =
+ ArrayList<NotificationEntry> userNotifications =
mNotificationData.getNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
- NotificationData.Entry entry = userNotifications.get(i);
+ NotificationEntry entry = userNotifications.get(i);
entry.onDensityOrFontScaleChanged();
boolean exposedGuts = entry.areGutsExposed();
if (exposedGuts) {
@@ -392,7 +394,7 @@
NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
rankingMap.getRanking(key, ranking);
- NotificationData.Entry entry = new NotificationData.Entry(notification, ranking);
+ NotificationEntry entry = new NotificationEntry(notification, ranking);
Dependency.get(LeakDetector.class).trackInstance(entry);
// Construct the expanded view.
@@ -445,7 +447,7 @@
final String key = notification.getKey();
abortExistingInflation(key);
- NotificationData.Entry entry = mNotificationData.get(key);
+ NotificationEntry entry = mNotificationData.get(key);
if (entry == null) {
return;
}
@@ -494,14 +496,14 @@
}
public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
- List<NotificationData.Entry> entries = new ArrayList<>();
+ List<NotificationEntry> entries = new ArrayList<>();
entries.addAll(mNotificationData.getActiveNotifications());
entries.addAll(mPendingNotifications.values());
// Has a copy of the current UI adjustments.
ArrayMap<String, NotificationUiAdjustment> oldAdjustments = new ArrayMap<>();
ArrayMap<String, Integer> oldImportances = new ArrayMap<>();
- for (NotificationData.Entry entry : entries) {
+ for (NotificationEntry entry : entries) {
NotificationUiAdjustment adjustment =
NotificationUiAdjustment.extractFromNotificationEntry(entry);
oldAdjustments.put(entry.key, adjustment);
@@ -513,7 +515,7 @@
updateRankingOfPendingNotifications(rankingMap);
// By comparing the old and new UI adjustments, reinflate the view accordingly.
- for (NotificationData.Entry entry : entries) {
+ for (NotificationEntry entry : entries) {
getRowBinder().onNotificationRankingUpdated(
entry,
oldImportances.get(entry.key),
@@ -531,7 +533,7 @@
return;
}
NotificationListenerService.Ranking tmpRanking = new NotificationListenerService.Ranking();
- for (NotificationData.Entry pendingNotification : mPendingNotifications.values()) {
+ for (NotificationEntry pendingNotification : mPendingNotifications.values()) {
rankingMap.getRanking(pendingNotification.key, tmpRanking);
pendingNotification.populateFromRanking(tmpRanking);
}
@@ -542,7 +544,7 @@
* notifications whose views have not yet been inflated. In general, the system pretends like
* these don't exist, although there are a couple exceptions.
*/
- public Iterable<NotificationData.Entry> getPendingNotificationsIterator() {
+ public Iterable<NotificationEntry> getPendingNotificationsIterator() {
return mPendingNotifications.values();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 700382a..e199ead 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -28,6 +28,8 @@
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -82,7 +84,7 @@
/**
* @return true if the provided notification should NOT be shown right now.
*/
- public boolean shouldFilterOut(NotificationData.Entry entry) {
+ public boolean shouldFilterOut(NotificationEntry entry) {
final StatusBarNotification sbn = entry.notification;
if (!(getEnvironment().isDeviceProvisioned()
|| showNotificationEvenIfUnprovisioned(sbn))) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 8bd0e9a..fc7a2b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -37,6 +37,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -139,7 +140,7 @@
* @param entry the entry to check
* @return true if the entry should heads up, false otherwise
*/
- public boolean shouldHeadsUp(NotificationData.Entry entry) {
+ public boolean shouldHeadsUp(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
if (getShadeController().isDozing()) {
@@ -227,7 +228,7 @@
* @param entry the entry to check
* @return true if the entry should ambient pulse, false otherwise
*/
- public boolean shouldPulse(NotificationData.Entry entry) {
+ public boolean shouldPulse(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
if (!getShadeController().isDozing()) {
@@ -273,14 +274,14 @@
/**
* Common checks between heads up alerting and ambient pulse alerting. See
- * {@link #shouldHeadsUp(NotificationData.Entry)} and
- * {@link #shouldPulse(NotificationData.Entry)}. Notifications that fail any of these checks
+ * {@link #shouldHeadsUp(NotificationEntry)} and
+ * {@link #shouldPulse(NotificationEntry)}. Notifications that fail any of these checks
* should not alert at all.
*
* @param entry the entry to check
* @return true if these checks pass, false if the notification should not alert
*/
- protected boolean canAlertCommon(NotificationData.Entry entry) {
+ protected boolean canAlertCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
if (mNotificationFilter.shouldFilterOut(entry)) {
@@ -325,7 +326,7 @@
* @param sbn notification that might be heads upped
* @return false if the notification can not be heads upped
*/
- boolean canHeadsUp(NotificationData.Entry entry, StatusBarNotification sbn);
+ boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
index 058efca..cc302b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
@@ -42,6 +42,7 @@
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
@@ -126,7 +127,7 @@
* Inflates the views for the given entry (possibly asynchronously).
*/
public void inflateViews(
- NotificationData.Entry entry,
+ NotificationEntry entry,
Runnable onDismissRunnable,
boolean isUpdate)
throws InflationException {
@@ -149,7 +150,7 @@
}
}
- private void bindRow(NotificationData.Entry entry, PackageManager pmUser,
+ private void bindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row,
Runnable onDismissRunnable) {
row.setExpansionLogger(mExpansionLogger, entry.notification.getKey());
@@ -197,7 +198,7 @@
* reinflating them.
*/
public void onNotificationRankingUpdated(
- NotificationData.Entry entry,
+ NotificationEntry entry,
@Nullable Integer oldImportance,
NotificationUiAdjustment oldAdjustment,
NotificationUiAdjustment newAdjustment,
@@ -224,7 +225,7 @@
//TODO: This method associates a row with an entry, but eventually needs to not do that
private void updateNotification(
- NotificationData.Entry entry,
+ NotificationEntry entry,
PackageManager pmUser,
StatusBarNotification sbn,
ExpandableNotificationRow row,
@@ -292,7 +293,7 @@
* @param sbn notification
* @param row row for the notification
*/
- void onBindRow(NotificationData.Entry entry, PackageManager pmUser,
+ void onBindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
index a194eef..f09c57d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
/**
* An object that can determine the visibility of a Notification.
*/
@@ -27,5 +29,5 @@
* @param entry
* @return true if row is in a visible location
*/
- boolean isInVisibleLocation(NotificationData.Entry entry);
+ boolean isInVisibleLocation(NotificationEntry entry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 8e6a93d..c886685 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -21,6 +21,7 @@
import androidx.collection.ArraySet;
import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -52,7 +53,7 @@
public VisualStabilityManager(NotificationEntryManager notificationEntryManager) {
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onEntryReinflated(NotificationData.Entry entry) {
+ public void onEntryReinflated(NotificationEntry entry) {
if (entry.hasLowPriorityStateUpdated()) {
onLowPriorityUpdated(entry);
if (mPresenter != null) {
@@ -163,7 +164,7 @@
}
@Override
- public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
if (isHeadsUp) {
// Heads up notifications should in general be allowed to reorder if they are out of
// view and stay at the current location if they aren't.
@@ -171,7 +172,7 @@
}
}
- private void onLowPriorityUpdated(NotificationData.Entry entry) {
+ private void onLowPriorityUpdated(NotificationEntry entry) {
mLowPriorityReorderingViews.add(entry.getRow());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
new file mode 100644
index 0000000..8c29fb5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2019 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.collection;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The list of currently displaying notifications.
+ */
+public class NotificationData {
+
+ private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
+
+ /**
+ * These dependencies are late init-ed
+ */
+ private KeyguardEnvironment mEnvironment;
+ private NotificationMediaManager mMediaManager;
+
+ private HeadsUpManager mHeadsUpManager;
+
+ private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>();
+ private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
+ private final ArrayList<NotificationEntry> mFilteredForUser = new ArrayList<>();
+
+ private final NotificationGroupManager mGroupManager =
+ Dependency.get(NotificationGroupManager.class);
+
+ private RankingMap mRankingMap;
+ private final Ranking mTmpRanking = new Ranking();
+
+ public void setHeadsUpManager(HeadsUpManager headsUpManager) {
+ mHeadsUpManager = headsUpManager;
+ }
+
+ private final Comparator<NotificationEntry> mRankingComparator =
+ new Comparator<NotificationEntry>() {
+ private final Ranking mRankingA = new Ranking();
+ private final Ranking mRankingB = new Ranking();
+
+ @Override
+ public int compare(NotificationEntry a, NotificationEntry b) {
+ final StatusBarNotification na = a.notification;
+ final StatusBarNotification nb = b.notification;
+ int aImportance = NotificationManager.IMPORTANCE_DEFAULT;
+ int bImportance = NotificationManager.IMPORTANCE_DEFAULT;
+ int aRank = 0;
+ int bRank = 0;
+
+ if (mRankingMap != null) {
+ // RankingMap as received from NoMan
+ getRanking(a.key, mRankingA);
+ getRanking(b.key, mRankingB);
+ aImportance = mRankingA.getImportance();
+ bImportance = mRankingB.getImportance();
+ aRank = mRankingA.getRank();
+ bRank = mRankingB.getRank();
+ }
+
+ String mediaNotification = getMediaManager().getMediaNotificationKey();
+
+ // IMPORTANCE_MIN media streams are allowed to drift to the bottom
+ final boolean aMedia = a.key.equals(mediaNotification)
+ && aImportance > NotificationManager.IMPORTANCE_MIN;
+ final boolean bMedia = b.key.equals(mediaNotification)
+ && bImportance > NotificationManager.IMPORTANCE_MIN;
+
+ boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH
+ && isSystemNotification(na);
+ boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH
+ && isSystemNotification(nb);
+
+ boolean isHeadsUp = a.getRow().isHeadsUp();
+ if (isHeadsUp != b.getRow().isHeadsUp()) {
+ return isHeadsUp ? -1 : 1;
+ } else if (isHeadsUp) {
+ // Provide consistent ranking with headsUpManager
+ return mHeadsUpManager.compare(a, b);
+ } else if (a.getRow().isAmbientPulsing() != b.getRow().isAmbientPulsing()) {
+ return a.getRow().isAmbientPulsing() ? -1 : 1;
+ } else if (aMedia != bMedia) {
+ // Upsort current media notification.
+ return aMedia ? -1 : 1;
+ } else if (aSystemMax != bSystemMax) {
+ // Upsort PRIORITY_MAX system notifications
+ return aSystemMax ? -1 : 1;
+ } else if (aRank != bRank) {
+ return aRank - bRank;
+ } else {
+ return Long.compare(nb.getNotification().when, na.getNotification().when);
+ }
+ }
+ };
+
+ private KeyguardEnvironment getEnvironment() {
+ if (mEnvironment == null) {
+ mEnvironment = Dependency.get(KeyguardEnvironment.class);
+ }
+ return mEnvironment;
+ }
+
+ private NotificationMediaManager getMediaManager() {
+ if (mMediaManager == null) {
+ mMediaManager = Dependency.get(NotificationMediaManager.class);
+ }
+ return mMediaManager;
+ }
+
+ /**
+ * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
+ *
+ * <p>
+ * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
+ * when the environment changes.
+ * <p>
+ * Don't hold on to or modify the returned list.
+ */
+ public ArrayList<NotificationEntry> getActiveNotifications() {
+ return mSortedAndFiltered;
+ }
+
+ public ArrayList<NotificationEntry> getNotificationsForCurrentUser() {
+ mFilteredForUser.clear();
+
+ synchronized (mEntries) {
+ final int len = mEntries.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+ final StatusBarNotification sbn = entry.notification;
+ if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
+ continue;
+ }
+ mFilteredForUser.add(entry);
+ }
+ }
+ return mFilteredForUser;
+ }
+
+ public NotificationEntry get(String key) {
+ return mEntries.get(key);
+ }
+
+ public void add(NotificationEntry entry) {
+ synchronized (mEntries) {
+ mEntries.put(entry.notification.getKey(), entry);
+ }
+ mGroupManager.onEntryAdded(entry);
+
+ updateRankingAndSort(mRankingMap);
+ }
+
+ public NotificationEntry remove(String key, RankingMap ranking) {
+ NotificationEntry removed;
+ synchronized (mEntries) {
+ removed = mEntries.remove(key);
+ }
+ if (removed == null) return null;
+ mGroupManager.onEntryRemoved(removed);
+ updateRankingAndSort(ranking);
+ return removed;
+ }
+
+ /** Updates the given notification entry with the provided ranking. */
+ public void update(
+ NotificationEntry entry,
+ RankingMap ranking,
+ StatusBarNotification notification) {
+ updateRanking(ranking);
+ final StatusBarNotification oldNotification = entry.notification;
+ entry.notification = notification;
+ mGroupManager.onEntryUpdated(entry, oldNotification);
+ }
+
+ public void updateRanking(RankingMap ranking) {
+ updateRankingAndSort(ranking);
+ }
+
+ public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
+ synchronized (mEntries) {
+ final int len = mEntries.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+ if (uid == entry.notification.getUid()
+ && pkg.equals(entry.notification.getPackageName())
+ && key.equals(entry.key)) {
+ if (showIcon) {
+ entry.mActiveAppOps.add(appOp);
+ } else {
+ entry.mActiveAppOps.remove(appOp);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns true if this notification should be displayed in the high-priority notifications
+ * section (and on the lockscreen and status bar).
+ */
+ public boolean isHighPriority(StatusBarNotification statusBarNotification) {
+ if (mRankingMap != null) {
+ getRanking(statusBarNotification.getKey(), mTmpRanking);
+ if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
+ || statusBarNotification.getNotification().isForegroundService()
+ || statusBarNotification.getNotification().hasMediaSession()) {
+ return true;
+ }
+ if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
+ final ArrayList<NotificationEntry> logicalChildren =
+ mGroupManager.getLogicalChildren(statusBarNotification);
+ for (NotificationEntry child : logicalChildren) {
+ if (isHighPriority(child.notification)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean isAmbient(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.isAmbient();
+ }
+ return false;
+ }
+
+ public int getVisibilityOverride(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getVisibilityOverride();
+ }
+ return Ranking.VISIBILITY_NO_OVERRIDE;
+ }
+
+ public int getImportance(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getImportance();
+ }
+ return NotificationManager.IMPORTANCE_UNSPECIFIED;
+ }
+
+ public String getOverrideGroupKey(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getOverrideGroupKey();
+ }
+ return null;
+ }
+
+ public List<SnoozeCriterion> getSnoozeCriteria(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getSnoozeCriteria();
+ }
+ return null;
+ }
+
+ public NotificationChannel getChannel(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getChannel();
+ }
+ return null;
+ }
+
+ public int getRank(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.getRank();
+ }
+ return 0;
+ }
+
+ public boolean shouldHide(String key) {
+ if (mRankingMap != null) {
+ getRanking(key, mTmpRanking);
+ return mTmpRanking.isSuspended();
+ }
+ return false;
+ }
+
+ private void updateRankingAndSort(RankingMap ranking) {
+ if (ranking != null) {
+ mRankingMap = ranking;
+ synchronized (mEntries) {
+ final int len = mEntries.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+ if (!getRanking(entry.key, mTmpRanking)) {
+ continue;
+ }
+ final StatusBarNotification oldSbn = entry.notification.cloneLight();
+ final String overrideGroupKey = getOverrideGroupKey(entry.key);
+ if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
+ entry.notification.setOverrideGroupKey(overrideGroupKey);
+ mGroupManager.onEntryUpdated(entry, oldSbn);
+ }
+ entry.populateFromRanking(mTmpRanking);
+ }
+ }
+ }
+ filterAndSort();
+ }
+
+ /**
+ * Get the ranking from the current ranking map.
+ *
+ * @param key the key to look up
+ * @param outRanking the ranking to populate
+ *
+ * @return {@code true} if the ranking was properly obtained.
+ */
+ @VisibleForTesting
+ protected boolean getRanking(String key, Ranking outRanking) {
+ return mRankingMap.getRanking(key, outRanking);
+ }
+
+ // TODO: This should not be public. Instead the Environment should notify this class when
+ // anything changed, and this class should call back the UI so it updates itself.
+ public void filterAndSort() {
+ mSortedAndFiltered.clear();
+
+ synchronized (mEntries) {
+ final int len = mEntries.size();
+ for (int i = 0; i < len; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+
+ if (mNotificationFilter.shouldFilterOut(entry)) {
+ continue;
+ }
+
+ mSortedAndFiltered.add(entry);
+ }
+ }
+
+ Collections.sort(mSortedAndFiltered, mRankingComparator);
+ }
+
+ public void dump(PrintWriter pw, String indent) {
+ int filteredLen = mSortedAndFiltered.size();
+ pw.print(indent);
+ pw.println("active notifications: " + filteredLen);
+ int active;
+ for (active = 0; active < filteredLen; active++) {
+ NotificationEntry e = mSortedAndFiltered.get(active);
+ dumpEntry(pw, indent, active, e);
+ }
+ synchronized (mEntries) {
+ int totalLen = mEntries.size();
+ pw.print(indent);
+ pw.println("inactive notifications: " + (totalLen - active));
+ int inactiveCount = 0;
+ for (int i = 0; i < totalLen; i++) {
+ NotificationEntry entry = mEntries.valueAt(i);
+ if (!mSortedAndFiltered.contains(entry)) {
+ dumpEntry(pw, indent, inactiveCount, entry);
+ inactiveCount++;
+ }
+ }
+ }
+ }
+
+ private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
+ getRanking(e.key, mTmpRanking);
+ pw.print(indent);
+ pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon);
+ StatusBarNotification n = e.notification;
+ pw.print(indent);
+ pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
+ + mTmpRanking.getImportance());
+ pw.print(indent);
+ pw.println(" notification=" + n.getNotification());
+ }
+
+ private static boolean isSystemNotification(StatusBarNotification sbn) {
+ String sbnPackage = sbn.getPackageName();
+ return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
+ }
+
+ /**
+ * Provides access to keyguard state and user settings dependent data.
+ */
+ public interface KeyguardEnvironment {
+ boolean isDeviceProvisioned();
+ boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
new file mode 100644
index 0000000..58aa02c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -0,0 +1,701 @@
+/*
+ * Copyright (C) 2019 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.collection;
+
+import static android.app.Notification.CATEGORY_ALARM;
+import static android.app.Notification.CATEGORY_CALL;
+import static android.app.Notification.CATEGORY_EVENT;
+import static android.app.Notification.CATEGORY_MESSAGE;
+import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager.Policy;
+import android.app.Person;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ContrastColorUtil;
+import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGuts;
+import com.android.systemui.statusbar.notification.row.NotificationInflater;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a notification that the system UI knows about
+ *
+ * Whenever the NotificationManager tells us about the existence of a new notification, we wrap it
+ * in a NotificationEntry. Thus, every notification has an associated NotificationEntry, even if
+ * that notification is never displayed to the user (for example, if it's filtered out for some
+ * reason).
+ *
+ * Entries store information about the current state of the notification. Essentially:
+ * anything that needs to persist or be modifiable even when the notification's views don't
+ * exist. Any other state should be stored on the views/view controllers themselves.
+ *
+ * At the moment, there are many things here that shouldn't be and vice-versa. Hopefully we can
+ * clean this up in the future.
+ */
+public final class NotificationEntry {
+ private static final long LAUNCH_COOLDOWN = 2000;
+ private static final long REMOTE_INPUT_COOLDOWN = 500;
+ private static final long INITIALIZATION_DELAY = 400;
+ private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
+ private static final int COLOR_INVALID = 1;
+ public final String key;
+ public StatusBarNotification notification;
+ public NotificationChannel channel;
+ public long lastAudiblyAlertedMs;
+ public boolean noisy;
+ public boolean ambient;
+ public int importance;
+ public StatusBarIconView icon;
+ public StatusBarIconView expandedIcon;
+ private boolean interruption;
+ public boolean autoRedacted; // whether the redacted notification was generated by us
+ public int targetSdk;
+ private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
+ public CharSequence remoteInputText;
+ public List<SnoozeCriterion> snoozeCriteria;
+ public int userSentiment = NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+ /** Smart Actions provided by the NotificationAssistantService. */
+ @NonNull
+ public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList();
+ public CharSequence[] smartReplies = new CharSequence[0];
+ @VisibleForTesting
+ public int suppressedVisualEffects;
+ public boolean suspended;
+
+ private NotificationEntry parent; // our parent (if we're in a group)
+ private ArrayList<NotificationEntry> children = new ArrayList<NotificationEntry>();
+ private ExpandableNotificationRow row; // the outer expanded view
+
+ private int mCachedContrastColor = COLOR_INVALID;
+ private int mCachedContrastColorIsFor = COLOR_INVALID;
+ private InflationTask mRunningTask = null;
+ private Throwable mDebugThrowable;
+ public CharSequence remoteInputTextWhenReset;
+ public long lastRemoteInputSent = NOT_LAUNCHED_YET;
+ public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
+ public CharSequence headsUpStatusBarText;
+ public CharSequence headsUpStatusBarTextPublic;
+
+ private long initializationTime = -1;
+
+ /**
+ * Whether or not this row represents a system notification. Note that if this is
+ * {@code null}, that means we were either unable to retrieve the info or have yet to
+ * retrieve the info.
+ */
+ public Boolean mIsSystemNotification;
+
+ /**
+ * Has the user sent a reply through this Notification.
+ */
+ private boolean hasSentReply;
+
+ /**
+ * Whether this notification should be displayed as a bubble.
+ */
+ private boolean mIsBubble;
+
+ /**
+ * Whether the user has dismissed this notification when it was in bubble form.
+ */
+ private boolean mUserDismissedBubble;
+
+ public NotificationEntry(StatusBarNotification n) {
+ this(n, null);
+ }
+
+ public NotificationEntry(
+ StatusBarNotification n,
+ @Nullable NotificationListenerService.Ranking ranking) {
+ this.key = n.getKey();
+ this.notification = n;
+ if (ranking != null) {
+ populateFromRanking(ranking);
+ }
+ }
+
+ public void populateFromRanking(@NonNull NotificationListenerService.Ranking ranking) {
+ channel = ranking.getChannel();
+ lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis();
+ importance = ranking.getImportance();
+ ambient = ranking.isAmbient();
+ snoozeCriteria = ranking.getSnoozeCriteria();
+ userSentiment = ranking.getUserSentiment();
+ systemGeneratedSmartActions = ranking.getSmartActions() == null
+ ? Collections.emptyList() : ranking.getSmartActions();
+ smartReplies = ranking.getSmartReplies() == null
+ ? new CharSequence[0]
+ : ranking.getSmartReplies().toArray(new CharSequence[0]);
+ suppressedVisualEffects = ranking.getSuppressedVisualEffects();
+ suspended = ranking.isSuspended();
+ }
+
+ public void setInterruption() {
+ interruption = true;
+ }
+
+ public boolean hasInterrupted() {
+ return interruption;
+ }
+
+ public void setIsBubble(boolean bubbleable) {
+ mIsBubble = bubbleable;
+ }
+
+ public boolean isBubble() {
+ return mIsBubble;
+ }
+
+ public void setBubbleDismissed(boolean userDismissed) {
+ mUserDismissedBubble = userDismissed;
+ }
+
+ public boolean isBubbleDismissed() {
+ return mUserDismissedBubble;
+ }
+
+ /**
+ * Resets the notification entry to be re-used.
+ */
+ public void reset() {
+ if (row != null) {
+ row.reset();
+ }
+ }
+
+ public ExpandableNotificationRow getRow() {
+ return row;
+ }
+
+ //TODO: This will go away when we have a way to bind an entry to a row
+ public void setRow(ExpandableNotificationRow row) {
+ this.row = row;
+ }
+
+ @Nullable
+ public List<NotificationEntry> getChildren() {
+ if (children.size() <= 0) {
+ return null;
+ }
+
+ return children;
+ }
+
+ public void notifyFullScreenIntentLaunched() {
+ setInterruption();
+ lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
+ }
+
+ public boolean hasJustLaunchedFullScreenIntent() {
+ return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
+ }
+
+ public boolean hasJustSentRemoteInput() {
+ return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN;
+ }
+
+ public boolean hasFinishedInitialization() {
+ return initializationTime == -1
+ || SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
+ }
+
+ /**
+ * Create the icons for a notification
+ * @param context the context to create the icons with
+ * @param sbn the notification
+ * @throws InflationException Exception if required icons are not valid or specified
+ */
+ public void createIcons(Context context, StatusBarNotification sbn)
+ throws InflationException {
+ Notification n = sbn.getNotification();
+ final Icon smallIcon = n.getSmallIcon();
+ if (smallIcon == null) {
+ throw new InflationException("No small icon in notification from "
+ + sbn.getPackageName());
+ }
+
+ // Construct the icon.
+ icon = new StatusBarIconView(context,
+ sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
+ icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+
+ // Construct the expanded icon.
+ expandedIcon = new StatusBarIconView(context,
+ sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
+ expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+ final StatusBarIcon ic = new StatusBarIcon(
+ sbn.getUser(),
+ sbn.getPackageName(),
+ smallIcon,
+ n.iconLevel,
+ n.number,
+ StatusBarIconView.contentDescForNotification(context, n));
+ if (!icon.set(ic) || !expandedIcon.set(ic)) {
+ icon = null;
+ expandedIcon = null;
+ throw new InflationException("Couldn't create icon: " + ic);
+ }
+ expandedIcon.setVisibility(View.INVISIBLE);
+ expandedIcon.setOnVisibilityChangedListener(
+ newVisibility -> {
+ if (row != null) {
+ row.setIconsVisible(newVisibility != View.VISIBLE);
+ }
+ });
+ }
+
+ public void setIconTag(int key, Object tag) {
+ if (icon != null) {
+ icon.setTag(key, tag);
+ expandedIcon.setTag(key, tag);
+ }
+ }
+
+ /**
+ * Update the notification icons.
+ *
+ * @param context the context to create the icons with.
+ * @param sbn the notification to read the icon from.
+ * @throws InflationException Exception if required icons are not valid or specified
+ */
+ public void updateIcons(Context context, StatusBarNotification sbn)
+ throws InflationException {
+ if (icon != null) {
+ // Update the icon
+ Notification n = sbn.getNotification();
+ final StatusBarIcon ic = new StatusBarIcon(
+ notification.getUser(),
+ notification.getPackageName(),
+ n.getSmallIcon(),
+ n.iconLevel,
+ n.number,
+ StatusBarIconView.contentDescForNotification(context, n));
+ icon.setNotification(sbn);
+ expandedIcon.setNotification(sbn);
+ if (!icon.set(ic) || !expandedIcon.set(ic)) {
+ throw new InflationException("Couldn't update icon: " + ic);
+ }
+ }
+ }
+
+ public int getContrastedColor(Context context, boolean isLowPriority,
+ int backgroundColor) {
+ int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
+ notification.getNotification().color;
+ if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
+ return mCachedContrastColor;
+ }
+ final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor,
+ backgroundColor);
+ mCachedContrastColorIsFor = rawColor;
+ mCachedContrastColor = contrasted;
+ return mCachedContrastColor;
+ }
+
+ /**
+ * Abort all existing inflation tasks
+ */
+ public void abortTask() {
+ if (mRunningTask != null) {
+ mRunningTask.abort();
+ mRunningTask = null;
+ }
+ }
+
+ public void setInflationTask(InflationTask abortableTask) {
+ // abort any existing inflation
+ InflationTask existing = mRunningTask;
+ abortTask();
+ mRunningTask = abortableTask;
+ if (existing != null && mRunningTask != null) {
+ mRunningTask.supersedeTask(existing);
+ }
+ }
+
+ public void onInflationTaskFinished() {
+ mRunningTask = null;
+ }
+
+ @VisibleForTesting
+ public InflationTask getRunningTask() {
+ return mRunningTask;
+ }
+
+ /**
+ * Set a throwable that is used for debugging
+ *
+ * @param debugThrowable the throwable to save
+ */
+ public void setDebugThrowable(Throwable debugThrowable) {
+ mDebugThrowable = debugThrowable;
+ }
+
+ public Throwable getDebugThrowable() {
+ return mDebugThrowable;
+ }
+
+ public void onRemoteInputInserted() {
+ lastRemoteInputSent = NOT_LAUNCHED_YET;
+ remoteInputTextWhenReset = null;
+ }
+
+ public void setHasSentReply() {
+ hasSentReply = true;
+ }
+
+ public boolean isLastMessageFromReply() {
+ if (!hasSentReply) {
+ return false;
+ }
+ Bundle extras = notification.getNotification().extras;
+ CharSequence[] replyTexts = extras.getCharSequenceArray(
+ Notification.EXTRA_REMOTE_INPUT_HISTORY);
+ if (!ArrayUtils.isEmpty(replyTexts)) {
+ return true;
+ }
+ Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+ if (messages != null && messages.length > 0) {
+ Parcelable message = messages[messages.length - 1];
+ if (message instanceof Bundle) {
+ Notification.MessagingStyle.Message lastMessage =
+ Notification.MessagingStyle.Message.getMessageFromBundle(
+ (Bundle) message);
+ if (lastMessage != null) {
+ Person senderPerson = lastMessage.getSenderPerson();
+ if (senderPerson == null) {
+ return true;
+ }
+ Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
+ return Objects.equals(user, senderPerson);
+ }
+ }
+ }
+ return false;
+ }
+
+ public void setInitializationTime(long time) {
+ if (initializationTime == -1) {
+ initializationTime = time;
+ }
+ }
+
+ public void sendAccessibilityEvent(int eventType) {
+ if (row != null) {
+ row.sendAccessibilityEvent(eventType);
+ }
+ }
+
+ /**
+ * Used by NotificationMediaManager to determine... things
+ * @return {@code true} if we are a media notification
+ */
+ public boolean isMediaNotification() {
+ if (row == null) return false;
+
+ return row.isMediaRow();
+ }
+
+ /**
+ * We are a top level child if our parent is the list of notifications duh
+ * @return {@code true} if we're a top level notification
+ */
+ public boolean isTopLevelChild() {
+ return row != null && row.isTopLevelChild();
+ }
+
+ public void resetUserExpansion() {
+ if (row != null) row.resetUserExpansion();
+ }
+
+ public void freeContentViewWhenSafe(@NotificationInflater.InflationFlag int inflationFlag) {
+ if (row != null) row.freeContentViewWhenSafe(inflationFlag);
+ }
+
+ public void setAmbientPulsing(boolean pulsing) {
+ if (row != null) row.setAmbientPulsing(pulsing);
+ }
+
+ public boolean rowExists() {
+ return row != null;
+ }
+
+ public boolean isRowDismissed() {
+ return row != null && row.isDismissed();
+ }
+
+ public boolean isRowRemoved() {
+ return row != null && row.isRemoved();
+ }
+
+ /**
+ * @return {@code true} if the row is null or removed
+ */
+ public boolean isRemoved() {
+ //TODO: recycling invalidates this
+ return row == null || row.isRemoved();
+ }
+
+ /**
+ * @return {@code true} if the row is null or dismissed
+ */
+ public boolean isDismissed() {
+ //TODO: recycling
+ return row == null || row.isDismissed();
+ }
+
+ public boolean isRowPinned() {
+ return row != null && row.isPinned();
+ }
+
+ public void setRowPinned(boolean pinned) {
+ if (row != null) row.setPinned(pinned);
+ }
+
+ public boolean isRowAnimatingAway() {
+ return row != null && row.isHeadsUpAnimatingAway();
+ }
+
+ public boolean isRowHeadsUp() {
+ return row != null && row.isHeadsUp();
+ }
+
+ public void setHeadsUp(boolean shouldHeadsUp) {
+ if (row != null) row.setHeadsUp(shouldHeadsUp);
+ }
+
+ public boolean mustStayOnScreen() {
+ return row != null && row.mustStayOnScreen();
+ }
+
+ public void setHeadsUpIsVisible() {
+ if (row != null) row.setHeadsUpIsVisible();
+ }
+
+ //TODO: i'm imagining a world where this isn't just the row, but I could be rwong
+ public ExpandableNotificationRow getHeadsUpAnimationView() {
+ return row;
+ }
+
+ public void setUserLocked(boolean userLocked) {
+ if (row != null) row.setUserLocked(userLocked);
+ }
+
+ public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
+ if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion);
+ }
+
+ public void setGroupExpansionChanging(boolean changing) {
+ if (row != null) row.setGroupExpansionChanging(changing);
+ }
+
+ public void notifyHeightChanged(boolean needsAnimation) {
+ if (row != null) row.notifyHeightChanged(needsAnimation);
+ }
+
+ public void closeRemoteInput() {
+ if (row != null) row.closeRemoteInput();
+ }
+
+ public boolean areChildrenExpanded() {
+ return row != null && row.areChildrenExpanded();
+ }
+
+ public boolean keepInParent() {
+ return row != null && row.keepInParent();
+ }
+
+ //TODO: probably less confusing to say "is group fully visible"
+ public boolean isGroupNotFullyVisible() {
+ return row == null || row.isGroupNotFullyVisible();
+ }
+
+ public NotificationGuts getGuts() {
+ if (row != null) return row.getGuts();
+ return null;
+ }
+
+ public boolean hasLowPriorityStateUpdated() {
+ return row != null && row.hasLowPriorityStateUpdated();
+ }
+
+ public void removeRow() {
+ if (row != null) row.setRemoved();
+ }
+
+ public boolean isSummaryWithChildren() {
+ return row != null && row.isSummaryWithChildren();
+ }
+
+ public void setKeepInParent(boolean keep) {
+ if (row != null) row.setKeepInParent(keep);
+ }
+
+ public void onDensityOrFontScaleChanged() {
+ if (row != null) row.onDensityOrFontScaleChanged();
+ }
+
+ public boolean areGutsExposed() {
+ return row != null && row.getGuts() != null && row.getGuts().isExposed();
+ }
+
+ public boolean isChildInGroup() {
+ return parent == null;
+ }
+
+ public void setLowPriorityStateUpdated(boolean updated) {
+ if (row != null) row.setLowPriorityStateUpdated(updated);
+ }
+
+ /**
+ * @return Can the underlying notification be cleared? This can be different from whether the
+ * notification can be dismissed in case notifications are sensitive on the lockscreen.
+ * @see #canViewBeDismissed()
+ */
+ public boolean isClearable() {
+ if (notification == null || !notification.isClearable()) {
+ return false;
+ }
+ if (children.size() > 0) {
+ for (int i = 0; i < children.size(); i++) {
+ NotificationEntry child = children.get(i);
+ if (!child.isClearable()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public boolean canViewBeDismissed() {
+ if (row == null) return true;
+ return row.canViewBeDismissed();
+ }
+
+ @VisibleForTesting
+ boolean isExemptFromDndVisualSuppression() {
+ if (isNotificationBlockedByPolicy(notification.getNotification())) {
+ return false;
+ }
+
+ if ((notification.getNotification().flags
+ & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ return true;
+ }
+ if (notification.getNotification().isMediaNotification()) {
+ return true;
+ }
+ if (mIsSystemNotification != null && mIsSystemNotification) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean shouldSuppressVisualEffect(int effect) {
+ if (isExemptFromDndVisualSuppression()) {
+ return false;
+ }
+ return (suppressedVisualEffects & effect) != 0;
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_FULL_SCREEN_INTENT}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressFullScreenIntent() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_PEEK}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressPeek() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_PEEK);
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_STATUS_BAR}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressStatusBar() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_STATUS_BAR);
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_AMBIENT}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressAmbient() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_AMBIENT);
+ }
+
+ /**
+ * Returns whether {@link Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST}
+ * is set for this entry.
+ */
+ public boolean shouldSuppressNotificationList() {
+ return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_NOTIFICATION_LIST);
+ }
+
+ /**
+ * Categories that are explicitly called out on DND settings screens are always blocked, if
+ * DND has flagged them, even if they are foreground or system notifications that might
+ * otherwise visually bypass DND.
+ */
+ private static boolean isNotificationBlockedByPolicy(Notification n) {
+ return isCategory(CATEGORY_CALL, n)
+ || isCategory(CATEGORY_MESSAGE, n)
+ || isCategory(CATEGORY_ALARM, n)
+ || isCategory(CATEGORY_EVENT, n)
+ || isCategory(CATEGORY_REMINDER, n);
+ }
+
+ private static boolean isCategory(String category, Notification n) {
+ return Objects.equals(n.category, category);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 43048a2..3eec38e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -33,9 +33,9 @@
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -115,11 +115,11 @@
// notifications.
// 3. Report newly visible and no-longer visible notifications.
// 4. Keep currently visible notifications for next report.
- ArrayList<NotificationData.Entry> activeNotifications = mEntryManager
+ ArrayList<NotificationEntry> activeNotifications = mEntryManager
.getNotificationData().getActiveNotifications();
int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
- NotificationData.Entry entry = activeNotifications.get(i);
+ NotificationEntry entry = activeNotifications.get(i);
String key = entry.notification.getKey();
boolean isVisible = mListContainer.isInVisibleLocation(entry);
NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible);
@@ -167,7 +167,7 @@
entryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onEntryRemoved(
- NotificationData.Entry entry,
+ NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
if (removedByUser && visibility != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a58c7cd..9e0dd84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -86,10 +86,10 @@
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
@@ -199,7 +199,7 @@
private ExpansionLogger mLogger;
private String mLoggingKey;
private NotificationGuts mGuts;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private StatusBarNotification mStatusBarNotification;
private String mAppName;
@@ -451,7 +451,7 @@
*
* @param entry the entry this row is tied to
*/
- public void setEntry(@NonNull NotificationData.Entry entry) {
+ public void setEntry(@NonNull NotificationEntry entry) {
mEntry = entry;
mStatusBarNotification = entry.notification;
cacheIsSystemNotification();
@@ -685,7 +685,7 @@
return mStatusBarNotification;
}
- public NotificationData.Entry getEntry() {
+ public NotificationEntry getEntry() {
return mEntry;
}
@@ -1422,7 +1422,7 @@
public void performDismiss(boolean fromAccessibility) {
if (isOnlyChildInGroup()) {
- NotificationData.Entry groupSummary =
+ NotificationEntry groupSummary =
mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
if (groupSummary.isClearable()) {
// If this is the only child in the group, dismiss the group, but don't try to show
@@ -2538,7 +2538,7 @@
/**
* @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
* otherwise some state might not be updated. To request about the general clearability
- * see {@link NotificationData.Entry#isClearable()}.
+ * see {@link NotificationEntry#isClearable()}.
*/
public boolean canViewBeDismissed() {
return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
@@ -2969,7 +2969,7 @@
}
public interface OnExpandClickListener {
- void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
+ void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 02a310c..bf30cf9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -46,8 +46,8 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.TransformableView;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -1231,7 +1231,7 @@
updateAllSingleLineViews();
}
- public void onNotificationUpdated(NotificationData.Entry entry) {
+ public void onNotificationUpdated(NotificationEntry entry) {
mStatusBarNotification = entry.notification;
mOnContentViewInactiveListeners.clear();
mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
@@ -1292,7 +1292,7 @@
}
}
- private void applyRemoteInputAndSmartReply(final NotificationData.Entry entry) {
+ private void applyRemoteInputAndSmartReply(final NotificationEntry entry) {
if (mRemoteInputController == null) {
return;
}
@@ -1313,7 +1313,7 @@
@VisibleForTesting
static SmartRepliesAndActions chooseSmartRepliesAndActions(
SmartReplyConstants smartReplyConstants,
- final NotificationData.Entry entry) {
+ final NotificationEntry entry) {
boolean enableAppGeneratedSmartReplies = (smartReplyConstants.isEnabled()
&& (!smartReplyConstants.requiresTargetingP()
|| entry.targetSdk >= Build.VERSION_CODES.P));
@@ -1370,7 +1370,7 @@
smartReplies, smartActions, freeformRemoteInputActionPair != null);
}
- private void applyRemoteInput(NotificationData.Entry entry, boolean hasFreeformRemoteInput) {
+ private void applyRemoteInput(NotificationEntry entry, boolean hasFreeformRemoteInput) {
View bigContentView = mExpandedChild;
if (bigContentView != null) {
mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasFreeformRemoteInput,
@@ -1402,7 +1402,7 @@
mCachedHeadsUpRemoteInput = null;
}
- private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
+ private RemoteInputView applyRemoteInput(View view, NotificationEntry entry,
boolean hasRemoteInput, PendingIntent existingPendingIntent,
RemoteInputView cachedView, NotificationViewWrapper wrapper) {
View actionContainerCandidate = view.findViewById(
@@ -1470,7 +1470,7 @@
}
private void applySmartReplyView(SmartRepliesAndActions smartRepliesAndActions,
- NotificationData.Entry entry) {
+ NotificationEntry entry) {
if (mExpandedChild != null) {
mExpandedSmartReplyView =
applySmartReplyView(mExpandedChild, smartRepliesAndActions, entry);
@@ -1496,7 +1496,7 @@
}
private SmartReplyView applySmartReplyView(View view,
- SmartRepliesAndActions smartRepliesAndActions, NotificationData.Entry entry) {
+ SmartRepliesAndActions smartRepliesAndActions, NotificationEntry entry) {
View smartReplyContainerCandidate = view.findViewById(
com.android.internal.R.id.smart_reply_container);
if (!(smartReplyContainerCandidate instanceof LinearLayout)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index ac4e583..bd1dfb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -48,7 +48,7 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -116,7 +116,7 @@
mNotificationActivityStarter = notificationActivityStarter;
}
- public void onDensityOrFontScaleChanged(NotificationData.Entry entry) {
+ public void onDensityOrFontScaleChanged(NotificationEntry entry) {
setExposedGuts(entry.getGuts());
bindGuts(entry.getRow());
}
@@ -429,7 +429,7 @@
}
@Override
- public boolean shouldExtendLifetime(NotificationData.Entry entry) {
+ public boolean shouldExtendLifetime(NotificationEntry entry) {
return entry != null
&&(mNotificationGutsExposed != null
&& entry.getGuts() != null
@@ -438,7 +438,7 @@
}
@Override
- public void setShouldManageLifetime(NotificationData.Entry entry, boolean shouldExtend) {
+ public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
if (shouldExtend) {
mKeyToRemoveOnGutsClosed = entry.key;
if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
index 9908049..42ebfce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
@@ -37,7 +37,7 @@
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.Assert;
@@ -614,7 +614,7 @@
@Nullable InflationCallback endListener, ExpandableNotificationRow row,
boolean redactAmbient) {
Assert.isMainThread();
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
NotificationContentView privateLayout = row.getPrivateLayout();
NotificationContentView publicLayout = row.getPublicLayout();
if (runningInflations.isEmpty()) {
@@ -724,7 +724,7 @@
* @param entry the entry with the content views set
* @param inflatedFlags the flags associated with the content views that were inflated
*/
- void onAsyncInflationFinished(NotificationData.Entry entry,
+ void onAsyncInflationFinished(NotificationEntry entry,
@InflationFlag int inflatedFlags);
/**
@@ -782,7 +782,7 @@
mRedactAmbient = redactAmbient;
mRemoteViewClickHandler = remoteViewClickHandler;
mCallback = callback;
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
entry.setInflationTask(this);
}
@@ -857,7 +857,7 @@
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@InflationFlag int inflatedFlags) {
mRow.getEntry().onInflationTaskFinished();
mRow.onNotificationUpdated();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
index 1741a0b..0160c547 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
@@ -25,7 +25,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.InflationTask;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* An inflater task that asynchronously inflates a ExpandableNotificationRow
@@ -36,14 +36,14 @@
private static final boolean TRACE_ORIGIN = true;
private RowInflationFinishedListener mListener;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private boolean mCancelled;
private Throwable mInflateOrigin;
/**
* Inflates a new notificationView. This should not be called twice on this object
*/
- public void inflate(Context context, ViewGroup parent, NotificationData.Entry entry,
+ public void inflate(Context context, ViewGroup parent, NotificationEntry entry,
RowInflationFinishedListener listener) {
if (TRACE_ORIGIN) {
mInflateOrigin = new Throwable("inflate requested here");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 670908f..cbec37e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -25,7 +25,7 @@
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -358,7 +358,7 @@
mPulsing = hasPulsing;
}
- public boolean isPulsing(NotificationData.Entry entry) {
+ public boolean isPulsing(NotificationEntry entry) {
if (!mPulsing || mAmbientPulseManager == null) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 1d5b9cc..f771be0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -22,8 +22,8 @@
import android.view.ViewGroup;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -117,7 +117,7 @@
* @param entry entry to get the view parent for
* @return the view parent for entry
*/
- ViewGroup getViewParentForNotification(NotificationData.Entry entry);
+ ViewGroup getViewParentForNotification(NotificationEntry entry);
/**
* Resets the currently exposed menu view.
@@ -140,7 +140,7 @@
*
* @param entry the entry whose view's view state needs to be cleaned up (say that 5 times fast)
*/
- void cleanUpViewStateForEntry(NotificationData.Entry entry);
+ void cleanUpViewStateForEntry(NotificationEntry entry);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index 4f0831f1..9418601 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -18,7 +18,7 @@
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -49,12 +49,12 @@
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry headsUp) {
+ public void onHeadsUpPinned(NotificationEntry headsUp) {
updateView(headsUp.getRow(), false /* animate */);
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry headsUp) {
+ public void onHeadsUpUnPinned(NotificationEntry headsUp) {
updateView(headsUp.getRow(), true /* animate */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1248cbf..e4b00dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -96,13 +96,13 @@
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.FakeShadowView;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -521,7 +521,7 @@
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onEntryUpdated(NotificationData.Entry entry) {
+ public void onEntryUpdated(NotificationEntry entry) {
if (!entry.notification.isClearable()) {
// The user may have performed a dismiss action on the notification, since it's
// not clearable we should snap it back.
@@ -602,14 +602,14 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
- public void setRemoteInputActive(NotificationData.Entry entry,
+ public void setRemoteInputActive(NotificationEntry entry,
boolean remoteInputActive) {
mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
entry.notifyHeightChanged(true /* needsAnimation */);
updateFooter();
}
- public void lockScrollTo(NotificationData.Entry entry) {
+ public void lockScrollTo(NotificationEntry entry) {
NotificationStackScrollLayout.this.lockScrollTo(entry.getRow());
}
@@ -922,7 +922,7 @@
@Override
@ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
- public boolean isInVisibleLocation(NotificationData.Entry entry) {
+ public boolean isInVisibleLocation(NotificationEntry entry) {
ExpandableNotificationRow row = entry.getRow();
ExpandableViewState childViewState = row.getViewState();
@@ -1236,13 +1236,13 @@
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getTopHeadsUpPinnedHeight() {
- NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
+ NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
if (topEntry == null) {
return 0;
}
ExpandableNotificationRow row = topEntry.getRow();
if (row.isChildInGroup()) {
- final NotificationData.Entry groupSummary
+ final NotificationEntry groupSummary
= mGroupManager.getGroupSummary(row.getStatusBarNotification());
if (groupSummary != null) {
row = groupSummary.getRow();
@@ -1417,7 +1417,7 @@
&& touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
if (slidingChild instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
&& mHeadsUpManager.getTopEntry().getRow() != row
&& mGroupManager.getGroupSummary(
@@ -1551,7 +1551,7 @@
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private void snapViewIfNeeded(NotificationData.Entry entry) {
+ private void snapViewIfNeeded(NotificationEntry entry) {
ExpandableNotificationRow child = entry.getRow();
boolean animate = mIsExpanded || isPinnedHeadsUp(child);
// If the child is showing the notification menu snap to that
@@ -1561,7 +1561,7 @@
@Override
@ShadeViewRefactor(RefactorComponent.ADAPTER)
- public ViewGroup getViewParentForNotification(NotificationData.Entry entry) {
+ public ViewGroup getViewParentForNotification(NotificationEntry entry) {
return this;
}
@@ -2064,7 +2064,7 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private boolean isPulsing(NotificationData.Entry entry) {
+ private boolean isPulsing(NotificationEntry entry) {
return mAmbientState.isPulsing(entry);
}
@@ -2569,7 +2569,7 @@
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@Override
- public void cleanUpViewStateForEntry(NotificationData.Entry entry) {
+ public void cleanUpViewStateForEntry(NotificationEntry entry) {
View child = entry.getRow();
if (child == mSwipeHelper.getTranslatingParentView()) {
mSwipeHelper.clearTranslatingParentView();
@@ -2697,7 +2697,7 @@
private boolean isChildInInvisibleGroup(View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- NotificationData.Entry groupSummary =
+ NotificationEntry groupSummary =
mGroupManager.getGroupSummary(row.getStatusBarNotification());
if (groupSummary != null && groupSummary.getRow() != row) {
return row.getVisibility() == View.INVISIBLE;
@@ -4716,7 +4716,7 @@
mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
}
- public void generateHeadsUpAnimation(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
generateHeadsUpAnimation(row, isHeadsUp);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index d1e488a..876b902 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -28,7 +28,7 @@
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -143,7 +143,7 @@
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry entry) {
+ public void onHeadsUpPinned(NotificationEntry entry) {
updateTopEntry();
updateHeader(entry);
}
@@ -206,11 +206,11 @@
}
private void updateTopEntry() {
- NotificationData.Entry newEntry = null;
+ NotificationEntry newEntry = null;
if (!mIsExpanded && mHeadsUpManager.hasPinnedHeadsUp()) {
newEntry = mHeadsUpManager.getTopEntry();
}
- NotificationData.Entry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
+ NotificationEntry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
mHeadsUpStatusBarView.setEntry(newEntry);
if (newEntry != previousEntry) {
boolean animateIsolation = false;
@@ -298,7 +298,7 @@
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
updateTopEntry();
updateHeader(entry);
}
@@ -338,7 +338,7 @@
});
}
- public void updateHeader(NotificationData.Entry entry) {
+ public void updateHeader(NotificationEntry entry) {
ExpandableNotificationRow row = entry.getRow();
float headerVisibleAmount = 1.0f;
if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index f4cfd41..0fada66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -41,8 +41,8 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -72,8 +72,8 @@
private int mDisplayCutoutTouchableRegionSize;
private boolean mTrackingHeadsUp;
private HashSet<String> mSwipedOutKeys = new HashSet<>();
- private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
- private ArraySet<NotificationData.Entry> mEntriesToRemoveWhenReorderingAllowed
+ private HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
+ private ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
= new ArraySet<>();
private boolean mIsExpanded;
private int[] mTmpTwoArray = new int[2];
@@ -187,7 +187,7 @@
releaseAllImmediately();
mReleaseOnExpandFinish = false;
} else {
- for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
+ for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
if (isAlerting(entry.key)) {
// Maybe the heads-up was removed already
removeAlertEntry(entry.key);
@@ -252,7 +252,7 @@
* @param remoteInputActive True to notify active, False to notify inactive.
*/
public void setRemoteInputActive(
- @NonNull NotificationData.Entry entry, boolean remoteInputActive) {
+ @NonNull NotificationEntry entry, boolean remoteInputActive) {
HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.key);
if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
headsUpEntry.remoteInputActive = remoteInputActive;
@@ -268,7 +268,7 @@
* Sets whether an entry's menu row is exposed and therefore it should stick in the heads up
* area if it's pinned until it's hidden again.
*/
- public void setMenuShown(@NonNull NotificationData.Entry entry, boolean menuShown) {
+ public void setMenuShown(@NonNull NotificationEntry entry, boolean menuShown) {
HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key);
if (headsUpEntry instanceof HeadsUpEntryPhone && entry.isRowPinned()) {
((HeadsUpEntryPhone) headsUpEntry).setMenuShownPinned(menuShown);
@@ -315,9 +315,9 @@
return;
}
if (hasPinnedHeadsUp()) {
- NotificationData.Entry topEntry = getTopEntry();
+ NotificationEntry topEntry = getTopEntry();
if (topEntry.isChildInGroup()) {
- final NotificationData.Entry groupSummary
+ final NotificationEntry groupSummary
= mGroupManager.getGroupSummary(topEntry.notification);
if (groupSummary != null) {
topEntry = groupSummary;
@@ -374,7 +374,7 @@
@Override
public void onReorderingAllowed() {
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
- for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
+ for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (isAlerting(entry.key)) {
// Maybe the heads-up was removed already
removeAlertEntry(entry.key);
@@ -399,7 +399,7 @@
}
@Override
- protected boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) {
+ protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) {
return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
|| super.shouldHeadsUpBecomePinned(entry);
}
@@ -488,7 +488,7 @@
return super.isSticky() || mMenuShownPinned;
}
- public void setEntry(@NonNull final NotificationData.Entry entry) {
+ public void setEntry(@NonNull final NotificationEntry entry) {
Runnable removeHeadsUpRunnable = () -> {
if (!mVisualStabilityManager.isReorderingAllowed()) {
mEntriesToRemoveWhenReorderingAllowed.add(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 9c1c71a..dd200da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -21,7 +21,7 @@
import android.view.ViewConfiguration;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -83,7 +83,7 @@
} else if (child == null && !mCallback.isExpanded()) {
// We might touch above the visible heads up child, but then we still would
// like to capture it.
- NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
+ NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
if (topEntry != null && topEntry.isRowPinned()) {
mPickedChild = topEntry.getRow();
mTouchingHeadsUpView = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
index 927228e..925a19d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -22,7 +22,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
public class KeyguardEnvironmentImpl implements KeyguardEnvironment {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index af3257a..d364356 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -31,9 +31,9 @@
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
@@ -108,7 +108,7 @@
* @param entry notification to check
* @return true if the entry was transferred to and should inflate + alert
*/
- public boolean isAlertTransferPending(@NonNull Entry entry) {
+ public boolean isAlertTransferPending(@NonNull NotificationEntry entry) {
PendingAlertInfo alertInfo = mPendingAlerts.get(entry.key);
return alertInfo != null && alertInfo.isStillValid();
}
@@ -172,16 +172,16 @@
};
@Override
- public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
+ public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
onAlertStateChanged(entry, isAmbient, mAmbientPulseManager);
}
@Override
- public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
}
- private void onAlertStateChanged(Entry entry, boolean isAlerting,
+ private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting,
AlertingNotificationManager alertManager) {
if (isAlerting && mGroupManager.isSummaryOfSuppressedGroup(entry.notification)) {
handleSuppressedSummaryAlerted(entry, alertManager);
@@ -193,7 +193,7 @@
// Called when a new notification has been posted but is not inflated yet. We use this to
// see as early as we can if we need to abort a transfer.
@Override
- public void onPendingEntryAdded(Entry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
String groupKey = mGroupManager.getGroupKey(entry.notification);
GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
if (groupAlertEntry != null) {
@@ -204,7 +204,7 @@
// Called when the entry's reinflation has finished. If there is an alert pending, we
// then show the alert.
@Override
- public void onEntryReinflated(Entry entry) {
+ public void onEntryReinflated(NotificationEntry entry) {
PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
if (alertInfo != null) {
if (alertInfo.isStillValid()) {
@@ -219,7 +219,7 @@
@Override
public void onEntryRemoved(
- @Nullable Entry entry,
+ @Nullable NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
// Removes any alerts pending on this entry. Note that this will not stop any inflation
@@ -241,8 +241,8 @@
return 0;
}
int number = 0;
- Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
- for (Entry entry : values) {
+ Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
+ for (NotificationEntry entry : values) {
if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
number++;
}
@@ -260,8 +260,8 @@
if (mEntryManager == null) {
return false;
}
- Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
- for (Entry entry : values) {
+ Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
+ for (NotificationEntry entry : values) {
if (isPendingNotificationInGroup(entry, group)) {
return true;
}
@@ -276,7 +276,7 @@
* @param group group to check
* @return true if the notification will add to the group, false o/w
*/
- private boolean isPendingNotificationInGroup(@NonNull Entry entry,
+ private boolean isPendingNotificationInGroup(@NonNull NotificationEntry entry,
@NonNull NotificationGroup group) {
String groupKey = mGroupManager.getGroupKey(group.summary.notification);
return mGroupManager.isGroupChild(entry.notification)
@@ -293,7 +293,7 @@
* @param summary the summary that is suppressed and alerting
* @param alertManager the alert manager that manages the alerting summary
*/
- private void handleSuppressedSummaryAlerted(@NonNull Entry summary,
+ private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary,
@NonNull AlertingNotificationManager alertManager) {
StatusBarNotification sbn = summary.notification;
GroupAlertEntry groupAlertEntry =
@@ -309,7 +309,7 @@
return;
}
- Entry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
+ NotificationEntry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
if (child != null) {
if (child.getRow().keepInParent()
|| child.isRowRemoved()
@@ -333,7 +333,7 @@
* @param toEntry entry to transfer to
* @param alertManager alert manager for the alert type
*/
- private void transferAlertState(@NonNull Entry fromEntry, @NonNull Entry toEntry,
+ private void transferAlertState(@NonNull NotificationEntry fromEntry, @NonNull NotificationEntry toEntry,
@NonNull AlertingNotificationManager alertManager) {
alertManager.removeNotification(fromEntry.key, true /* releaseImmediately */);
alertNotificationWhenPossible(toEntry, alertManager);
@@ -353,13 +353,13 @@
private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
< ALERT_TRANSFER_TIMEOUT) {
- Entry summary = groupAlertEntry.mGroup.summary;
+ NotificationEntry summary = groupAlertEntry.mGroup.summary;
AlertingNotificationManager alertManager = getActiveAlertManager();
if (!onlySummaryAlerts(summary)) {
return;
}
- ArrayList<Entry> children = mGroupManager.getLogicalChildren(summary.notification);
+ ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.notification);
int numChildren = children.size();
int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup);
numChildren += numPendingChildren;
@@ -368,7 +368,7 @@
}
boolean releasedChild = false;
for (int i = 0; i < children.size(); i++) {
- Entry entry = children.get(i);
+ NotificationEntry entry = children.get(i);
if (onlySummaryAlerts(entry) && alertManager.isAlerting(entry.key)) {
releasedChild = true;
alertManager.removeNotification(entry.key, true /* releaseImmediately */);
@@ -399,7 +399,7 @@
* @param entry entry to show
* @param alertManager alert manager for the alert type
*/
- private void alertNotificationWhenPossible(@NonNull Entry entry,
+ private void alertNotificationWhenPossible(@NonNull NotificationEntry entry,
@NonNull AlertingNotificationManager alertManager) {
@InflationFlag int contentFlag = alertManager.getContentFlag();
if (!entry.getRow().isInflationFlagSet(contentFlag)) {
@@ -419,7 +419,7 @@
return mIsDozing ? mAmbientPulseManager : mHeadsUpManager;
}
- private boolean onlySummaryAlerts(Entry entry) {
+ private boolean onlySummaryAlerts(NotificationEntry entry) {
return entry.notification.getNotification().getGroupAlertBehavior()
== Notification.GROUP_ALERT_SUMMARY;
}
@@ -439,7 +439,7 @@
* the transfer is still valid if the notification is updated.
*/
final StatusBarNotification mOriginalNotification;
- final Entry mEntry;
+ final NotificationEntry mEntry;
/**
* The notification is still pending inflation but we've decided that we no longer need
@@ -450,7 +450,7 @@
*/
boolean mAbortOnInflation;
- PendingAlertInfo(Entry entry, AlertingNotificationManager alertManager) {
+ PendingAlertInfo(NotificationEntry entry, AlertingNotificationManager alertManager) {
mOriginalNotification = entry.notification;
mEntry = entry;
mAlertManager = alertManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 3c1c076..bb9e418 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -27,7 +27,7 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -97,7 +97,7 @@
}
}
- public void onEntryRemoved(NotificationData.Entry removed) {
+ public void onEntryRemoved(NotificationEntry removed) {
onEntryRemovedInternal(removed, removed.notification);
mIsolatedEntries.remove(removed.key);
}
@@ -109,7 +109,7 @@
* @param sbn the notification the entry has, which doesn't need to be the same as it's internal
* notification
*/
- private void onEntryRemovedInternal(NotificationData.Entry removed,
+ private void onEntryRemovedInternal(NotificationEntry removed,
final StatusBarNotification sbn) {
String groupKey = getGroupKey(sbn);
final NotificationGroup group = mGroupMap.get(groupKey);
@@ -136,7 +136,7 @@
}
}
- public void onEntryAdded(final NotificationData.Entry added) {
+ public void onEntryAdded(final NotificationEntry added) {
if (added.isRowRemoved()) {
added.setDebugThrowable(new Throwable());
}
@@ -152,7 +152,7 @@
}
}
if (isGroupChild) {
- NotificationData.Entry existing = group.children.get(added.key);
+ NotificationEntry existing = group.children.get(added.key);
if (existing != null && existing != added) {
Throwable existingThrowable = existing.getDebugThrowable();
Log.wtf(TAG, "Inconsistent entries found with the same key " + added.key
@@ -169,9 +169,9 @@
group.expanded = added.areChildrenExpanded();
updateSuppression(group);
if (!group.children.isEmpty()) {
- ArrayList<NotificationData.Entry> childrenCopy
+ ArrayList<NotificationEntry> childrenCopy
= new ArrayList<>(group.children.values());
- for (NotificationData.Entry child : childrenCopy) {
+ for (NotificationEntry child : childrenCopy) {
onEntryBecomingChild(child);
}
for (OnGroupChangeListener listener : mListeners) {
@@ -181,7 +181,7 @@
}
}
- private void onEntryBecomingChild(NotificationData.Entry entry) {
+ private void onEntryBecomingChild(NotificationEntry entry) {
if (shouldIsolate(entry)) {
isolateNotification(entry);
}
@@ -221,7 +221,7 @@
return count;
}
- private NotificationData.Entry getIsolatedChild(String groupKey) {
+ private NotificationEntry getIsolatedChild(String groupKey) {
for (StatusBarNotification sbn : mIsolatedEntries.values()) {
if (sbn.getGroupKey().equals(groupKey) && isIsolated(sbn)) {
return mGroupMap.get(sbn.getKey()).summary;
@@ -230,7 +230,7 @@
return null;
}
- public void onEntryUpdated(NotificationData.Entry entry,
+ public void onEntryUpdated(NotificationEntry entry,
StatusBarNotification oldNotification) {
String oldKey = oldNotification.getGroupKey();
String newKey = entry.notification.getGroupKey();
@@ -267,7 +267,7 @@
if (!isOnlyChild(sbn)) {
return false;
}
- NotificationData.Entry logicalGroupSummary = getLogicalGroupSummary(sbn);
+ NotificationEntry logicalGroupSummary = getLogicalGroupSummary(sbn);
return logicalGroupSummary != null
&& !logicalGroupSummary.notification.equals(sbn);
}
@@ -343,7 +343,7 @@
* Get the summary of a specified status bar notification. For isolated notification this return
* itself.
*/
- public NotificationData.Entry getGroupSummary(StatusBarNotification sbn) {
+ public NotificationEntry getGroupSummary(StatusBarNotification sbn) {
return getGroupSummary(getGroupKey(sbn));
}
@@ -352,12 +352,12 @@
* but the logical summary, i.e when a child is isolated, it still returns the summary as if
* it wasn't isolated.
*/
- public NotificationData.Entry getLogicalGroupSummary(StatusBarNotification sbn) {
+ public NotificationEntry getLogicalGroupSummary(StatusBarNotification sbn) {
return getGroupSummary(sbn.getGroupKey());
}
@Nullable
- private NotificationData.Entry getGroupSummary(String groupKey) {
+ private NotificationEntry getGroupSummary(String groupKey) {
NotificationGroup group = mGroupMap.get(groupKey);
//TODO: see if this can become an Entry
return group == null ? null
@@ -371,13 +371,13 @@
* @param summary summary of a group
* @return list of the children
*/
- public ArrayList<NotificationData.Entry> getLogicalChildren(StatusBarNotification summary) {
+ public ArrayList<NotificationEntry> getLogicalChildren(StatusBarNotification summary) {
NotificationGroup group = mGroupMap.get(summary.getGroupKey());
if (group == null) {
return null;
}
- ArrayList<NotificationData.Entry> children = new ArrayList<>(group.children.values());
- NotificationData.Entry isolatedChild = getIsolatedChild(summary.getGroupKey());
+ ArrayList<NotificationEntry> children = new ArrayList<>(group.children.values());
+ NotificationEntry isolatedChild = getIsolatedChild(summary.getGroupKey());
if (isolatedChild != null) {
children.add(isolatedChild);
}
@@ -443,24 +443,24 @@
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry entry) {
+ public void onHeadsUpPinned(NotificationEntry entry) {
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
}
@Override
- public void onAmbientStateChanged(NotificationData.Entry entry, boolean isAmbient) {
+ public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
onAlertStateChanged(entry, isAmbient);
}
@Override
- public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
onAlertStateChanged(entry, isHeadsUp);
}
- private void onAlertStateChanged(NotificationData.Entry entry, boolean isAlerting) {
+ private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting) {
if (isAlerting) {
if (shouldIsolate(entry)) {
isolateNotification(entry);
@@ -479,7 +479,7 @@
* @return true if the entry should be isolated
*/
- private boolean shouldIsolate(NotificationData.Entry entry) {
+ private boolean shouldIsolate(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
@@ -499,7 +499,7 @@
*
* @param entry the notification to isolate
*/
- private void isolateNotification(NotificationData.Entry entry) {
+ private void isolateNotification(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
// We will be isolated now, so lets update the groups
@@ -523,7 +523,7 @@
*
* @param entry the notification to un-isolate
*/
- private void stopIsolatingNotification(NotificationData.Entry entry) {
+ private void stopIsolatingNotification(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
if (mIsolatedEntries.containsKey(sbn.getKey())) {
// not isolated anymore, we need to update the groups
@@ -564,8 +564,8 @@
}
public static class NotificationGroup {
- public final HashMap<String, NotificationData.Entry> children = new HashMap<>();
- public NotificationData.Entry summary;
+ public final HashMap<String, NotificationEntry> children = new HashMap<>();
+ public NotificationEntry summary;
public boolean expanded;
/**
* Is this notification group suppressed, i.e its summary is hidden
@@ -580,7 +580,7 @@
? Log.getStackTraceString(summary.getDebugThrowable())
: "");
result += "\n children size: " + children.size();
- for (NotificationData.Entry child : children.values()) {
+ for (NotificationEntry child : children.values()) {
result += "\n " + child.notification
+ (child.getDebugThrowable() != null
? Log.getStackTraceString(child.getDebugThrowable())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 056c8a7..1fb5484 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -23,9 +23,9 @@
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.tuner.TunerService;
@@ -182,7 +182,7 @@
return mStatusBar.getStatusBarHeight();
}
- protected boolean shouldShowNotificationIcon(NotificationData.Entry entry,
+ protected boolean shouldShowNotificationIcon(NotificationEntry entry,
boolean showAmbient, boolean showLowPriority, boolean hideDismissed,
boolean hideRepliedMessages) {
if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
@@ -247,7 +247,7 @@
* @param hideDismissed should dismissed icons be hidden
* @param hideRepliedMessages should messages that have been replied to be hidden
*/
- private void updateIconsForLayout(Function<NotificationData.Entry, StatusBarIconView> function,
+ private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority,
boolean hideDismissed, boolean hideRepliedMessages) {
ArrayList<StatusBarIconView> toShow = new ArrayList<>(
@@ -257,7 +257,7 @@
for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
View view = mNotificationScrollLayout.getChildAt(i);
if (view instanceof ExpandableNotificationRow) {
- NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
+ NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed,
hideRepliedMessages)) {
toShow.add(function.apply(ent));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 16576ad..d873b0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -76,9 +76,9 @@
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.AnimatableProperty;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -2489,12 +2489,12 @@
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry entry) {
+ public void onHeadsUpPinned(NotificationEntry entry) {
mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(), true);
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
// When we're unpinning the notification via active edge they remain heads-upped,
// we need to make sure that an animation happens in this case, otherwise the notification
@@ -2507,7 +2507,7 @@
}
@Override
- public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp);
}
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 977e336..d3aa5ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -192,12 +192,11 @@
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationClicker;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -489,7 +488,7 @@
private Runnable mLaunchTransitionEndRunnable;
protected boolean mLaunchTransitionFadingAway;
- private NotificationData.Entry mDraggedDownEntry;
+ private NotificationEntry mDraggedDownEntry;
private boolean mLaunchCameraOnScreenTurningOn;
private boolean mLaunchCameraOnFinishedGoingToSleep;
private int mLastCameraLaunchSource;
@@ -1510,21 +1509,21 @@
}
@Override
- public void onHeadsUpPinned(NotificationData.Entry entry) {
+ public void onHeadsUpPinned(NotificationEntry entry) {
dismissVolumeDialog();
}
@Override
- public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+ public void onHeadsUpUnPinned(NotificationEntry entry) {
}
@Override
- public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
+ public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
mEntryManager.updateNotificationRanking(null /* rankingMap */);
}
@Override
- public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
+ public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
mEntryManager.updateNotificationRanking(null);
if (isAmbient) {
mDozeServiceHost.fireNotificationPulse();
@@ -2551,11 +2550,11 @@
};
public void resetUserExpandedStates() {
- ArrayList<Entry> activeNotifications = mEntryManager.getNotificationData()
+ ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
.getActiveNotifications();
final int notificationCount = activeNotifications.size();
for (int i = 0; i < notificationCount; i++) {
- NotificationData.Entry entry = activeNotifications.get(i);
+ NotificationEntry entry = activeNotifications.get(i);
entry.resetUserExpansion();
}
}
@@ -3506,7 +3505,7 @@
int userId = mLockscreenUserManager.getCurrentUserId();
ExpandableNotificationRow row = null;
- NotificationData.Entry entry = null;
+ NotificationEntry entry = null;
if (expandView instanceof ExpandableNotificationRow) {
entry = ((ExpandableNotificationRow) expandView).getEntry();
entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
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 8d1b911..4f61009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -60,10 +60,10 @@
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -131,7 +131,7 @@
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onPendingEntryAdded(NotificationData.Entry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
handleFullScreenIntent(entry);
}
});
@@ -267,7 +267,7 @@
}
}
Intent fillInIntent = null;
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
CharSequence remoteInputText = null;
if (!TextUtils.isEmpty(entry.remoteInputText)) {
remoteInputText = entry.remoteInputText;
@@ -345,7 +345,7 @@
}, null, false /* afterKeyguardGone */);
}
- private void handleFullScreenIntent(NotificationData.Entry entry) {
+ private void handleFullScreenIntent(NotificationEntry entry) {
boolean isHeadsUped = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
if (!isHeadsUped && entry.notification.getNotification().fullScreenIntent != null) {
if (shouldSuppressFullScreenIntent(entry)) {
@@ -413,7 +413,7 @@
|| !mActivityLaunchAnimator.isAnimationPending();
}
- private boolean shouldSuppressFullScreenIntent(NotificationData.Entry entry) {
+ private boolean shouldSuppressFullScreenIntent(NotificationEntry entry) {
if (mPresenter.isDeviceInVrMode()) {
return true;
}
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 fb3157a..16c8e62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -60,12 +60,12 @@
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationRowBinder;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -183,19 +183,19 @@
Dependency.get(InitController.class).addPostInitTask(() -> {
NotificationEntryListener notificationEntryListener = new NotificationEntryListener() {
@Override
- public void onNotificationAdded(Entry entry) {
+ public void onNotificationAdded(NotificationEntry entry) {
// Recalculate the position of the sliding windows and the titles.
mShadeController.updateAreThereNotifications();
}
@Override
- public void onEntryUpdated(Entry entry) {
+ public void onEntryUpdated(NotificationEntry entry) {
mShadeController.updateAreThereNotifications();
}
@Override
public void onEntryRemoved(
- @Nullable Entry entry,
+ @Nullable NotificationEntry entry,
NotificationVisibility visibility,
boolean removedByUser) {
StatusBarNotificationPresenter.this.onNotificationRemoved(
@@ -258,10 +258,10 @@
}
private void updateNotificationOnUiModeChanged() {
- ArrayList<Entry> userNotifications
+ ArrayList<NotificationEntry> userNotifications
= mEntryManager.getNotificationData().getNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
- Entry entry = userNotifications.get(i);
+ NotificationEntry entry = userNotifications.get(i);
ExpandableNotificationRow row = entry.getRow();
if (row != null) {
row.onUiModeChanged();
@@ -323,7 +323,7 @@
return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
}
- public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
+ public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
if (mShadeController.isDozing()) {
return false;
}
@@ -381,7 +381,7 @@
}
@Override
- public void onBindRow(Entry entry, PackageManager pmUser,
+ public void onBindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row) {
row.setAboveShelfChangedListener(mAboveShelfObserver);
row.setSecureStateProvider(mUnlockMethodCache::canSkipBouncer);
@@ -439,7 +439,7 @@
}
@Override
- public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
+ public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) {
mShadeController.goToLockedShade(clickedEntry.getRow());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index a02c9d5..fd3f680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -30,7 +30,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.statusbar.AlertingNotificationManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import java.io.FileDescriptor;
@@ -108,11 +108,11 @@
}
}
- protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationData.Entry entry) {
+ protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationEntry entry) {
return hasFullScreenIntent(entry);
}
- protected boolean hasFullScreenIntent(@NonNull NotificationData.Entry entry) {
+ protected boolean hasFullScreenIntent(@NonNull NotificationEntry entry) {
return entry.notification.getNotification().fullScreenIntent != null;
}
@@ -121,7 +121,7 @@
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setEntryPinned: " + isPinned);
}
- NotificationData.Entry entry = headsUpEntry.mEntry;
+ NotificationEntry entry = headsUpEntry.mEntry;
if (entry.isRowPinned() != isPinned) {
entry.setRowPinned(isPinned);
updatePinnedMode();
@@ -141,7 +141,7 @@
@Override
protected void onAlertEntryAdded(AlertEntry alertEntry) {
- NotificationData.Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
entry.setHeadsUp(true);
setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry));
for (OnHeadsUpChangedListener listener : mListeners) {
@@ -151,7 +151,7 @@
@Override
protected void onAlertEntryRemoved(AlertEntry alertEntry) {
- NotificationData.Entry entry = alertEntry.mEntry;
+ NotificationEntry entry = alertEntry.mEntry;
entry.setHeadsUp(false);
setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */);
for (OnHeadsUpChangedListener listener : mListeners) {
@@ -222,7 +222,7 @@
* Returns the top Heads Up Notification, which appears to show at first.
*/
@Nullable
- public NotificationData.Entry getTopEntry() {
+ public NotificationEntry getTopEntry() {
HeadsUpEntry topEntry = getTopHeadsUpEntry();
return (topEntry != null) ? topEntry.mEntry : null;
}
@@ -323,7 +323,7 @@
* @return -1 if the first argument should be ranked higher than the second, 1 if the second
* one should be ranked higher and 0 if they are equal.
*/
- public int compare(@NonNull NotificationData.Entry a, @NonNull NotificationData.Entry b) {
+ public int compare(@NonNull NotificationEntry a, @NonNull NotificationEntry b) {
AlertEntry aEntry = getHeadsUpEntry(a.key);
AlertEntry bEntry = getHeadsUpEntry(b.key);
if (aEntry == null || bEntry == null) {
@@ -336,7 +336,7 @@
* Set an entry to be expanded and therefore stick in the heads up area if it's pinned
* until it's collapsed again.
*/
- public void setExpanded(@NonNull NotificationData.Entry entry, boolean expanded) {
+ public void setExpanded(@NonNull NotificationEntry entry, boolean expanded) {
HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key);
if (headsUpEntry != null && entry.isRowPinned()) {
headsUpEntry.setExpanded(expanded);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
index 7ad547a..438226a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
@@ -16,8 +16,7 @@
package com.android.systemui.statusbar.policy;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* A listener to heads up changes
@@ -33,12 +32,12 @@
/**
* A notification was just pinned to the top.
*/
- default void onHeadsUpPinned(NotificationData.Entry entry) {}
+ default void onHeadsUpPinned(NotificationEntry entry) {}
/**
* A notification was just unpinned from the top.
*/
- default void onHeadsUpUnPinned(NotificationData.Entry entry) {}
+ default void onHeadsUpUnPinned(NotificationEntry entry) {}
/**
* A notification just became a heads up or turned back to its normal state.
@@ -46,5 +45,5 @@
* @param entry the entry of the changed notification
* @param isHeadsUp whether the notification is now a headsUp notification
*/
- default void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {}
+ default void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 866015e..dfb02cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -56,7 +56,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -83,7 +83,7 @@
private RemoteInputController mController;
private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private boolean mRemoved;
@@ -180,7 +180,7 @@
}
public static RemoteInputView inflate(Context context, ViewGroup root,
- NotificationData.Entry entry,
+ NotificationEntry entry,
RemoteInputController controller) {
RemoteInputView v = (RemoteInputView)
LayoutInflater.from(context).inflate(R.layout.remote_input, root, false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index f85d803..5e5fc42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -36,8 +36,8 @@
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import java.text.BreakIterator;
@@ -194,7 +194,7 @@
*/
public void addRepliesFromRemoteInput(
SmartReplies smartReplies,
- SmartReplyController smartReplyController, NotificationData.Entry entry) {
+ SmartReplyController smartReplyController, NotificationEntry entry) {
if (smartReplies.remoteInput != null && smartReplies.pendingIntent != null) {
if (smartReplies.choices != null) {
for (int i = 0; i < smartReplies.choices.length; ++i) {
@@ -212,7 +212,7 @@
* notification are shown.
*/
public void addSmartActions(SmartActions smartActions,
- SmartReplyController smartReplyController, NotificationData.Entry entry,
+ SmartReplyController smartReplyController, NotificationEntry entry,
HeadsUpManager headsUpManager) {
int numSmartActions = smartActions.actions.size();
for (int n = 0; n < numSmartActions; n++) {
@@ -235,7 +235,7 @@
@VisibleForTesting
Button inflateReplyButton(Context context, ViewGroup root, int replyIndex,
SmartReplies smartReplies, SmartReplyController smartReplyController,
- NotificationData.Entry entry) {
+ NotificationEntry entry) {
Button b = (Button) LayoutInflater.from(context).inflate(
R.layout.smart_reply_button, root, false);
CharSequence choice = smartReplies.choices[replyIndex];
@@ -289,7 +289,7 @@
@VisibleForTesting
Button inflateActionButton(Context context, ViewGroup root, int actionIndex,
SmartActions smartActions, SmartReplyController smartReplyController,
- NotificationData.Entry entry, HeadsUpManager headsUpManager) {
+ NotificationEntry entry, HeadsUpManager headsUpManager) {
Notification.Action action = smartActions.actions.get(actionIndex);
Button button = (Button) LayoutInflater.from(context).inflate(
R.layout.smart_action_button, root, false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index f8912bc..9400d6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -36,9 +36,9 @@
import android.widget.RemoteViews;
import com.android.internal.messages.nano.SystemMessageProto;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Before;
import org.junit.Test;
@@ -391,18 +391,18 @@
}
private void entryRemoved(StatusBarNotification notification) {
- mEntryListener.onEntryRemoved(new NotificationData.Entry(notification),
+ mEntryListener.onEntryRemoved(new NotificationEntry(notification),
null, false);
}
private void entryAdded(StatusBarNotification notification, int importance) {
- NotificationData.Entry entry = new NotificationData.Entry(notification);
+ NotificationEntry entry = new NotificationEntry(notification);
entry.importance = importance;
mEntryListener.onPendingEntryAdded(entry);
}
private void entryUpdated(StatusBarNotification notification, int importance) {
- NotificationData.Entry entry = new NotificationData.Entry(notification);
+ NotificationEntry entry = new NotificationEntry(notification);
entry.importance = importance;
mEntryListener.onEntryUpdated(entry);
}
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 31df4a3..21d3652 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -33,9 +33,9 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 9d0556f..f8957b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -36,7 +36,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -67,7 +67,7 @@
private AlertingNotificationManager mAlertingNotificationManager;
- protected NotificationData.Entry mEntry;
+ protected NotificationEntry mEntry;
protected Handler mTestHandler;
private StatusBarNotification mSbn;
protected boolean mTimedOut = false;
@@ -119,7 +119,7 @@
public void setUp() {
mTestHandler = Handler.createAsync(Looper.myLooper());
mSbn = createNewNotification(0 /* id */);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationEntry(mSbn);
mEntry.setRow(mRow);
mAlertingNotificationManager = createAlertingNotificationManager();
@@ -170,7 +170,7 @@
public void testReleaseAllImmediately() {
for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
StatusBarNotification sbn = createNewNotification(i);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.setRow(mRow);
mAlertingNotificationManager.showNotification(entry);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 65c04fe..c880172 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -31,8 +31,9 @@
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Before;
import org.junit.Test;
@@ -85,7 +86,7 @@
@Test
public void testNotificationUpdateCallsUpdateNotification() {
- when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationData.Entry(mSbn));
+ when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationEntry(mSbn));
mListener.onNotificationPosted(mSbn, mRanking);
TestableLooper.get(this).processAllMessages();
verify(mEntryManager).updateNotification(mSbn, mRanking);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index f168a49..d7ca5b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar;
-import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED;
import static android.content.Intent.ACTION_USER_SWITCHED;
import static junit.framework.Assert.assertFalse;
@@ -42,8 +41,8 @@
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 150dcb9..c159516 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -24,8 +24,8 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender;
import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender;
import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -60,7 +60,7 @@
private TestableNotificationRemoteInputManager mRemoteInputManager;
private StatusBarNotification mSbn;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private RemoteInputHistoryExtender mRemoteInputHistoryExtender;
private SmartReplyHistoryExtender mSmartReplyHistoryExtender;
private RemoteInputActiveExtender mRemoteInputActiveExtender;
@@ -75,7 +75,7 @@
Handler.createAsync(Looper.myLooper()));
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
0, new Notification(), UserHandle.CURRENT, null, 0);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationEntry(mSbn);
mEntry.setRow(mRow);
mRemoteInputManager.setUpWithPresenterForTest(mCallback,
@@ -170,7 +170,7 @@
// Setup a notification entry with 1 remote input.
StatusBarNotification newSbn =
mRemoteInputManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false);
- NotificationData.Entry entry = new NotificationData.Entry(newSbn);
+ NotificationEntry entry = new NotificationEntry(newSbn);
// Try rebuilding to add another reply.
newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(entry, "Reply 2", true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index fb5e875..529da82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -32,7 +32,7 @@
import android.widget.RemoteViews;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationInflaterTest;
@@ -238,7 +238,7 @@
mUser,
null /* overrideGroupKey */,
System.currentTimeMillis());
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.setRow(row);
entry.createIcons(mContext, sbn);
entry.channel = new NotificationChannel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index e84e0f3..bf91305 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -38,10 +38,10 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -102,9 +102,9 @@
mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
}
- private NotificationData.Entry createEntry() throws Exception {
+ private NotificationEntry createEntry() throws Exception {
ExpandableNotificationRow row = mHelper.createRow();
- NotificationData.Entry entry = new NotificationData.Entry(row.getStatusBarNotification());
+ NotificationEntry entry = new NotificationEntry(row.getStatusBarNotification());
entry.setRow(row);
return entry;
}
@@ -113,9 +113,9 @@
public void testNotificationsBecomingBundled() throws Exception {
// Tests 3 top level notifications becoming a single bundled notification with |entry0| as
// the summary.
- NotificationData.Entry entry0 = createEntry();
- NotificationData.Entry entry1 = createEntry();
- NotificationData.Entry entry2 = createEntry();
+ NotificationEntry entry0 = createEntry();
+ NotificationEntry entry1 = createEntry();
+ NotificationEntry entry2 = createEntry();
// Set up the prior state to look like three top level notifications.
mListContainer.addContainerView(entry0.getRow());
@@ -142,9 +142,9 @@
@Test
public void testNotificationsBecomingUnbundled() throws Exception {
// Tests a bundled notification becoming three top level notifications.
- NotificationData.Entry entry0 = createEntry();
- NotificationData.Entry entry1 = createEntry();
- NotificationData.Entry entry2 = createEntry();
+ NotificationEntry entry0 = createEntry();
+ NotificationEntry entry1 = createEntry();
+ NotificationEntry entry2 = createEntry();
entry0.getRow().addChildNotification(entry1.getRow());
entry0.getRow().addChildNotification(entry2.getRow());
@@ -173,8 +173,8 @@
@Test
public void testNotificationsBecomingSuppressed() throws Exception {
// Tests two top level notifications becoming a suppressed summary and a child.
- NotificationData.Entry entry0 = createEntry();
- NotificationData.Entry entry1 = createEntry();
+ NotificationEntry entry0 = createEntry();
+ NotificationEntry entry1 = createEntry();
entry0.getRow().addChildNotification(entry1.getRow());
// Set up the prior state to look like a top level notification.
@@ -199,7 +199,7 @@
@Test
public void testUpdateNotificationViews_appOps() throws Exception {
- NotificationData.Entry entry0 = createEntry();
+ NotificationEntry entry0 = createEntry();
entry0.setRow(spy(entry0.getRow()));
when(mNotificationData.getActiveNotifications()).thenReturn(
Lists.newArrayList(entry0));
@@ -264,7 +264,7 @@
public void setMaxDisplayedNotifications(int maxNotifications) {}
@Override
- public ViewGroup getViewParentForNotification(NotificationData.Entry entry) {
+ public ViewGroup getViewParentForNotification(NotificationEntry entry) {
return null;
}
@@ -280,10 +280,10 @@
}
@Override
- public void cleanUpViewStateForEntry(Entry entry) { }
+ public void cleanUpViewStateForEntry(NotificationEntry entry) { }
@Override
- public boolean isInVisibleLocation(Entry entry) {
+ public boolean isInVisibleLocation(NotificationEntry entry) {
return true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index e7a1f05..6cca434 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -36,8 +36,8 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.Before;
@@ -58,7 +58,7 @@
private static final int TEST_ACTION_COUNT = 3;
private Notification mNotification;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private SmartReplyController mSmartReplyController;
private NotificationRemoteInputManager mRemoteInputManager;
@@ -92,7 +92,7 @@
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
0, mNotification, new UserHandle(ActivityManager.getCurrentUser()), null, 0);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationEntry(mSbn);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 6197341..4d22536 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -65,7 +65,8 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
@@ -123,7 +124,7 @@
@Mock private RowInflaterTask mAsyncInflationTask;
@Mock private NotificationRowBinder mMockedRowBinder;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private StatusBarNotification mSbn;
private TestableNotificationEntryManager mEntryManager;
private CountDownLatch mCountDownLatch;
@@ -137,7 +138,7 @@
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
super.onAsyncInflationFinished(entry, inflatedFlags);
@@ -222,7 +223,7 @@
.setContentText("Text");
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
0, n.build(), new UserHandle(ActivityManager.getCurrentUser()), null, 0);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationEntry(mSbn);
mEntry.expandedIcon = mock(StatusBarIconView.class);
mEntryManager = new TestableNotificationEntryManager(mContext);
@@ -259,10 +260,10 @@
verify(mEntryListener, never()).onInflationError(any(), any());
// Row inflation:
- ArgumentCaptor<NotificationData.Entry> entryCaptor = ArgumentCaptor.forClass(
- NotificationData.Entry.class);
+ ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass(
+ NotificationEntry.class);
verify(mBindCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any());
- NotificationData.Entry entry = entryCaptor.getValue();
+ NotificationEntry entry = entryCaptor.getValue();
verify(mRemoteInputManager).bindRow(entry.getRow());
// Row content inflation:
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index da8bc01d..387475f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -40,6 +40,8 @@
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -191,12 +193,12 @@
// test should filter out hidden notifications:
// hidden
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
entry.suspended = true;
assertTrue(mNotificationFilter.shouldFilterOut(entry));
// not hidden
- entry = new NotificationData.Entry(mMockStatusBarNotification);
+ entry = new NotificationEntry(mMockStatusBarNotification);
entry.suspended = false;
assertFalse(mNotificationFilter.shouldFilterOut(entry));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index 6fbd8c7..813fc9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -29,6 +29,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import org.junit.Before;
@@ -44,13 +45,13 @@
private VisualStabilityManager.Callback mCallback = mock(VisualStabilityManager.Callback.class);
private VisibilityLocationProvider mLocationProvider = mock(VisibilityLocationProvider.class);
private ExpandableNotificationRow mRow = mock(ExpandableNotificationRow.class);
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
@Before
public void setUp() {
mVisualStabilityManager.setUpWithPresenter(mock(NotificationPresenter.class));
mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider);
- mEntry = new NotificationData.Entry(mock(StatusBarNotification.class));
+ mEntry = new NotificationEntry(mock(StatusBarNotification.class));
mEntry.setRow(mRow);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 6f4de1c..193f483 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.statusbar.notification;
+package com.android.systemui.statusbar.notification.collection;
import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
import static android.app.AppOpsManager.OP_CAMERA;
@@ -59,7 +59,9 @@
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -203,7 +205,7 @@
mRow.getEntry().notification)).thenReturn(false);
when(mEnvironment.isNotificationForCurrentProfiles(
row2.getEntry().notification)).thenReturn(true);
- ArrayList<NotificationData.Entry> result =
+ ArrayList<NotificationEntry> result =
mNotificationData.getNotificationsForCurrentUser();
assertEquals(result.size(), 1);
@@ -217,7 +219,7 @@
TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
Notification n = mMockStatusBarNotification.getNotification();
n.flags = Notification.FLAG_FOREGROUND_SERVICE;
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
mNotificationData.add(entry);
assertTrue(entry.isExemptFromDndVisualSuppression());
@@ -234,7 +236,7 @@
nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
n = nb.build();
when(mMockStatusBarNotification.getNotification()).thenReturn(n);
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
mNotificationData.add(entry);
assertTrue(entry.isExemptFromDndVisualSuppression());
@@ -246,7 +248,7 @@
initStatusBarNotification(false);
when(mMockStatusBarNotification.getKey()).thenReturn(
TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
entry.mIsSystemNotification = true;
mNotificationData.add(entry);
@@ -259,7 +261,7 @@
initStatusBarNotification(false);
when(mMockStatusBarNotification.getKey()).thenReturn(
TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
- NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+ NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
entry.mIsSystemNotification = true;
mNotificationData.add(entry);
@@ -313,8 +315,8 @@
snoozeCriterions.add(snoozeCriterion);
when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions);
- NotificationData.Entry entry =
- new NotificationData.Entry(mMockStatusBarNotification, ranking);
+ NotificationEntry entry =
+ new NotificationEntry(mMockStatusBarNotification, ranking);
assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions);
assertEquals(NOTIFICATION_CHANNEL, entry.channel);
@@ -343,7 +345,7 @@
StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
notification, mContext.getUser(), "", 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.setHasSentReply();
assertTrue(entry.isLastMessageFromReply());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index afdeb62..6472589 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -41,9 +41,10 @@
import com.android.systemui.UiOffloadThread;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -77,7 +78,7 @@
@Mock private NotificationListener mListener;
@Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private TestableNotificationLogger mLogger;
private NotificationEntryListener mNotificationEntryListener;
private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
@@ -93,7 +94,7 @@
StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
0, null, TEST_UID,
0, new Notification(), UserHandle.CURRENT, null, 0);
- mEntry = new NotificationData.Entry(sbn);
+ mEntry = new NotificationEntry(sbn);
mEntry.setRow(mRow);
mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index 82b42c5..d94bf84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -47,7 +47,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import org.junit.Before;
@@ -73,7 +73,7 @@
StatusBarNotification mStatusBarNotification;
@Mock
Notification mNotification;
- NotificationData.Entry mEntry;
+ NotificationEntry mEntry;
@Mock
RemoteInput mRemoteInput;
@Mock
@@ -107,7 +107,7 @@
// Smart replies and actions
when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true);
when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
- mEntry = new NotificationData.Entry(mStatusBarNotification);
+ mEntry = new NotificationEntry(mStatusBarNotification);
when(mSmartReplyConstants.isEnabled()).thenReturn(true);
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index ad43bea..0899c73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -60,7 +60,7 @@
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -183,8 +183,8 @@
when(row.getGuts()).thenReturn(guts);
doNothing().when(row).inflateGuts();
- NotificationData.Entry realEntry = realRow.getEntry();
- NotificationData.Entry entry = spy(realEntry);
+ NotificationEntry realEntry = realRow.getEntry();
+ NotificationEntry entry = spy(realEntry);
when(entry.getRow()).thenReturn(row);
when(entry.getGuts()).thenReturn(guts);
@@ -443,7 +443,7 @@
NotificationGuts guts = new NotificationGuts(mContext);
ExpandableNotificationRow row = spy(createTestNotificationRow());
doReturn(guts).when(row).getGuts();
- NotificationData.Entry entry = row.getEntry();
+ NotificationEntry entry = row.getEntry();
entry.setRow(row);
mGutsManager.setExposedGuts(guts);
@@ -452,7 +452,7 @@
@Test
public void testSetShouldManageLifetime_setShouldManage() {
- NotificationData.Entry entry = createTestNotificationRow().getEntry();
+ NotificationEntry entry = createTestNotificationRow().getEntry();
mGutsManager.setShouldManageLifetime(entry, true /* shouldManage */);
assertTrue(entry.key.equals(mGutsManager.mKeyToRemoveOnGutsClosed));
@@ -460,7 +460,7 @@
@Test
public void testSetShouldManageLifetime_setShouldNotManage() {
- NotificationData.Entry entry = createTestNotificationRow().getEntry();
+ NotificationEntry entry = createTestNotificationRow().getEntry();
mGutsManager.mKeyToRemoveOnGutsClosed = entry.key;
mGutsManager.setShouldManageLifetime(entry, false /* shouldManage */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
index d6b706d..648df3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
@@ -48,7 +48,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Assert;
import org.junit.Before;
@@ -88,7 +88,7 @@
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
}
});
@@ -174,7 +174,7 @@
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
countDownLatch.countDown();
}
@@ -256,7 +256,7 @@
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry,
+ public void onAsyncInflationFinished(NotificationEntry entry,
@NotificationInflater.InflationFlag int inflatedFlags) {
if (expectingException) {
exceptionHolder.setException(new RuntimeException(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index e4d0196..04d7509 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -35,7 +35,7 @@
import android.view.ViewGroup;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
@@ -54,7 +54,7 @@
public void setup() {
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
mRow = mock(ExpandableNotificationRow.class);
- NotificationData.Entry entry = new NotificationData.Entry(
+ NotificationEntry entry = new NotificationEntry(
mock(StatusBarNotification.class));
entry.channel = mock(NotificationChannel.class);
when(mRow.getEntry()).thenReturn(entry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index b66d0ab..214404c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -53,9 +53,9 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -265,8 +265,8 @@
@Test
public void testUpdateFooter_remoteInput() {
setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
+ ArrayList<NotificationEntry> entries = new ArrayList<>();
+ entries.add(mock(NotificationEntry.class));
when(mNotificationData.getActiveNotifications()).thenReturn(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
@@ -282,8 +282,8 @@
@Test
public void testUpdateFooter_oneClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
+ ArrayList<NotificationEntry> entries = new ArrayList<>();
+ entries.add(mock(NotificationEntry.class));
when(mNotificationData.getActiveNotifications()).thenReturn(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
@@ -298,8 +298,8 @@
@Test
public void testUpdateFooter_oneNonClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
+ ArrayList<NotificationEntry> entries = new ArrayList<>();
+ entries.add(mock(NotificationEntry.class));
when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries);
assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0);
@@ -314,7 +314,7 @@
// add notification
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
- NotificationData.Entry entry = mock(NotificationData.Entry.class);
+ NotificationEntry entry = mock(NotificationEntry.class);
when(row.getEntry()).thenReturn(entry);
when(entry.isClearable()).thenReturn(true);
mStackScroller.addContainerView(row);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 44deb10..9ceb325 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -16,15 +16,20 @@
package com.android.systemui.statusbar.phone;
-import android.view.View;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.when;
+
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.View;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AlertingNotificationManagerTest;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import org.junit.Before;
import org.junit.Rule;
@@ -34,11 +39,6 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
-
-import static org.mockito.Mockito.when;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -96,7 +96,7 @@
@Test
public void testCanRemoveImmediately_notTopEntry() {
- NotificationData.Entry laterEntry = new NotificationData.Entry(createNewNotification(1));
+ NotificationEntry laterEntry = new NotificationEntry(createNewNotification(1));
laterEntry.setRow(mRow);
mHeadsUpManager.showNotification(mEntry);
mHeadsUpManager.showNotification(laterEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 79695fd..cefd4ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -32,10 +32,9 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import org.junit.Before;
@@ -64,7 +63,7 @@
@Captor
private ArgumentCaptor<NotificationEntryListener> mListenerCaptor;
private NotificationEntryListener mNotificationEntryListener;
- private final HashMap<String, Entry> mPendingEntries = new HashMap<>();
+ private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>();
private final NotificationGroupTestHelper mGroupTestHelper =
new NotificationGroupTestHelper(mContext);
@@ -94,9 +93,9 @@
@Test
public void testSuppressedSummaryHeadsUpTransfersToChild() {
- Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mHeadsUpManager.showNotification(summaryEntry);
- Entry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
// Summary will be suppressed because there is only one child.
mGroupManager.onEntryAdded(summaryEntry);
@@ -109,11 +108,11 @@
@Test
public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry2 =
+ NotificationEntry childEntry2 =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
mHeadsUpManager.showNotification(summaryEntry);
// Trigger a transfer of alert state from summary to child.
@@ -133,11 +132,11 @@
@Test
public void testSuppressedSummaryHeadsUpDoesntTransferBackOnDozingChanged() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry2 =
+ NotificationEntry childEntry2 =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
mHeadsUpManager.showNotification(summaryEntry);
// Trigger a transfer of alert state from summary to child.
@@ -158,9 +157,9 @@
@Test
public void testSuppressedSummaryHeadsUpTransferDoesNotAlertChildIfUninflated() {
- Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mHeadsUpManager.showNotification(summaryEntry);
- Entry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
@@ -176,9 +175,9 @@
@Test
public void testSuppressedSummaryHeadsUpTransferAlertsChildOnInflation() {
- Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mHeadsUpManager.showNotification(summaryEntry);
- Entry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
@@ -196,13 +195,13 @@
@Test
public void testSuppressedSummaryHeadsUpTransferBackAbortsChildInflation() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
- NotificationData.Entry childEntry2 =
+ NotificationEntry childEntry2 =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
mHeadsUpManager.showNotification(summaryEntry);
// Trigger a transfer of alert state from summary to child.
@@ -226,9 +225,9 @@
@Test
public void testCleanUpPendingAlertInfo() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
@@ -244,9 +243,9 @@
@Test
public void testUpdateGroupChangeDoesNotTransfer() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
@@ -267,9 +266,9 @@
@Test
public void testUpdateChildToSummaryDoesNotTransfer() {
- NotificationData.Entry summaryEntry =
+ NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
- NotificationData.Entry childEntry =
+ NotificationEntry childEntry =
mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
.thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
index b0bd1fb..ecb3e4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
@@ -29,7 +29,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import org.junit.Before;
@@ -69,8 +69,8 @@
@Test
public void testIsOnlyChildInGroup() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
@@ -80,8 +80,8 @@
@Test
public void testIsChildInGroupWithSummary() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
@@ -92,8 +92,8 @@
@Test
public void testIsSummaryOfGroupWithChildren() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
@@ -105,8 +105,8 @@
@Test
public void testRemoveChildFromGroupWithSummary() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -118,8 +118,8 @@
@Test
public void testRemoveSummaryFromGroupWithSummary() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -132,8 +132,8 @@
@Test
public void testHeadsUpEntryIsIsolated() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -149,8 +149,8 @@
@Test
public void testAmbientPulseEntryIsIsolated() {
- NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
- NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+ NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+ NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
index 7ad68eb..e6b9778 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
@@ -27,7 +27,7 @@
import android.service.notification.StatusBarNotification;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
/**
@@ -44,23 +44,23 @@
mContext = context;
}
- public NotificationData.Entry createSummaryNotification() {
+ public NotificationEntry createSummaryNotification() {
return createSummaryNotification(Notification.GROUP_ALERT_ALL);
}
- public NotificationData.Entry createSummaryNotification(int groupAlertBehavior) {
+ public NotificationEntry createSummaryNotification(int groupAlertBehavior) {
return createEntry(true, groupAlertBehavior);
}
- public NotificationData.Entry createChildNotification() {
+ public NotificationEntry createChildNotification() {
return createChildNotification(Notification.GROUP_ALERT_ALL);
}
- public NotificationData.Entry createChildNotification(int groupAlertBehavior) {
+ public NotificationEntry createChildNotification(int groupAlertBehavior) {
return createEntry(false, groupAlertBehavior);
}
- public NotificationData.Entry createEntry(boolean isSummary, int groupAlertBehavior) {
+ public NotificationEntry createEntry(boolean isSummary, int groupAlertBehavior) {
Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("Title")
.setSmallIcon(R.drawable.ic_person)
@@ -79,7 +79,7 @@
new UserHandle(ActivityManager.getCurrentUser()),
null /* overrideGroupKey */,
0 /* postTime */);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
entry.setRow(row);
when(row.getEntry()).thenReturn(entry);
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 2bbfd7d..12cb9957 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
@@ -40,7 +40,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -82,7 +82,7 @@
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0,
false /* animate */);
TestableLooper.get(this).processAllMessages();
@@ -96,7 +96,7 @@
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
false /* animate */);
TestableLooper.get(this).processAllMessages();
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 a45a5c4..0d4046b 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
@@ -95,13 +95,13 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -135,7 +135,7 @@
@Mock private IDreamManager mDreamManager;
@Mock private ScrimController mScrimController;
@Mock private DozeScrimController mDozeScrimController;
- @Mock private ArrayList<Entry> mNotificationList;
+ @Mock private ArrayList<NotificationEntry> mNotificationList;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private NotificationData mNotificationData;
@Mock
@@ -409,7 +409,7 @@
.build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.importance = IMPORTANCE_HIGH;
assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -430,7 +430,7 @@
.build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.importance = IMPORTANCE_HIGH;
assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -447,7 +447,7 @@
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.suppressedVisualEffects = SUPPRESSED_EFFECT_PEEK;
entry.importance = IMPORTANCE_HIGH;
@@ -465,7 +465,7 @@
Notification n = new Notification.Builder(getContext(), "a").build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ NotificationEntry entry = new NotificationEntry(sbn);
entry.importance = IMPORTANCE_HIGH;
assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index c5bac92..fdc8ef1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -50,7 +50,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -94,7 +94,7 @@
private int mSpacing;
@Mock private SmartReplyController mLogger;
- private NotificationData.Entry mEntry;
+ private NotificationEntry mEntry;
private Notification mNotification;
@Mock ActivityStarter mActivityStarter;
@@ -127,7 +127,7 @@
StatusBarNotification sbn = mock(StatusBarNotification.class);
when(sbn.getNotification()).thenReturn(mNotification);
when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY);
- mEntry = new NotificationData.Entry(sbn);
+ mEntry = new NotificationEntry(sbn);
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
}
diff --git a/services/Android.bp b/services/Android.bp
index 58a0997..01734f4 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -28,6 +28,7 @@
"services.net",
"services.print",
"services.restrictions",
+ "services.startop",
"services.usage",
"services.usb",
"services.voiceinteraction",
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 2346cfc..5cea56e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -64,7 +64,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -87,6 +86,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.location.AbstractLocationProvider;
import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.GeocoderProxy;
@@ -117,6 +117,11 @@
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
/**
* The service class that manages LocationProviders and issues location
@@ -171,10 +176,7 @@
private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
private final Context mContext;
- private final AppOpsManager mAppOps;
-
- // used internally for synchronization
- private final Object mLock = new Object();
+ private AppOpsManager mAppOps;
// --- fields below are final after systemRunning() ---
private LocationFudger mLocationFudger;
@@ -186,7 +188,7 @@
private GeocoderProxy mGeocodeProvider;
private GnssStatusListenerHelper mGnssStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
- private LocationWorkerHandler mLocationHandler;
+ private final Handler mHandler;
private PassiveProvider mPassiveProvider; // track passive provider for special cases
private LocationBlacklist mBlacklist;
private GnssMeasurementsProvider mGnssMeasurementsProvider;
@@ -195,8 +197,6 @@
private boolean mLocationControllerExtraPackageEnabled;
private IGpsGeofenceHardware mGpsGeofenceProxy;
- // --- fields below are protected by mLock ---
-
// Mock (test) providers
private final HashMap<String, MockProvider> mMockProviders =
new HashMap<>();
@@ -205,8 +205,8 @@
private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
// currently installed providers (with mocks replacing real providers)
- private final ArrayList<LocationProvider> mProviders =
- new ArrayList<>();
+ private final CopyOnWriteArrayList<LocationProvider> mProviders =
+ new CopyOnWriteArrayList<>();
// real providers, saved here when mocked out
private final HashMap<String, LocationProvider> mRealProviders =
@@ -232,8 +232,8 @@
// all providers that operate over proxy, for authorizing incoming location and whitelisting
// throttling
- private final ArrayList<LocationProviderProxy> mProxyProviders =
- new ArrayList<>();
+ private final CopyOnWriteArrayList<LocationProviderProxy> mProxyProviders =
+ new CopyOnWriteArrayList<>();
private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
@@ -246,9 +246,6 @@
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
- // Maximum age of last location returned to clients with foreground-only location permissions.
- private long mLastLocationMaxAgeMs;
-
private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
@@ -261,7 +258,7 @@
public LocationManagerService(Context context) {
super();
mContext = context;
- mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mHandler = BackgroundThread.getHandler();
// Let the package manager query which are the default location
// providers as they get certain permissions granted by default.
@@ -271,132 +268,92 @@
userId -> mContext.getResources().getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames));
- if (D) Log.d(TAG, "Constructed");
-
// most startup is deferred until systemRunning()
}
public void systemRunning() {
- synchronized (mLock) {
- if (D) Log.d(TAG, "systemRunning()");
+ runInternal(this::initialize);
+ }
- // fetch package manager
- mPackageManager = mContext.getPackageManager();
+ private void initialize() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- // fetch power manager
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mPackageManager = mContext.getPackageManager();
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- // fetch activity manager
- mActivityManager
- = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ // prepare mHandler's dependents
+ mLocationFudger = new LocationFudger(mContext, mHandler);
+ mBlacklist = new LocationBlacklist(mContext, mHandler);
+ mBlacklist.init();
+ mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
- // prepare worker thread
- mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
+ mAppOps.startWatchingMode(
+ AppOpsManager.OP_COARSE_LOCATION,
+ null,
+ AppOpsManager.WATCH_FOREGROUND_CHANGES,
+ new AppOpsManager.OnOpChangedInternalListener() {
+ public void onOpChanged(int op, String packageName) {
+ mHandler.post(() -> onAppOpChanged());
+ }
+ });
- // prepare mLocationHandler's dependents
- mLocationFudger = new LocationFudger(mContext, mLocationHandler);
- mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
- mBlacklist.init();
- mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
+ mPackageManager.addOnPermissionsChangeListener(
+ uid -> runInternal(this::onPermissionsChanged));
- // Monitor for app ops mode changes.
- AppOpsManager.OnOpChangedListener callback
- = new AppOpsManager.OnOpChangedInternalListener() {
- public void onOpChanged(int op, String packageName) {
- mLocationHandler.post(() -> {
- synchronized (mLock) {
- for (Receiver receiver : mReceivers.values()) {
- receiver.updateMonitoring(true);
- }
- applyAllProviderRequirementsLocked();
- }
- });
- }
- };
- mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
- AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
+ mActivityManager.addOnUidImportanceListener(
+ (uid, importance) -> mHandler.post(
+ () -> onUidImportanceChanged(uid, importance)),
+ FOREGROUND_IMPORTANCE_CUTOFF);
- PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
- synchronized (mLock) {
- applyAllProviderRequirementsLocked();
- }
- };
- mPackageManager.addOnPermissionsChangeListener(permissionListener);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ updateUserProfiles(mCurrentUserId);
- // listen for background/foreground changes
- ActivityManager.OnUidImportanceListener uidImportanceListener =
- (uid, importance) -> mLocationHandler.post(
- () -> onUidImportanceChanged(uid, importance));
- mActivityManager.addOnUidImportanceListener(uidImportanceListener,
- FOREGROUND_IMPORTANCE_CUTOFF);
+ updateBackgroundThrottlingWhitelist();
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- updateUserProfiles(mCurrentUserId);
-
- updateBackgroundThrottlingWhitelistLocked();
- updateLastLocationMaxAgeLocked();
-
- // prepare providers
- loadProvidersLocked();
- updateProvidersSettingsLocked();
- for (LocationProvider provider : mProviders) {
- applyRequirementsLocked(provider.getName());
- }
+ // prepare providers
+ loadProvidersLocked();
+ updateProvidersSettings();
+ for (LocationProvider provider : mProviders) {
+ applyRequirements(provider.getName());
}
// listen for settings changes
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
- new ContentObserver(mLocationHandler) {
+ new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- synchronized (mLock) {
- updateProvidersSettingsLocked();
- }
+ onProviderAllowedChanged();
}
}, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
true,
- new ContentObserver(mLocationHandler) {
+ new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- synchronized (mLock) {
- for (LocationProvider provider : mProviders) {
- applyRequirementsLocked(provider.getName());
- }
- }
+ onBackgroundThrottleIntervalChanged();
}
}, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
- true,
- new ContentObserver(mLocationHandler) {
- @Override
- public void onChange(boolean selfChange) {
- synchronized (mLock) {
- updateLastLocationMaxAgeLocked();
- }
- }
- }
- );
- mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
true,
- new ContentObserver(mLocationHandler) {
+ new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- synchronized (mLock) {
- updateBackgroundThrottlingWhitelistLocked();
- for (LocationProvider provider : mProviders) {
- applyRequirementsLocked(provider.getName());
- }
- }
+ onBackgroundThrottleWhitelistChanged();
}
}, UserHandle.USER_ALL);
- mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
+ new PackageMonitor() {
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ LocationManagerService.this.onPackageDisappeared(packageName);
+ }
+ }.register(mContext, mHandler.getLooper(), true);
// listen for user change
IntentFilter intentFilter = new IntentFilter();
@@ -415,73 +372,170 @@
updateUserProfiles(mCurrentUserId);
}
}
- }, UserHandle.ALL, intentFilter, null, mLocationHandler);
+ }, UserHandle.ALL, intentFilter, null, mHandler);
+ }
+
+ // will block until completion and propagate exceptions, and thus should be used from binder
+ // threads, particuarily binder threads from components that sit above LMS (ie, not location
+ // providers).
+ private void runFromBinderBlocking(Runnable runnable) throws RemoteException {
+ runFromBinderBlocking(Executors.callable(runnable));
+ }
+
+ // will block until completion and propagate exceptions, and thus should be used from binder
+ // threads, particuarily binder threads from components that sit above LMS (ie, not location
+ // providers).
+ private <T> T runFromBinderBlocking(Callable<T> callable) throws RemoteException {
+ FutureTask<T> task = new FutureTask<>(callable);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ runInternal(task);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ try {
+ return task.get();
+ } catch (ExecutionException e) {
+ // binder calls can handle 3 types of exceptions, runtimeexception and error (which can
+ // be thrown any time), and remote exception. we transfer all of these exceptions from
+ // the execution thread to the binder thread so that they may propagate normally. note
+ // that we are loosing some context in doing so (losing the stack trace from the binder
+ // thread).
+ if (e.getCause() instanceof RemoteException) {
+ throw (RemoteException) e.getCause();
+ } else if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ } else if (e.getCause() instanceof Error) {
+ throw (Error) e.getCause();
+ }
+
+ // callers should not throw checked exceptions
+ Log.wtf(TAG, "caller threw checked exception", e);
+ throw new UnsupportedOperationException(e);
+ } catch (InterruptedException e) {
+ throw new RemoteException("Binder call interrupted", e, true, true);
+ }
+ }
+
+ // will return immediately and will not propagate exceptions. should be used for non-binder work
+ // that needs to be shifted onto the location thread, primarily listeners that do not support
+ // running on arbitrary threads.
+ private void runInternal(Runnable runnable) {
+ // it would be a better use of resources to use locks to manage cross thread access to
+ // various pieces on information. however, the history of the location package has mostly
+ // shown that this is difficult to maintain in a multi-dev environment, and tends to always
+ // lead towards the use of uber-locks and deadlocks. using a single thread to run everything
+ // is more understandable for most devs, and seems less likely to result in future bugs
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ runnable.run();
+ } else {
+ mHandler.post(runnable);
+ }
+ }
+
+ private void onAppOpChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ for (Receiver receiver : mReceivers.values()) {
+ receiver.updateMonitoring(true);
+ }
+ for (LocationProvider p : mProviders) {
+ applyRequirements(p.getName());
+ }
+ }
+
+ private void onPermissionsChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ for (LocationProvider p : mProviders) {
+ applyRequirements(p.getName());
+ }
+ }
+
+ private void onProviderAllowedChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ updateProvidersSettings();
+ }
+
+ private void onPackageDisappeared(String packageName) {
+ ArrayList<Receiver> deadReceivers = null;
+
+ for (Receiver receiver : mReceivers.values()) {
+ if (receiver.mIdentity.mPackageName.equals(packageName)) {
+ if (deadReceivers == null) {
+ deadReceivers = new ArrayList<>();
+ }
+ deadReceivers.add(receiver);
+ }
+ }
+
+ // perform removal outside of mReceivers loop
+ if (deadReceivers != null) {
+ for (Receiver receiver : deadReceivers) {
+ removeUpdates(receiver);
+ }
+ }
}
private void onUidImportanceChanged(int uid, int importance) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
boolean foreground = isImportanceForeground(importance);
HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
- synchronized (mLock) {
- for (Entry<String, ArrayList<UpdateRecord>> entry
- : mRecordsByProvider.entrySet()) {
- String provider = entry.getKey();
- for (UpdateRecord record : entry.getValue()) {
- if (record.mReceiver.mIdentity.mUid == uid
- && record.mIsForegroundUid != foreground) {
- if (D) {
- Log.d(TAG, "request from uid " + uid + " is now "
- + (foreground ? "foreground" : "background)"));
- }
- record.updateForeground(foreground);
-
- if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
- affectedProviders.add(provider);
- }
- }
- }
- }
- for (String provider : affectedProviders) {
- applyRequirementsLocked(provider);
- }
-
- for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
- Identity callerIdentity = entry.getValue();
- if (callerIdentity.mUid == uid) {
+ for (Entry<String, ArrayList<UpdateRecord>> entry
+ : mRecordsByProvider.entrySet()) {
+ String provider = entry.getKey();
+ for (UpdateRecord record : entry.getValue()) {
+ if (record.mReceiver.mIdentity.mUid == uid
+ && record.mIsForegroundUid != foreground) {
if (D) {
- Log.d(TAG, "gnss measurements listener from uid " + uid
- + " is now " + (foreground ? "foreground" : "background)"));
- }
- if (foreground || isThrottlingExemptLocked(entry.getValue())) {
- mGnssMeasurementsProvider.addListener(
- IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
- callerIdentity.mUid, callerIdentity.mPackageName);
- } else {
- mGnssMeasurementsProvider.removeListener(
- IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
- }
- }
- }
-
- for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
- Identity callerIdentity = entry.getValue();
- if (callerIdentity.mUid == uid) {
- if (D) {
- Log.d(TAG, "gnss navigation message listener from uid "
- + uid + " is now "
+ Log.d(TAG, "request from uid " + uid + " is now "
+ (foreground ? "foreground" : "background)"));
}
- if (foreground || isThrottlingExemptLocked(entry.getValue())) {
- mGnssNavigationMessageProvider.addListener(
- IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
- callerIdentity.mUid, callerIdentity.mPackageName);
- } else {
- mGnssNavigationMessageProvider.removeListener(
- IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
+ record.updateForeground(foreground);
+
+ if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
+ affectedProviders.add(provider);
}
}
}
+ }
+ for (String provider : affectedProviders) {
+ applyRequirements(provider);
+ }
- // TODO(b/120449926): The GNSS status listeners should be handled similar to the above.
+ for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
+ Identity callerIdentity = entry.getValue();
+ if (callerIdentity.mUid == uid) {
+ if (D) {
+ Log.d(TAG, "gnss measurements listener from uid " + uid
+ + " is now " + (foreground ? "foreground" : "background)"));
+ }
+ if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+ mGnssMeasurementsProvider.addListener(
+ IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
+ callerIdentity.mUid, callerIdentity.mPackageName);
+ } else {
+ mGnssMeasurementsProvider.removeListener(
+ IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
+ }
+ }
+ }
+
+ for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
+ Identity callerIdentity = entry.getValue();
+ if (callerIdentity.mUid == uid) {
+ if (D) {
+ Log.d(TAG, "gnss navigation message listener from uid "
+ + uid + " is now "
+ + (foreground ? "foreground" : "background)"));
+ }
+ if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+ mGnssNavigationMessageProvider.addListener(
+ IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
+ callerIdentity.mUid, callerIdentity.mPackageName);
+ } else {
+ mGnssNavigationMessageProvider.removeListener(
+ IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
+ }
+ }
}
}
@@ -489,31 +543,33 @@
return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
}
- /**
- * Makes a list of userids that are related to the current user. This is
- * relevant when using managed profiles. Otherwise the list only contains
- * the current user.
- *
- * @param currentUserId the current user, who might have an alter-ego.
- */
- private void updateUserProfiles(int currentUserId) {
- int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
- synchronized (mLock) {
- mCurrentUserProfiles = profileIds;
+ private void onBackgroundThrottleIntervalChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ for (LocationProvider provider : mProviders) {
+ applyRequirements(provider.getName());
}
}
- /**
- * Checks if the specified userId matches any of the current foreground
- * users stored in mCurrentUserProfiles.
- */
- private boolean isCurrentProfile(int userId) {
- synchronized (mLock) {
- return ArrayUtils.contains(mCurrentUserProfiles, userId);
+ private void onBackgroundThrottleWhitelistChanged() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ updateBackgroundThrottlingWhitelist();
+ for (LocationProvider provider : mProviders) {
+ applyRequirements(provider.getName());
}
}
+ private void updateUserProfiles(int currentUserId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(currentUserId);
+ }
+
+ private boolean isCurrentProfile(int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ return ArrayUtils.contains(mCurrentUserProfiles, userId);
+ }
+
private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
PackageManager pm = mContext.getPackageManager();
String systemPackageName = mContext.getPackageName();
ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
@@ -584,12 +640,13 @@
}
private void loadProvidersLocked() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
// create a passive location provider, which is always enabled
LocationProvider passiveProviderManager = new LocationProvider(
LocationManager.PASSIVE_PROVIDER);
PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
- addProviderLocked(passiveProviderManager);
+ addProvider(passiveProviderManager);
mPassiveProvider = passiveProvider;
if (GnssLocationProvider.isSupported()) {
@@ -598,14 +655,14 @@
LocationManager.GPS_PROVIDER);
GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
gnssProviderManager,
- mLocationHandler.getLooper());
+ mHandler.getLooper());
mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
- addProviderLocked(gnssProviderManager);
+ addProvider(gnssProviderManager);
mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
@@ -647,7 +704,7 @@
if (networkProvider != null) {
mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
mProxyProviders.add(networkProvider);
- addProviderLocked(networkProviderManager);
+ addProvider(networkProviderManager);
} else {
Slog.w(TAG, "no network location provider found");
}
@@ -663,7 +720,7 @@
com.android.internal.R.string.config_fusedLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
if (fusedProvider != null) {
- addProviderLocked(fusedProviderManager);
+ addProvider(fusedProviderManager);
mProxyProviders.add(fusedProvider);
mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
} else {
@@ -728,28 +785,22 @@
Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
Integer.parseInt(fragments[8]) /* powerRequirement */,
Integer.parseInt(fragments[9]) /* accuracy */);
- addTestProviderLocked(name, properties);
+ addTestProvider(name, properties);
}
}
- /**
- * Called when the device's active user changes.
- *
- * @param userId the new active user's UserId
- */
private void switchUser(int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (mCurrentUserId == userId) {
return;
}
mBlacklist.switchUser(userId);
- mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
- synchronized (mLock) {
- mLastLocation.clear();
- mLastLocationCoarseInterval.clear();
- updateUserProfiles(userId);
- updateProvidersSettingsLocked();
- mCurrentUserId = userId;
- }
+ mHandler.removeMessages(MSG_LOCATION_CHANGED);
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
+ updateUserProfiles(userId);
+ updateProvidersSettings();
+ mCurrentUserId = userId;
}
private static final class Identity {
@@ -808,10 +859,13 @@
}
public void setRequest(ProviderRequest request, WorkSource workSource) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
mProvider.setRequest(request, workSource);
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
pw.println(mName + " provider:");
pw.println(" setting=" + mSettingsEnabled);
pw.println(" enabled=" + mEnabled);
@@ -820,34 +874,38 @@
}
public long getStatusUpdateTime() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
return mProvider.getStatusUpdateTime();
}
public int getStatus(Bundle extras) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
return mProvider.getStatus(extras);
}
public void sendExtraCommand(String command, Bundle extras) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
mProvider.sendExtraCommand(command, extras);
}
// called from any thread
@Override
public void onReportLocation(Location location) {
- runOnHandler(() -> LocationManagerService.this.reportLocation(location,
+ // no security check necessary because this is coming from an internal-only interface
+ runInternal(() -> LocationManagerService.this.handleLocationChanged(location,
mProvider == mPassiveProvider));
}
// called from any thread
@Override
public void onReportLocation(List<Location> locations) {
- runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
+ LocationManagerService.this.reportLocationBatch(locations);
}
// called from any thread
@Override
public void onSetEnabled(boolean enabled) {
- runOnHandler(() -> {
+ runInternal(() -> {
if (enabled == mEnabled) {
return;
}
@@ -872,18 +930,16 @@
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
"-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
- synchronized (mLock) {
- if (!enabled) {
- // If any provider has been disabled, clear all last locations for all
- // providers. This is to be on the safe side in case a provider has location
- // derived from this disabled provider.
- mLastLocation.clear();
- mLastLocationCoarseInterval.clear();
- }
-
- updateProviderListenersLocked(mName);
+ if (!enabled) {
+ // If any provider has been disabled, clear all last locations for all
+ // providers. This is to be on the safe side in case a provider has location
+ // derived from this disabled provider.
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
}
+ updateProviderListeners(mName);
+
mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
UserHandle.ALL);
});
@@ -891,34 +947,27 @@
@Override
public void onSetProperties(ProviderProperties properties) {
- runOnHandler(() -> mProperties = properties);
+ runInternal(() -> {
+ mProperties = properties;
+ });
}
private void setSettingsEnabled(boolean enabled) {
- synchronized (mLock) {
- if (mSettingsEnabled == enabled) {
- return;
- }
-
- mSettingsEnabled = enabled;
- if (!mSettingsEnabled) {
- // if any provider has been disabled, clear all last locations for all
- // providers. this is to be on the safe side in case a provider has location
- // derived from this disabled provider.
- mLastLocation.clear();
- mLastLocationCoarseInterval.clear();
- updateProviderListenersLocked(mName);
- } else if (mEnabled) {
- updateProviderListenersLocked(mName);
- }
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ if (mSettingsEnabled == enabled) {
+ return;
}
- }
- private void runOnHandler(Runnable runnable) {
- if (Looper.myLooper() == mLocationHandler.getLooper()) {
- runnable.run();
- } else {
- mLocationHandler.post(runnable);
+ mSettingsEnabled = enabled;
+ if (!mSettingsEnabled) {
+ // if any provider has been disabled, clear all last locations for all
+ // providers. this is to be on the safe side in case a provider has location
+ // derived from this disabled provider.
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
+ updateProviderListeners(mName);
+ } else if (mEnabled) {
+ updateProviderListeners(mName);
}
}
}
@@ -1022,7 +1071,7 @@
// See if receiver has any enabled update records. Also note if any update records
// are high power (has a high power provider with an interval under a threshold).
for (UpdateRecord updateRecord : mUpdateRecords.values()) {
- if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
+ if (isAllowedByUserSettingsForUser(updateRecord.mProvider,
mCurrentUserId)) {
requestingLocation = true;
LocationManagerService.LocationProvider locationProvider
@@ -1122,7 +1171,7 @@
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
+ mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
getResolutionPermission(mAllowedResolutionLevel),
PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
// call this after broadcasting so we do not increment
@@ -1158,7 +1207,7 @@
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
+ mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
getResolutionPermission(mAllowedResolutionLevel),
PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
// call this after broadcasting so we do not increment
@@ -1201,7 +1250,7 @@
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
+ mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
getResolutionPermission(mAllowedResolutionLevel),
PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
// call this after broadcasting so we do not increment
@@ -1219,12 +1268,12 @@
public void binderDied() {
if (D) Log.d(TAG, "Location listener died");
- synchronized (mLock) {
- removeUpdatesLocked(this);
- }
- synchronized (this) {
- clearPendingBroadcastsLocked();
- }
+ runInternal(() -> {
+ removeUpdates(this);
+ synchronized (this) {
+ clearPendingBroadcastsLocked();
+ }
+ });
}
@Override
@@ -1261,28 +1310,22 @@
}
@Override
- public void locationCallbackFinished(ILocationListener listener) {
+ public void locationCallbackFinished(ILocationListener listener) throws RemoteException {
//Do not use getReceiverLocked here as that will add the ILocationListener to
//the receiver list if it is not found. If it is not found then the
//LocationListener was removed when it had a pending broadcast and should
//not be added back.
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
IBinder binder = listener.asBinder();
Receiver receiver = mReceivers.get(binder);
if (receiver != null) {
synchronized (receiver) {
- // so wakelock calls will succeed
- long identity = Binder.clearCallingIdentity();
receiver.decrementPendingBroadcastsLocked();
- Binder.restoreCallingIdentity(identity);
}
}
- }
+ });
}
- /**
- * Returns the year of the GNSS hardware.
- */
@Override
public int getGnssYearOfHardware() {
if (mGnssSystemInfoProvider != null) {
@@ -1292,10 +1335,6 @@
}
}
-
- /**
- * Returns the model name of the GNSS hardware.
- */
@Override
@Nullable
public String getGnssHardwareModelName() {
@@ -1306,10 +1345,6 @@
}
}
- /**
- * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
- * (try to) access GNSS information at this layer.
- */
private boolean hasGnssPermissions(String packageName) {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForProviderUse(
@@ -1329,9 +1364,6 @@
return hasLocationAccess;
}
- /**
- * Returns the GNSS batching size, if available.
- */
@Override
public int getGnssBatchSize(String packageName) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1344,10 +1376,6 @@
}
}
- /**
- * Adds a callback for GNSS Batching events, if permissions allow, which are transported
- * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
- */
@Override
public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1391,9 +1419,6 @@
}
}
- /**
- * Removes callback for GNSS batching
- */
@Override
public void removeGnssBatchingCallback() {
try {
@@ -1408,10 +1433,6 @@
mGnssBatchingDeathCallback = null;
}
-
- /**
- * Starts GNSS batching, if available.
- */
@Override
public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1432,9 +1453,6 @@
return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
}
- /**
- * Flushes a GNSS batch in progress
- */
@Override
public void flushGnssBatch(String packageName) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1454,9 +1472,6 @@
}
}
- /**
- * Stops GNSS batching
- */
@Override
public boolean stopGnssBatch() {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1475,7 +1490,7 @@
checkCallerIsProvider();
// Currently used only for GNSS locations - update permissions check if changed
- if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
+ if (isAllowedByUserSettingsForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
if (mGnssBatchingCallback == null) {
Slog.e(TAG, "reportLocationBatch() called without active Callback");
return;
@@ -1490,35 +1505,28 @@
}
}
- private void addProviderLocked(LocationProvider provider) {
+ private void addProvider(LocationProvider provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
mProviders.add(provider);
mProvidersByName.put(provider.getName(), provider);
}
- private void removeProviderLocked(LocationProvider provider) {
+ private void removeProvider(LocationProvider provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
mProviders.remove(provider);
mProvidersByName.remove(provider.getName());
}
- /**
- * Returns "true" if access to the specified location provider is allowed by the specified
- * user's settings. Access to all location providers is forbidden to non-location-provider
- * processes belonging to background users.
- *
- * @param provider the name of the location provider
- * @param userId the user id to query
- */
- private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
+ private boolean isAllowedByUserSettingsForUser(String provider, int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
- return isLocationEnabledForUser(userId);
+ return isLocationEnabledForUserInternal(userId);
}
if (LocationManager.FUSED_PROVIDER.equals(provider)) {
- return isLocationEnabledForUser(userId);
+ return isLocationEnabledForUserInternal(userId);
}
- synchronized (mLock) {
- if (mMockProviders.containsKey(provider)) {
- return isLocationEnabledForUser(userId);
- }
+ if (mMockProviders.containsKey(provider)) {
+ return isLocationEnabledForUserInternal(userId);
}
long identity = Binder.clearCallingIdentity();
@@ -1533,29 +1541,14 @@
}
}
-
- /**
- * Returns "true" if access to the specified location provider is allowed by the specified
- * user's settings. Access to all location providers is forbidden to non-location-provider
- * processes belonging to background users.
- *
- * @param provider the name of the location provider
- * @param uid the requestor's UID
- * @param userId the user id to query
- */
- private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
+ private boolean isAllowedByUserSettings(String provider, int uid, int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
return false;
}
- return isAllowedByUserSettingsLockedForUser(provider, userId);
+ return isAllowedByUserSettingsForUser(provider, userId);
}
- /**
- * Returns the permission string associated with the specified resolution level.
- *
- * @param resolutionLevel the resolution level
- * @return the permission string
- */
private String getResolutionPermission(int resolutionLevel) {
switch (resolutionLevel) {
case RESOLUTION_LEVEL_FINE:
@@ -1567,13 +1560,6 @@
}
}
- /**
- * Returns the resolution level allowed to the given PID/UID pair.
- *
- * @param pid the PID
- * @param uid the UID
- * @return resolution level allowed to the pid/uid pair
- */
private int getAllowedResolutionLevel(int pid, int uid) {
if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
pid, uid) == PERMISSION_GRANTED) {
@@ -1586,32 +1572,16 @@
}
}
- /**
- * Returns the resolution level allowed to the caller
- *
- * @return resolution level allowed to caller
- */
private int getCallerAllowedResolutionLevel() {
return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
}
- /**
- * Throw SecurityException if specified resolution level is insufficient to use geofences.
- *
- * @param allowedResolutionLevel resolution level allowed to caller
- */
private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
}
}
- /**
- * Return the minimum resolution level required to use the specified location provider.
- *
- * @param provider the name of the location provider
- * @return minimum resolution level required for provider
- */
private int getMinimumResolutionLevelForProviderUse(String provider) {
if (LocationManager.GPS_PROVIDER.equals(provider) ||
LocationManager.PASSIVE_PROVIDER.equals(provider)) {
@@ -1643,13 +1613,6 @@
return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
}
- /**
- * Throw SecurityException if specified resolution level is insufficient to use the named
- * location provider.
- *
- * @param allowedResolutionLevel resolution level allowed to caller
- * @param providerName the name of the location provider
- */
private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
String providerName) {
int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
@@ -1668,20 +1631,6 @@
}
}
- /**
- * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
- * for battery).
- */
- private void checkDeviceStatsAllowed() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_DEVICE_STATS, null);
- }
-
- private void checkUpdateAppOpsAllowed() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
- }
-
public static int resolutionLevelToOp(int allowedResolutionLevel) {
if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
@@ -1739,19 +1688,15 @@
*/
@Override
public List<String> getAllProviders() {
- ArrayList<String> out;
- synchronized (mLock) {
- out = new ArrayList<>(mProviders.size());
- for (LocationProvider provider : mProviders) {
- String name = provider.getName();
- if (LocationManager.FUSED_PROVIDER.equals(name)) {
- continue;
- }
- out.add(name);
+ ArrayList<String> providers = new ArrayList<>(mProviders.size());
+ for (LocationProvider provider : mProviders) {
+ String name = provider.getName();
+ if (LocationManager.FUSED_PROVIDER.equals(name)) {
+ continue;
}
+ providers.add(name);
}
- if (D) Log.d(TAG, "getAllProviders()=" + out);
- return out;
+ return providers;
}
/**
@@ -1760,39 +1705,33 @@
* Can return passive provider, but never returns fused provider.
*/
@Override
- public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
+ public List<String> getProviders(Criteria criteria, boolean enabledOnly)
+ throws RemoteException {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- ArrayList<String> out;
int uid = Binder.getCallingUid();
- long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- out = new ArrayList<>(mProviders.size());
- for (LocationProvider provider : mProviders) {
- String name = provider.getName();
- if (LocationManager.FUSED_PROVIDER.equals(name)) {
- continue;
- }
- if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
- if (enabledOnly
- && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
- continue;
- }
- if (criteria != null
- && !android.location.LocationProvider.propertiesMeetCriteria(
- name, provider.getProperties(), criteria)) {
- continue;
- }
- out.add(name);
- }
+ return runFromBinderBlocking(() -> {
+ ArrayList<String> providers = new ArrayList<>(mProviders.size());
+ for (LocationProvider provider : mProviders) {
+ String name = provider.getName();
+ if (LocationManager.FUSED_PROVIDER.equals(name)) {
+ continue;
}
+ if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUse(name)) {
+ continue;
+ }
+ if (enabledOnly
+ && !isAllowedByUserSettings(name, uid, mCurrentUserId)) {
+ continue;
+ }
+ if (criteria != null
+ && !android.location.LocationProvider.propertiesMeetCriteria(
+ name, provider.getProperties(), criteria)) {
+ continue;
+ }
+ providers.add(name);
}
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- if (D) Log.d(TAG, "getProviders()=" + out);
- return out;
+ return providers;
+ });
}
/**
@@ -1803,59 +1742,51 @@
* some simplified logic.
*/
@Override
- public String getBestProvider(Criteria criteria, boolean enabledOnly) {
- String result;
-
+ public String getBestProvider(Criteria criteria, boolean enabledOnly) throws RemoteException {
List<String> providers = getProviders(criteria, enabledOnly);
- if (!providers.isEmpty()) {
- result = pickBest(providers);
- if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
- return result;
- }
- providers = getProviders(null, enabledOnly);
- if (!providers.isEmpty()) {
- result = pickBest(providers);
- if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
- return result;
+ if (providers.isEmpty()) {
+ providers = getProviders(null, enabledOnly);
}
- if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
+ if (!providers.isEmpty()) {
+ if (providers.contains(LocationManager.GPS_PROVIDER)) {
+ return LocationManager.GPS_PROVIDER;
+ } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
+ return LocationManager.NETWORK_PROVIDER;
+ } else {
+ return providers.get(0);
+ }
+ }
+
return null;
}
- private String pickBest(List<String> providers) {
- if (providers.contains(LocationManager.GPS_PROVIDER)) {
- return LocationManager.GPS_PROVIDER;
- } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
- return LocationManager.NETWORK_PROVIDER;
- } else {
- return providers.get(0);
- }
- }
-
@Override
- public boolean providerMeetsCriteria(String provider, Criteria criteria) {
- LocationProvider p = mProvidersByName.get(provider);
- if (p == null) {
- throw new IllegalArgumentException("provider=" + provider);
- }
+ public boolean providerMeetsCriteria(String provider, Criteria criteria)
+ throws RemoteException {
+ return runFromBinderBlocking(() -> {
+ LocationProvider p = mProvidersByName.get(provider);
+ if (p == null) {
+ throw new IllegalArgumentException("provider=" + provider);
+ }
- boolean result = android.location.LocationProvider.propertiesMeetCriteria(
- p.getName(), p.getProperties(), criteria);
- if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
- return result;
+ return android.location.LocationProvider.propertiesMeetCriteria(
+ p.getName(), p.getProperties(), criteria);
+ });
}
- private void updateProvidersSettingsLocked() {
+ private void updateProvidersSettings() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
for (LocationProvider p : mProviders) {
- p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
+ p.setSettingsEnabled(isAllowedByUserSettingsForUser(p.getName(), mCurrentUserId));
}
mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
UserHandle.ALL);
}
- private void updateProviderListenersLocked(String provider) {
+ private void updateProviderListeners(String provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
@@ -1880,14 +1811,15 @@
if (deadReceivers != null) {
for (int i = deadReceivers.size() - 1; i >= 0; i--) {
- removeUpdatesLocked(deadReceivers.get(i));
+ removeUpdates(deadReceivers.get(i));
}
}
- applyRequirementsLocked(provider);
+ applyRequirements(provider);
}
- private void applyRequirementsLocked(String provider) {
+ private void applyRequirements(String provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
@@ -1993,14 +1925,13 @@
}
@Override
- public String[] getBackgroundThrottlingWhitelist() {
- synchronized (mLock) {
- return mBackgroundThrottlePackageWhitelist.toArray(
- new String[0]);
- }
+ public String[] getBackgroundThrottlingWhitelist() throws RemoteException {
+ return runFromBinderBlocking(
+ () -> mBackgroundThrottlePackageWhitelist.toArray(new String[0]));
}
- private void updateBackgroundThrottlingWhitelistLocked() {
+ private void updateBackgroundThrottlingWhitelist() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
String setting = Settings.Global.getString(
mContext.getContentResolver(),
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
@@ -2015,15 +1946,8 @@
Arrays.asList(setting.split(",")));
}
- private void updateLastLocationMaxAgeLocked() {
- mLastLocationMaxAgeMs =
- Settings.Global.getLong(
- mContext.getContentResolver(),
- Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
- DEFAULT_LAST_LOCATION_MAX_AGE_MS);
- }
-
private boolean isThrottlingExemptLocked(Identity identity) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (identity.mUid == Process.SYSTEM_UID) {
return true;
}
@@ -2105,7 +2029,7 @@
// and also remove the Receiver if it has no more update records
if (receiverRecords.size() == 0) {
- removeUpdatesLocked(mReceiver);
+ removeUpdates(mReceiver);
}
}
@@ -2119,8 +2043,9 @@
}
}
- private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
+ private Receiver getReceiver(ILocationListener listener, int pid, int uid,
String packageName, WorkSource workSource, boolean hideFromAppOps) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
IBinder binder = listener.asBinder();
Receiver receiver = mReceivers.get(binder);
if (receiver == null) {
@@ -2137,8 +2062,9 @@
return receiver;
}
- private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
+ private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName,
WorkSource workSource, boolean hideFromAppOps) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Receiver receiver = mReceivers.get(intent);
if (receiver == null) {
receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
@@ -2202,29 +2128,9 @@
throw new SecurityException("invalid package name: " + packageName);
}
- private void checkPendingIntent(PendingIntent intent) {
- if (intent == null) {
- throw new IllegalArgumentException("invalid pending intent: " + null);
- }
- }
-
- private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
- int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
- if (intent == null && listener == null) {
- throw new IllegalArgumentException("need either listener or intent");
- } else if (intent != null && listener != null) {
- throw new IllegalArgumentException("cannot register both listener and intent");
- } else if (intent != null) {
- checkPendingIntent(intent);
- return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
- } else {
- return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
- }
- }
-
@Override
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
- PendingIntent intent, String packageName) {
+ PendingIntent intent, String packageName) throws RemoteException {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
checkPackageName(packageName);
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
@@ -2232,11 +2138,13 @@
request.getProvider());
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
- checkDeviceStatsAllowed();
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.UPDATE_DEVICE_STATS, null);
}
boolean hideFromAppOps = request.getHideFromAppOps();
if (hideFromAppOps) {
- checkUpdateAppOpsAllowed();
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.UPDATE_APP_OPS_STATS, null);
}
boolean callerHasLocationHardwarePermission =
mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
@@ -2246,25 +2154,33 @@
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
- // providers may use public location API's, need to clear identity
- long identity = Binder.clearCallingIdentity();
- try {
- // We don't check for MODE_IGNORED here; we will do that when we go to deliver
- // a location.
- checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
- synchronized (mLock) {
- Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
- packageName, workSource, hideFromAppOps);
- requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ // We don't check for MODE_IGNORED here; we will do that when we go to deliver
+ // a location.
+ checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
+
+ if (intent == null && listener == null) {
+ throw new IllegalArgumentException("need either listener or intent");
+ } else if (intent != null && listener != null) {
+ throw new IllegalArgumentException("cannot register both listener and intent");
}
+
+ runFromBinderBlocking(() -> {
+ Receiver receiver;
+ if (intent != null) {
+ receiver = getReceiver(intent, pid, uid, packageName, workSource,
+ hideFromAppOps);
+ } else {
+ receiver = getReceiver(listener, pid, uid, packageName, workSource,
+ hideFromAppOps);
+ }
+ requestLocationUpdates(sanitizedRequest, receiver, uid, packageName);
+ });
}
- private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
+ private void requestLocationUpdates(LocationRequest request, Receiver receiver,
int uid, String packageName) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
// Figure out the provider. Either its explicitly request (legacy use cases), or
// use the fused provider
if (request == null) request = DEFAULT_LOCATION_REQUEST;
@@ -2293,7 +2209,7 @@
}
if (provider.isEnabled()) {
- applyRequirementsLocked(name);
+ applyRequirements(name);
} else {
// Notify the listener that updates are currently disabled
receiver.callProviderEnabledLocked(name, false);
@@ -2305,27 +2221,31 @@
@Override
public void removeUpdates(ILocationListener listener, PendingIntent intent,
- String packageName) {
+ String packageName) throws RemoteException {
checkPackageName(packageName);
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ int uid = Binder.getCallingUid();
- synchronized (mLock) {
- Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
- packageName, null, false);
-
- // providers may use public location API's, need to clear identity
- long identity = Binder.clearCallingIdentity();
- try {
- removeUpdatesLocked(receiver);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ if (intent == null && listener == null) {
+ throw new IllegalArgumentException("need either listener or intent");
+ } else if (intent != null && listener != null) {
+ throw new IllegalArgumentException("cannot register both listener and intent");
}
+
+ runFromBinderBlocking(() -> {
+ Receiver receiver;
+ if (intent != null) {
+ receiver = getReceiver(intent, pid, uid, packageName, null, false);
+ } else {
+ receiver = getReceiver(listener, pid, uid, packageName, null, false);
+ }
+ removeUpdates(receiver);
+ });
}
- private void removeUpdatesLocked(Receiver receiver) {
+ private void removeUpdates(Receiver receiver) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
@@ -2352,20 +2272,14 @@
// update provider
for (String provider : providers) {
- applyRequirementsLocked(provider);
- }
- }
-
- private void applyAllProviderRequirementsLocked() {
- for (LocationProvider p : mProviders) {
- applyRequirementsLocked(p.getName());
+ applyRequirements(provider);
}
}
@Override
- public Location getLastLocation(LocationRequest request, String packageName) {
- if (D) Log.d(TAG, "getLastLocation: " + request);
- if (request == null) request = DEFAULT_LOCATION_REQUEST;
+ public Location getLastLocation(LocationRequest r, String packageName) throws RemoteException {
+ if (D) Log.d(TAG, "getLastLocation: " + r);
+ LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkPackageName(packageName);
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
@@ -2391,68 +2305,60 @@
}
return null;
}
-
- synchronized (mLock) {
- // Figure out the provider. Either its explicitly request (deprecated API's),
- // or use the fused provider
- String name = request.getProvider();
- if (name == null) name = LocationManager.FUSED_PROVIDER;
- LocationProvider provider = mProvidersByName.get(name);
- if (provider == null) return null;
-
- if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
-
- Location location;
- if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
- // Make sure that an app with coarse permissions can't get frequent location
- // updates by calling LocationManager.getLastKnownLocation repeatedly.
- location = mLastLocationCoarseInterval.get(name);
- } else {
- location = mLastLocation.get(name);
- }
- if (location == null) {
- return null;
- }
-
- // Don't return stale location to apps with foreground-only location permission.
- String op = resolutionLevelToOpStr(allowedResolutionLevel);
- long locationAgeMs = SystemClock.elapsedRealtime() -
- location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
- if ((locationAgeMs > mLastLocationMaxAgeMs)
- && (mAppOps.unsafeCheckOp(op, uid, packageName)
- == AppOpsManager.MODE_FOREGROUND)) {
- return null;
- }
-
- if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
- Location noGPSLocation = location.getExtraLocation(
- Location.EXTRA_NO_GPS_LOCATION);
- if (noGPSLocation != null) {
- return new Location(mLocationFudger.getOrCreate(noGPSLocation));
- }
- } else {
- return new Location(location);
- }
- }
- return null;
} finally {
Binder.restoreCallingIdentity(identity);
}
+
+ return runFromBinderBlocking(() -> {
+ // Figure out the provider. Either its explicitly request (deprecated API's),
+ // or use the fused provider
+ String name = request.getProvider();
+ if (name == null) name = LocationManager.FUSED_PROVIDER;
+ LocationProvider provider = mProvidersByName.get(name);
+ if (provider == null) return null;
+
+ if (!isAllowedByUserSettings(name, uid, mCurrentUserId)) return null;
+
+ Location location;
+ if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
+ // Make sure that an app with coarse permissions can't get frequent location
+ // updates by calling LocationManager.getLastKnownLocation repeatedly.
+ location = mLastLocationCoarseInterval.get(name);
+ } else {
+ location = mLastLocation.get(name);
+ }
+ if (location == null) {
+ return null;
+ }
+
+ // Don't return stale location to apps with foreground-only location permission.
+ String op = resolutionLevelToOpStr(allowedResolutionLevel);
+ long locationAgeMs = SystemClock.elapsedRealtime()
+ - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
+ if ((locationAgeMs > Settings.Global.getLong(
+ mContext.getContentResolver(),
+ Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
+ DEFAULT_LAST_LOCATION_MAX_AGE_MS))
+ && (mAppOps.unsafeCheckOp(op, uid, packageName)
+ == AppOpsManager.MODE_FOREGROUND)) {
+ return null;
+ }
+
+ if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
+ Location noGPSLocation = location.getExtraLocation(
+ Location.EXTRA_NO_GPS_LOCATION);
+ if (noGPSLocation != null) {
+ return new Location(mLocationFudger.getOrCreate(noGPSLocation));
+ }
+ } else {
+ return new Location(location);
+ }
+ return null;
+ });
}
- /**
- * Provides an interface to inject and set the last location if location is not available
- * currently.
- *
- * This helps in cases where the product (Cars for example) has saved the last known location
- * before powering off. This interface lets the client inject the saved location while the GPS
- * chipset is getting its first fix, there by improving user experience.
- *
- * @param location - Location object to inject
- * @return true if update was successful, false if not
- */
@Override
- public boolean injectLocation(Location location) {
+ public boolean injectLocation(Location location) throws RemoteException {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to inject location");
mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
@@ -2464,29 +2370,31 @@
}
return false;
}
- LocationProvider p = null;
- String provider = location.getProvider();
- if (provider != null) {
- p = mProvidersByName.get(provider);
- }
- if (p == null) {
- if (D) {
- Log.d(TAG, "injectLocation(): unknown provider");
+
+ return runFromBinderBlocking(() -> {
+ LocationProvider p = null;
+ String provider = location.getProvider();
+ if (provider != null) {
+ p = mProvidersByName.get(provider);
}
- return false;
- }
- synchronized (mLock) {
- if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
+ if (p == null) {
if (D) {
- Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
+ Log.d(TAG, "injectLocation(): unknown provider");
+ }
+ return false;
+ }
+ if (!isAllowedByUserSettingsForUser(provider, mCurrentUserId)) {
+ if (D) {
+ Log.d(TAG, "Location disabled in Settings for current user:"
+ + mCurrentUserId);
}
return false;
} else {
// NOTE: If last location is already available, location is not injected. If
- // provider's normal source (like a GPS chipset) have already provided an output,
+ // provider's normal source (like a GPS chipset) have already provided an output
// there is no need to inject this location.
if (mLastLocation.get(provider) == null) {
- updateLastLocationLocked(location, provider);
+ updateLastLocation(location, provider);
} else {
if (D) {
Log.d(TAG, "injectLocation(): Location exists. Not updating");
@@ -2494,8 +2402,8 @@
return false;
}
}
- }
- return true;
+ return true;
+ });
}
@Override
@@ -2504,7 +2412,9 @@
if (request == null) request = DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
- checkPendingIntent(intent);
+ if (intent == null) {
+ throw new IllegalArgumentException("invalid pending intent: " + null);
+ }
checkPackageName(packageName);
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
@@ -2515,7 +2425,10 @@
LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
callerHasLocationHardwarePermission);
- if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
+ if (D) {
+ Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " "
+ + intent);
+ }
// geo-fence manager uses the public location API, need to clear identity
int uid = Binder.getCallingUid();
@@ -2536,7 +2449,9 @@
@Override
public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
- checkPendingIntent(intent);
+ if (intent == null) {
+ throw new IllegalArgumentException("invalid pending intent: " + null);
+ }
checkPackageName(packageName);
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
@@ -2568,14 +2483,14 @@
@Override
public boolean addGnssMeasurementsListener(
- IGnssMeasurementsListener listener, String packageName) {
+ IGnssMeasurementsListener listener, String packageName) throws RemoteException {
if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
return false;
}
- synchronized (mLock) {
- Identity callerIdentity
- = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ Identity callerIdentity =
+ new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ return runFromBinderBlocking(() -> {
// TODO(b/120481270): Register for client death notification and update map.
mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
long identity = Binder.clearCallingIdentity();
@@ -2591,7 +2506,7 @@
}
return true;
- }
+ });
}
@Override
@@ -2619,28 +2534,30 @@
}
@Override
- public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
+ public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener)
+ throws RemoteException {
if (mGnssMeasurementsProvider == null) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
mGnssMeasurementsListeners.remove(listener.asBinder());
mGnssMeasurementsProvider.removeListener(listener);
- }
+ });
}
@Override
public boolean addGnssNavigationMessageListener(
IGnssNavigationMessageListener listener,
- String packageName) {
+ String packageName) throws RemoteException {
if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
return false;
}
- synchronized (mLock) {
- Identity callerIdentity
- = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ Identity callerIdentity =
+ new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+
+ return runFromBinderBlocking(() -> {
// TODO(b/120481270): Register for client death notification and update map.
mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
long identity = Binder.clearCallingIdentity();
@@ -2656,21 +2573,23 @@
}
return true;
- }
+ });
}
@Override
- public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
+ public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener)
+ throws RemoteException {
if (mGnssNavigationMessageProvider != null) {
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
mGnssNavigationMessageListeners.remove(listener.asBinder());
mGnssNavigationMessageProvider.removeListener(listener);
- }
+ });
}
}
@Override
- public boolean sendExtraCommand(String provider, String command, Bundle extras) {
+ public boolean sendExtraCommand(String provider, String command, Bundle extras)
+ throws RemoteException {
if (provider == null) {
// throw NullPointerException to remain compatible with previous implementation
throw new NullPointerException();
@@ -2684,13 +2603,13 @@
throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
}
- synchronized (mLock) {
+ return runFromBinderBlocking(() -> {
LocationProvider p = mProvidersByName.get(provider);
if (p == null) return false;
p.sendExtraCommand(command, extras);
return true;
- }
+ });
}
@Override
@@ -2707,251 +2626,181 @@
}
}
- /**
- * @return null if the provider does not exist
- * @throws SecurityException if the provider is not allowed to be
- * accessed by the caller
- */
@Override
- public ProviderProperties getProviderProperties(String provider) {
+ public ProviderProperties getProviderProperties(String provider) throws RemoteException {
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
- LocationProvider p;
- synchronized (mLock) {
- p = mProvidersByName.get(provider);
- }
-
- if (p == null) return null;
- return p.getProperties();
- }
-
- /**
- * @return null if the provider does not exist
- * @throws SecurityException if the provider is not allowed to be
- * accessed by the caller
- */
- @Override
- public String getNetworkProviderPackage() {
- LocationProvider p;
- synchronized (mLock) {
- p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
- }
-
- if (p == null) {
- return null;
- }
- if (p.mProvider instanceof LocationProviderProxy) {
- return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
- }
- return null;
+ return runFromBinderBlocking(() -> {
+ LocationProvider p = mProvidersByName.get(provider);
+ if (p == null) return null;
+ return p.getProperties();
+ });
}
@Override
- public void setLocationControllerExtraPackage(String packageName) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- Manifest.permission.LOCATION_HARDWARE + " permission required");
- synchronized (mLock) {
- mLocationControllerExtraPackage = packageName;
- }
- }
+ public String getNetworkProviderPackage() throws RemoteException {
+ return runFromBinderBlocking(() -> {
+ LocationProvider p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
- @Override
- public String getLocationControllerExtraPackage() {
- synchronized (mLock) {
- return mLocationControllerExtraPackage;
- }
- }
-
- @Override
- public void setLocationControllerExtraPackageEnabled(boolean enabled) {
- mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
- Manifest.permission.LOCATION_HARDWARE + " permission required");
- synchronized (mLock) {
- mLocationControllerExtraPackageEnabled = enabled;
- }
- }
-
- @Override
- public boolean isLocationControllerExtraPackageEnabled() {
- synchronized (mLock) {
- return mLocationControllerExtraPackageEnabled
- && (mLocationControllerExtraPackage != null);
- }
- }
-
- /**
- * Returns the current location enabled/disabled status for a user
- *
- * @param userId the id of the user
- * @return true if location is enabled
- */
- @Override
- public boolean isLocationEnabledForUser(int userId) {
- // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
- checkInteractAcrossUsersPermission(userId);
-
- long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- final String allowedProviders = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- userId);
- if (allowedProviders == null) {
- return false;
- }
- final List<String> providerList = Arrays.asList(allowedProviders.split(","));
- for (String provider : mRealProviders.keySet()) {
- if (provider.equals(LocationManager.PASSIVE_PROVIDER)
- || provider.equals(LocationManager.FUSED_PROVIDER)) {
- continue;
- }
- if (providerList.contains(provider)) {
- return true;
- }
- }
- return false;
+ if (p == null) {
+ return null;
}
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ if (p.mProvider instanceof LocationProviderProxy) {
+ return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
+ }
+ return null;
+ });
}
- /**
- * Enable or disable location for a user
- *
- * @param enabled true to enable location, false to disable location
- * @param userId the id of the user
- */
@Override
- public void setLocationEnabledForUser(boolean enabled, int userId) {
+ public void setLocationControllerExtraPackage(String packageName) throws RemoteException {
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+ Manifest.permission.LOCATION_HARDWARE + " permission required");
+
+ runFromBinderBlocking(() -> mLocationControllerExtraPackage = packageName);
+ }
+
+ @Override
+ public String getLocationControllerExtraPackage() throws RemoteException {
+ return runFromBinderBlocking(() -> mLocationControllerExtraPackage);
+ }
+
+ @Override
+ public void setLocationControllerExtraPackageEnabled(boolean enabled) throws RemoteException {
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+ Manifest.permission.LOCATION_HARDWARE + " permission required");
+ runFromBinderBlocking(() -> mLocationControllerExtraPackageEnabled = enabled);
+ }
+
+ @Override
+ public boolean isLocationControllerExtraPackageEnabled() throws RemoteException {
+ return runFromBinderBlocking(() -> mLocationControllerExtraPackageEnabled
+ && (mLocationControllerExtraPackage != null));
+ }
+
+ @Override
+ public boolean isLocationEnabledForUser(int userId) throws RemoteException {
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Requires INTERACT_ACROSS_USERS permission");
+ }
+
+ return runFromBinderBlocking(() -> isLocationEnabledForUserInternal(userId));
+ }
+
+ private boolean isLocationEnabledForUserInternal(int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ final String allowedProviders = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ userId);
+ if (allowedProviders == null) {
+ return false;
+ }
+ final List<String> providerList = Arrays.asList(allowedProviders.split(","));
+
+ for (String provider : mRealProviders.keySet()) {
+ if (provider.equals(LocationManager.PASSIVE_PROVIDER)
+ || provider.equals(LocationManager.FUSED_PROVIDER)) {
+ continue;
+ }
+ if (providerList.contains(provider)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void setLocationEnabledForUser(boolean enabled, int userId) throws RemoteException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS,
"Requires WRITE_SECURE_SETTINGS permission");
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
- checkInteractAcrossUsersPermission(userId);
-
- long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- final Set<String> allRealProviders = mRealProviders.keySet();
- // Update all providers on device plus gps and network provider when disabling
- // location
- Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
- allProvidersSet.addAll(allRealProviders);
- // When disabling location, disable gps and network provider that could have been
- // enabled by location mode api.
- if (!enabled) {
- allProvidersSet.add(LocationManager.GPS_PROVIDER);
- allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
- }
- if (allProvidersSet.isEmpty()) {
- return;
- }
- // to ensure thread safety, we write the provider name with a '+' or '-'
- // and let the SettingsProvider handle it rather than reading and modifying
- // the list of enabled providers.
- final String prefix = enabled ? "+" : "-";
- StringBuilder locationProvidersAllowed = new StringBuilder();
- for (String provider : allProvidersSet) {
- if (provider.equals(LocationManager.PASSIVE_PROVIDER)
- || provider.equals(LocationManager.FUSED_PROVIDER)) {
- continue;
- }
- locationProvidersAllowed.append(prefix);
- locationProvidersAllowed.append(provider);
- locationProvidersAllowed.append(",");
- }
- // Remove the trailing comma
- locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- locationProvidersAllowed.toString(),
- userId);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Requires INTERACT_ACROSS_USERS permission");
}
+
+ runFromBinderBlocking(() -> {
+ final Set<String> allRealProviders = mRealProviders.keySet();
+ // Update all providers on device plus gps and network provider when disabling
+ // location
+ Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
+ allProvidersSet.addAll(allRealProviders);
+ // When disabling location, disable gps and network provider that could have been
+ // enabled by location mode api.
+ if (!enabled) {
+ allProvidersSet.add(LocationManager.GPS_PROVIDER);
+ allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
+ }
+ if (allProvidersSet.isEmpty()) {
+ return;
+ }
+ // to ensure thread safety, we write the provider name with a '+' or '-'
+ // and let the SettingsProvider handle it rather than reading and modifying
+ // the list of enabled providers.
+ final String prefix = enabled ? "+" : "-";
+ StringBuilder locationProvidersAllowed = new StringBuilder();
+ for (String provider : allProvidersSet) {
+ if (provider.equals(LocationManager.PASSIVE_PROVIDER)
+ || provider.equals(LocationManager.FUSED_PROVIDER)) {
+ continue;
+ }
+ locationProvidersAllowed.append(prefix);
+ locationProvidersAllowed.append(provider);
+ locationProvidersAllowed.append(",");
+ }
+ // Remove the trailing comma
+ locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ locationProvidersAllowed.toString(),
+ userId);
+ });
}
- /**
- * Returns the current enabled/disabled status of a location provider and user
- *
- * @param providerName name of the provider
- * @param userId the id of the user
- * @return true if the provider exists and is enabled
- */
@Override
- public boolean isProviderEnabledForUser(String providerName, int userId) {
+ public boolean isProviderEnabledForUser(String providerName, int userId)
+ throws RemoteException {
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
- checkInteractAcrossUsersPermission(userId);
-
- if (!isLocationEnabledForUser(userId)) {
- return false;
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Requires INTERACT_ACROSS_USERS permission");
}
// Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
// so we discourage its use
if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
- long identity = Binder.clearCallingIdentity();
- try {
- LocationProvider provider;
- synchronized (mLock) {
- provider = mProvidersByName.get(providerName);
- }
- return provider != null && provider.isEnabled();
- } finally {
- Binder.restoreCallingIdentity(identity);
+ if (!isLocationEnabledForUser(userId)) {
+ return false;
}
+
+ return runFromBinderBlocking(() -> {
+ LocationProvider provider = mProvidersByName.get(providerName);
+ return provider != null && provider.isEnabled();
+ });
}
- /**
- * Enable or disable a single location provider.
- *
- * @param provider name of the provider
- * @param enabled true to enable the provider. False to disable the provider
- * @param userId the id of the user to set
- * @return true if the value was set, false on errors
- */
@Override
public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
return false;
}
- /**
- * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
- * current user id
- *
- * @param userId the user id to get or set value
- */
- private void checkInteractAcrossUsersPermission(int userId) {
- int uid = Binder.getCallingUid();
- if (UserHandle.getUserId(uid) != userId) {
- if (ActivityManager.checkComponentPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
- }
- }
- }
-
- /**
- * Returns "true" if the UID belongs to a bound location provider.
- *
- * @param uid the uid
- * @return true if uid belongs to a bound location provider
- */
private boolean isUidALocationProvider(int uid) {
if (uid == Process.SYSTEM_UID) {
return true;
}
- if (mGeocodeProvider != null) {
- if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
- }
+
for (LocationProviderProxy proxy : mProxyProviders) {
if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
}
@@ -2970,7 +2819,6 @@
// providers installed oustide the system image. So
// also allow providers with a UID matching the
// currently bound package name
-
if (isUidALocationProvider(Binder.getCallingUid())) {
return;
}
@@ -2979,9 +2827,6 @@
"or UID of a currently bound location provider");
}
- /**
- * Returns true if the given package belongs to the given uid.
- */
private boolean doesUidHavePackage(int uid, String packageName) {
if (packageName == null) {
return false;
@@ -2998,22 +2843,12 @@
return false;
}
+ // TODO: will be removed in future
@Override
public void reportLocation(Location location, boolean passive) {
- checkCallerIsProvider();
-
- if (!location.isComplete()) {
- Log.w(TAG, "Dropping incomplete location: " + location);
- return;
- }
-
- mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
- Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
- m.arg1 = (passive ? 1 : 0);
- mLocationHandler.sendMessageAtFrontOfQueue(m);
+ throw new IllegalStateException("operation unsupported");
}
-
private static boolean shouldBroadcastSafe(
Location loc, Location lastLoc, UpdateRecord record, long now) {
// Always broadcast the first update
@@ -3046,14 +2881,33 @@
return record.mRealRequest.getExpireAt() >= now;
}
- private void handleLocationChangedLocked(Location location, boolean passive) {
- if (D) Log.d(TAG, "incoming location: " + location);
+ private void handleLocationChanged(Location location, boolean passive) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ // create a working copy of the incoming Location so that the service can modify it without
+ // disturbing the caller's copy
+ Location myLocation = new Location(location);
+ String pr = myLocation.getProvider();
+
+ // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
+ // bit if location did not come from a mock provider because passive/fused providers can
+ // forward locations from mock providers, and should not grant them legitimacy in doing so.
+ if (!myLocation.isFromMockProvider() && isMockProvider(pr)) {
+ myLocation.setIsFromMockProvider(true);
+ }
+
+ if (!passive) {
+ // notify passive provider of the new location
+ mPassiveProvider.updateLocation(myLocation);
+ }
+
+ if (D) Log.d(TAG, "incoming location: " + myLocation);
long now = SystemClock.elapsedRealtime();
- String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
+ String provider = (passive ? LocationManager.PASSIVE_PROVIDER : myLocation.getProvider());
// Skip if the provider is unknown.
LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
- updateLastLocationLocked(location, provider);
+ updateLastLocation(myLocation, provider);
// mLastLocation should have been updated from the updateLastLocationLocked call above.
Location lastLocation = mLastLocation.get(provider);
if (lastLocation == null) {
@@ -3064,13 +2918,13 @@
// Update last known coarse interval location if enough time has passed.
Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
if (lastLocationCoarseInterval == null) {
- lastLocationCoarseInterval = new Location(location);
+ lastLocationCoarseInterval = new Location(myLocation);
mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
}
- long timeDiffNanos = location.getElapsedRealtimeNanos()
+ long timeDiffNanos = myLocation.getElapsedRealtimeNanos()
- lastLocationCoarseInterval.getElapsedRealtimeNanos();
if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
- lastLocationCoarseInterval.set(location);
+ lastLocationCoarseInterval.set(myLocation);
}
// Don't ever return a coarse location that is more recent than the allowed update
// interval (i.e. don't allow an app to keep registering and unregistering for
@@ -3194,24 +3048,20 @@
// remove dead records and receivers outside the loop
if (deadReceivers != null) {
for (Receiver receiver : deadReceivers) {
- removeUpdatesLocked(receiver);
+ removeUpdates(receiver);
}
}
if (deadUpdateRecords != null) {
for (UpdateRecord r : deadUpdateRecords) {
r.disposeLocked(true);
}
- applyRequirementsLocked(provider);
+ applyRequirements(provider);
}
}
- /**
- * Updates last location with the given location
- *
- * @param location new location to update
- * @param provider Location provider to update for
- */
- private void updateLastLocationLocked(Location location, String provider) {
+ private void updateLastLocation(Location location, String provider) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
Location lastNoGPSLocation;
Location lastLocation = mLastLocation.get(provider);
@@ -3229,75 +3079,11 @@
lastLocation.set(location);
}
- private class LocationWorkerHandler extends Handler {
- public LocationWorkerHandler(Looper looper) {
- super(looper, null, true);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_LOCATION_CHANGED:
- handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
- break;
- }
- }
- }
-
private boolean isMockProvider(String provider) {
- synchronized (mLock) {
- return mMockProviders.containsKey(provider);
- }
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ return mMockProviders.containsKey(provider);
}
- private void handleLocationChanged(Location location, boolean passive) {
- // create a working copy of the incoming Location so that the service can modify it without
- // disturbing the caller's copy
- Location myLocation = new Location(location);
- String provider = myLocation.getProvider();
-
- // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
- // bit if location did not come from a mock provider because passive/fused providers can
- // forward locations from mock providers, and should not grant them legitimacy in doing so.
- if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
- myLocation.setIsFromMockProvider(true);
- }
-
- synchronized (mLock) {
- if (!passive) {
- // notify passive provider of the new location
- mPassiveProvider.updateLocation(myLocation);
- }
- handleLocationChangedLocked(myLocation, passive);
- }
- }
-
- private final PackageMonitor mPackageMonitor = new PackageMonitor() {
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
- // remove all receivers associated with this package name
- synchronized (mLock) {
- ArrayList<Receiver> deadReceivers = null;
-
- for (Receiver receiver : mReceivers.values()) {
- if (receiver.mIdentity.mPackageName.equals(packageName)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<>();
- }
- deadReceivers.add(receiver);
- }
- }
-
- // perform removal outside of mReceivers loop
- if (deadReceivers != null) {
- for (Receiver receiver : deadReceivers) {
- removeUpdatesLocked(receiver);
- }
- }
- }
- }
- };
-
// Geocoder
@Override
@@ -3338,7 +3124,8 @@
}
@Override
- public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
+ public void addTestProvider(String name, ProviderProperties properties, String opPackageName)
+ throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
@@ -3347,23 +3134,24 @@
throw new IllegalArgumentException("Cannot mock the passive location provider");
}
- long identity = Binder.clearCallingIdentity();
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
// remove the real provider if we are replacing GPS or network provider
if (LocationManager.GPS_PROVIDER.equals(name)
|| LocationManager.NETWORK_PROVIDER.equals(name)
|| LocationManager.FUSED_PROVIDER.equals(name)) {
LocationProvider p = mProvidersByName.get(name);
if (p != null) {
- removeProviderLocked(p);
+ removeProvider(p);
}
}
- addTestProviderLocked(name, properties);
- }
- Binder.restoreCallingIdentity(identity);
+ addTestProvider(name, properties);
+ return null;
+ });
}
- private void addTestProviderLocked(String name, ProviderProperties properties) {
+ private void addTestProvider(String name, ProviderProperties properties) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
if (mProvidersByName.get(name) != null) {
throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
}
@@ -3371,122 +3159,103 @@
LocationProvider provider = new LocationProvider(name);
MockProvider mockProvider = new MockProvider(provider, properties);
- addProviderLocked(provider);
+ addProvider(provider);
mMockProviders.put(name, mockProvider);
mLastLocation.put(name, null);
mLastLocationCoarseInterval.put(name, null);
}
@Override
- public void removeTestProvider(String provider, String opPackageName) {
+ public void removeTestProvider(String provider, String opPackageName) throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
MockProvider mockProvider = mMockProviders.remove(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
- long identity = Binder.clearCallingIdentity();
- try {
- removeProviderLocked(mProvidersByName.get(provider));
+ removeProvider(mProvidersByName.get(provider));
- // reinstate real provider if available
- LocationProvider realProvider = mRealProviders.get(provider);
- if (realProvider != null) {
- addProviderLocked(realProvider);
- }
- mLastLocation.put(provider, null);
- mLastLocationCoarseInterval.put(provider, null);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ // reinstate real provider if available
+ LocationProvider realProvider = mRealProviders.get(provider);
+ if (realProvider != null) {
+ addProvider(realProvider);
}
- }
+ mLastLocation.put(provider, null);
+ mLastLocationCoarseInterval.put(provider, null);
+ });
}
@Override
- public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
+ public void setTestProviderLocation(String provider, Location loc, String opPackageName)
+ throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
- // Ensure that the location is marked as being mock. There's some logic to do this in
- // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
+ // Ensure that the location is marked as being mock. There's some logic to do this
+ // in handleLocationChanged(), but it fails if loc has the wrong provider
+ // (b/33091107).
Location mock = new Location(loc);
mock.setIsFromMockProvider(true);
if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
- // The location has an explicit provider that is different from the mock provider
- // name. The caller may be trying to fool us via bug 33091107.
+ // The location has an explicit provider that is different from the mock
+ // provider name. The caller may be trying to fool us via bug 33091107.
EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
provider + "!=" + loc.getProvider());
}
- // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
- long identity = Binder.clearCallingIdentity();
- try {
- mockProvider.setLocation(mock);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ mockProvider.setLocation(mock);
+ });
}
@Override
- public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
+ public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName)
+ throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
- long identity = Binder.clearCallingIdentity();
- try {
- mockProvider.setEnabled(enabled);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ mockProvider.setEnabled(enabled);
+ });
}
@Override
public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
- String opPackageName) {
+ String opPackageName) throws RemoteException {
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- synchronized (mLock) {
+ runFromBinderBlocking(() -> {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
mockProvider.setStatus(status, extras, updateTime);
- }
- }
-
- private void log(String log) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Slog.d(TAG, log);
- }
+ });
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- synchronized (mLock) {
+ Runnable dump = () -> {
if (args.length > 0 && args[0].equals("--gnssmetrics")) {
if (mGnssMetricsProvider != null) {
pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
@@ -3579,6 +3348,14 @@
if (mGnssBatchingInProgress) {
pw.println(" GNSS batching in progress");
}
+ };
+
+ FutureTask<Void> task = new FutureTask<>(dump, null);
+ mHandler.postAtFrontOfQueue(task);
+ try {
+ task.get();
+ } catch (InterruptedException | ExecutionException e) {
+ pw.println("error dumping: " + e);
}
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 88d73fb..c222e69 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -767,6 +767,23 @@
return installed;
}
+ protected Set<String> getAllowedPackages() {
+ final Set<String> allowedPackages = new ArraySet<>();
+ for (int k = 0; k < mApproved.size(); k++) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ String pkgName = getPackageName(allowed.valueAt(j));
+ if (!TextUtils.isEmpty(pkgName)) {
+ allowedPackages.add(pkgName);
+ }
+ }
+ }
+ }
+ return allowedPackages;
+ }
+
private void trimApprovedListsAccordingToInstalledServices() {
int N = mApproved.size();
for (int i = 0 ; i < N; i++) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4f21db1..c68e0f9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1701,8 +1701,16 @@
}
private void sendRegisteredOnlyBroadcast(String action) {
- getContext().sendBroadcastAsUser(new Intent(action)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
+ Intent intent = new Intent(action);
+ getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+ UserHandle.ALL, null);
+ // explicitly send the broadcast to all DND packages, even if they aren't currently running
+ intent.setFlags(0);
+ final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages();
+ for (String pkg : dndApprovedPackages) {
+ intent.setPackage(pkg);
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index e5b1878..afc0b72 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -375,8 +375,7 @@
newConfig = mConfig.copy();
for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
- if (rule.component.getPackageName().equals(packageName)
- && canManageAutomaticZenRule(rule)) {
+ if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) {
newConfig.automaticRules.removeAt(i);
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index fe0b5c2..caebf15 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1066,93 +1066,19 @@
final int visibleWindowCount = visibleWindows.size();
HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
- for (int i = visibleWindowCount - 1; i >= 0; i--) {
+
+ // Iterate until we figure out what is touchable for the entire screen.
+ for (int i = visibleWindowCount - 1; i >= 0 && !unaccountedSpace.isEmpty(); i--) {
final WindowState windowState = visibleWindows.valueAt(i);
- final int flags = windowState.mAttrs.flags;
- final Task task = windowState.getTask();
- // If the window is part of a task that we're finished with - ignore.
- if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
- continue;
- }
-
- // Ignore non-touchable windows, except the split-screen divider, which is
- // occasionally non-touchable but still useful for identifying split-screen
- // mode.
- if (((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
- && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
- continue;
- }
-
- // Compute the bounds in the screen.
final Rect boundsInScreen = mTempRect;
computeWindowBoundsInScreen(windowState, boundsInScreen);
- // If the window is completely covered by other windows - ignore.
- if (unaccountedSpace.quickReject(boundsInScreen)) {
- continue;
- }
-
- // Add windows of certain types not covered by modal windows.
- if (isReportedWindowType(windowState.mAttrs.type)) {
- // Add the window to the ones to be reported.
+ if (windowMattersToAccessibility(windowState, boundsInScreen, unaccountedSpace,
+ skipRemainingWindowsForTasks)) {
addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows);
- if (windowState.isFocused()) {
- focusedWindowAdded = true;
- }
- }
-
- if (windowState.mAttrs.type !=
- WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
-
- // Account for the space this window takes if the window
- // is not an accessibility overlay which does not change
- // the reported windows.
- unaccountedSpace.op(boundsInScreen, unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
-
- // If a window is modal it prevents other windows from being touched
- if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
- // Account for all space in the task, whether the windows in it are
- // touchable or not. The modal window blocks all touches from the task's
- // area.
- unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
-
- if (task != null) {
- // If the window is associated with a particular task, we can skip the
- // rest of the windows for that task.
- skipRemainingWindowsForTasks.add(task.mTaskId);
- continue;
- } else {
- // If the window is not associated with a particular task, then it is
- // globally modal. In this case we can skip all remaining windows.
- break;
- }
- }
- }
-
- // We figured out what is touchable for the entire screen - done.
- if (unaccountedSpace.isEmpty()) {
- break;
- }
- }
-
- // Always report the focused window.
- if (!focusedWindowAdded) {
- for (int i = visibleWindowCount - 1; i >= 0; i--) {
- WindowState windowState = visibleWindows.valueAt(i);
- if (windowState.isFocused()) {
- // Compute the bounds in the screen.
- Rect boundsInScreen = mTempRect;
- computeWindowBoundsInScreen(windowState, boundsInScreen);
-
- // Add the window to the ones to be reported.
- addPopulatedWindowInfo(
- windowState, boundsInScreen, windows, addedWindows);
- break;
- }
+ updateUnaccountedSpace(windowState, boundsInScreen, unaccountedSpace,
+ skipRemainingWindowsForTasks);
}
}
@@ -1221,6 +1147,73 @@
clearAndRecycleWindows(windows);
}
+ private boolean windowMattersToAccessibility(WindowState windowState, Rect boundsInScreen,
+ Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
+ if (windowState.isFocused()) {
+ return true;
+ }
+
+ // If the window is part of a task that we're finished with - ignore.
+ final Task task = windowState.getTask();
+ if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
+ return false;
+ }
+
+ // Ignore non-touchable windows, except the split-screen divider, which is
+ // occasionally non-touchable but still useful for identifying split-screen
+ // mode.
+ if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
+ && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
+ return false;
+ }
+
+ // If the window is completely covered by other windows - ignore.
+ if (unaccountedSpace.quickReject(boundsInScreen)) {
+ return false;
+ }
+
+ // Add windows of certain types not covered by modal windows.
+ if (isReportedWindowType(windowState.mAttrs.type)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void updateUnaccountedSpace(WindowState windowState, Rect boundsInScreen,
+ Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
+ if (windowState.mAttrs.type
+ != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
+
+ // Account for the space this window takes if the window
+ // is not an accessibility overlay which does not change
+ // the reported windows.
+ unaccountedSpace.op(boundsInScreen, unaccountedSpace,
+ Region.Op.REVERSE_DIFFERENCE);
+
+ // If a window is modal it prevents other windows from being touched
+ if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
+ // Account for all space in the task, whether the windows in it are
+ // touchable or not. The modal window blocks all touches from the task's
+ // area.
+ unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
+ Region.Op.REVERSE_DIFFERENCE);
+
+ final Task task = windowState.getTask();
+ if (task != null) {
+ // If the window is associated with a particular task, we can skip the
+ // rest of the windows for that task.
+ skipRemainingWindowsForTasks.add(task.mTaskId);
+ } else {
+ // If the window is not associated with a particular task, then it is
+ // globally modal. In this case we can skip all remaining windows.
+ unaccountedSpace.setEmpty();
+ }
+ }
+ }
+ }
+
private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
// Get the touchable frame.
Region touchableRegion = mTempRegion1;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8884615..6f8f85f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -728,9 +728,10 @@
mLastReportedMultiWindowMode = inPictureInPictureMode;
final Configuration newConfig = new Configuration();
if (targetStackBounds != null && !targetStackBounds.isEmpty()) {
- task.computeResolvedOverrideConfiguration(newConfig,
- task.getParent().getConfiguration(),
- task.getRequestedOverrideConfiguration());
+ newConfig.setTo(task.getRequestedOverrideConfiguration());
+ Rect outBounds = newConfig.windowConfiguration.getBounds();
+ task.adjustForMinimalTaskDimensions(outBounds, outBounds);
+ task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration());
}
schedulePictureInPictureModeChanged(newConfig);
scheduleMultiWindowModeChanged(newConfig);
@@ -2503,7 +2504,8 @@
return;
}
- final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
+ final IBinder binder =
+ (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null;
mAppWindowToken.setOrientation(requestedOrientation, binder, this);
}
@@ -2547,7 +2549,6 @@
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
private void updateOverrideConfiguration() {
- mTmpConfig.unset();
computeBounds(mTmpBounds);
if (mTmpBounds.equals(getRequestedOverrideBounds())) {
@@ -2558,8 +2559,10 @@
// Bounds changed...update configuration to match.
if (!matchParentBounds()) {
- task.computeResolvedOverrideConfiguration(mTmpConfig,
- task.getParent().getConfiguration(), getRequestedOverrideConfiguration());
+ mTmpConfig.setTo(getRequestedOverrideConfiguration());
+ task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration());
+ } else {
+ mTmpConfig.unset();
}
onRequestedOverrideConfigurationChanged(mTmpConfig);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fecc8da..740d472 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3656,6 +3656,12 @@
}
}
+ /** @returns the orientation of the display when it's rotation is ROTATION_0. */
+ int getNaturalOrientation() {
+ return mBaseDisplayWidth < mBaseDisplayHeight
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+ }
+
void performLayout(boolean initial, boolean updateInputWindows) {
if (!isLayoutNeeded()) {
return;
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index e343322..1d56f04 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -44,6 +44,9 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -1259,10 +1262,6 @@
setFrontOfTask();
}
- void addActivityAtBottom(ActivityRecord r) {
- addActivityAtIndex(0, r);
- }
-
void addActivityToTop(ActivityRecord r) {
addActivityAtIndex(mActivities.size(), r);
}
@@ -1278,6 +1277,34 @@
}
/**
+ * Checks if the root activity requires a particular orientation (either by override or
+ * activityInfo) and returns that. Otherwise, this returns ORIENTATION_UNDEFINED.
+ */
+ private int getRootActivityRequestedOrientation() {
+ ActivityRecord root = getRootActivity();
+ if (getRequestedOverrideConfiguration().orientation != ORIENTATION_UNDEFINED
+ || root == null) {
+ return getRequestedOverrideConfiguration().orientation;
+ }
+ int rootScreenOrientation = root.getOrientation();
+ if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+ // NOSENSOR means the display's "natural" orientation, so return that.
+ ActivityDisplay display = mStack != null ? mStack.getDisplay() : null;
+ if (display != null && display.mDisplayContent != null) {
+ return mStack.getDisplay().mDisplayContent.getNaturalOrientation();
+ }
+ } else if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+ // LOCKED means the activity's orientation remains unchanged, so return existing value.
+ return root.getConfiguration().orientation;
+ } else if (ActivityInfo.isFixedOrientationLandscape(rootScreenOrientation)) {
+ return ORIENTATION_LANDSCAPE;
+ } else if (ActivityInfo.isFixedOrientationPortrait(rootScreenOrientation)) {
+ return ORIENTATION_PORTRAIT;
+ }
+ return ORIENTATION_UNDEFINED;
+ }
+
+ /**
* Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either
* be in the current task or unparented to any task.
*/
@@ -1741,7 +1768,7 @@
updateTaskDescription();
}
- private void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
+ void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
if (bounds == null) {
return;
}
@@ -1853,11 +1880,27 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
+ // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
+ // restore the last recorded non-fullscreen bounds.
+ final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
+ final boolean nextPersistTaskBounds =
+ getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
+ || newParentConfig.windowConfiguration.persistTaskBounds();
+ if (!prevPersistTaskBounds && nextPersistTaskBounds
+ && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
+ // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
+ getRequestedOverrideConfiguration().windowConfiguration
+ .setBounds(mLastNonFullscreenBounds);
+ }
+
final boolean wasInMultiWindowMode = inMultiWindowMode();
super.onConfigurationChanged(newParentConfig);
if (wasInMultiWindowMode != inMultiWindowMode()) {
mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
}
+
+ // If the configuration supports persistent bounds (eg. Freeform), keep track of the
+ // current (non-fullscreen) bounds for persistence.
if (getWindowConfiguration().persistTaskBounds()) {
final Rect currentBounds = getRequestedOverrideBounds();
if (!currentBounds.isEmpty()) {
@@ -2047,7 +2090,7 @@
* configuring an "inherit-bounds" window which means that all configuration settings would
* just be inherited from the parent configuration.
**/
- void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Rect bounds,
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
@@ -2060,6 +2103,7 @@
}
density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ final Rect bounds = inOutConfig.windowConfiguration.getBounds();
Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
if (outAppBounds == null || outAppBounds.isEmpty()) {
inOutConfig.windowConfiguration.setAppBounds(bounds);
@@ -2107,13 +2151,14 @@
// Iterating across all screen orientations, and return the minimum of the task
// width taking into account that the bounds might change because the snap
// algorithm snaps to a different value
- getSmallestScreenWidthDpForDockedBounds(bounds);
+ inOutConfig.smallestScreenWidthDp =
+ getSmallestScreenWidthDpForDockedBounds(bounds);
}
// otherwise, it will just inherit
}
}
- if (inOutConfig.orientation == Configuration.ORIENTATION_UNDEFINED) {
+ if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
}
@@ -2134,36 +2179,56 @@
}
}
- // TODO(b/113900640): remove this once ActivityRecord is changed to not need it anymore.
- void computeResolvedOverrideConfiguration(Configuration inOutConfig, Configuration parentConfig,
- Configuration overrideConfig) {
- // Save previous bounds because adjustForMinimalTaskDimensions uses that to determine if it
- // changes left bound vs. right bound, or top bound vs. bottom bound.
- mTmpBounds.set(inOutConfig.windowConfiguration.getBounds());
-
- inOutConfig.setTo(overrideConfig);
-
- Rect outOverrideBounds = inOutConfig.windowConfiguration.getBounds();
- if (outOverrideBounds != null && !outOverrideBounds.isEmpty()) {
- adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
-
- int windowingMode = overrideConfig.windowConfiguration.getWindowingMode();
- if (windowingMode == WINDOWING_MODE_UNDEFINED) {
- windowingMode = parentConfig.windowConfiguration.getWindowingMode();
- }
- if (windowingMode == WINDOWING_MODE_FREEFORM) {
- // by policy, make sure the window remains within parent
- fitWithinBounds(outOverrideBounds, parentConfig.windowConfiguration.getBounds());
- }
-
- computeConfigResourceOverrides(inOutConfig, outOverrideBounds, parentConfig);
- }
- }
-
@Override
void resolveOverrideConfiguration(Configuration newParentConfig) {
- computeResolvedOverrideConfiguration(getResolvedOverrideConfiguration(), newParentConfig,
- getRequestedOverrideConfiguration());
+ mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
+ super.resolveOverrideConfiguration(newParentConfig);
+ int windowingMode =
+ getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
+ }
+ Rect outOverrideBounds =
+ getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent"
+ outOverrideBounds.setEmpty();
+
+ // If the task or its root activity require a different orientation, make it fit the
+ // available bounds by scaling down its bounds.
+ int forcedOrientation = getRootActivityRequestedOrientation();
+ if (forcedOrientation != ORIENTATION_UNDEFINED
+ && forcedOrientation != newParentConfig.orientation) {
+ final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
+ final int parentWidth = parentBounds.width();
+ final int parentHeight = parentBounds.height();
+ final float aspect = ((float) parentHeight) / parentWidth;
+ if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+ final int height = (int) (parentWidth / aspect);
+ final int top = parentBounds.centerY() - height / 2;
+ outOverrideBounds.set(
+ parentBounds.left, top, parentBounds.right, top + height);
+ } else {
+ final int width = (int) (parentHeight * aspect);
+ final int left = parentBounds.centerX() - width / 2;
+ outOverrideBounds.set(
+ left, parentBounds.top, left + width, parentBounds.bottom);
+ }
+ }
+ }
+
+ if (outOverrideBounds.isEmpty()) {
+ // If the task fills the parent, just inherit all the other configs from parent.
+ return;
+ }
+
+ adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
+ if (windowingMode == WINDOWING_MODE_FREEFORM) {
+ // by policy, make sure the window remains within parent somewhere
+ fitWithinBounds(outOverrideBounds, newParentConfig.windowConfiguration.getBounds());
+ }
+ computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
}
Rect updateOverrideConfigurationFromLaunchBounds() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index be09aea..4326c39 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -145,6 +145,7 @@
import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowManagerGlobalLock;
import com.android.server.wm.WindowManagerService;
+import com.google.android.startop.iorap.IorapForwardingService;
import dalvik.system.VMRuntime;
@@ -1007,10 +1008,13 @@
mSystemServiceManager.startService(PinnerService.class);
traceEnd();
+ traceBeginAndSlog("IorapForwardingService");
+ mSystemServiceManager.startService(IorapForwardingService.class);
+ traceEnd();
+
traceBeginAndSlog("SignedConfigService");
SignedConfigService.registerUpdateReceiver(mSystemContext);
traceEnd();
-
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
diff --git a/services/net/java/android/net/dhcp/DhcpServingParams.java b/services/net/java/android/net/dhcp/DhcpServingParams.java
index df15ba1..2780814a 100644
--- a/services/net/java/android/net/dhcp/DhcpServingParams.java
+++ b/services/net/java/android/net/dhcp/DhcpServingParams.java
@@ -17,6 +17,7 @@
package android.net.dhcp;
import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
+import static android.net.NetworkUtils.intToInet4AddressHTH;
import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
@@ -24,6 +25,7 @@
import static java.lang.Integer.toUnsignedLong;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.NetworkUtils;
@@ -103,6 +105,37 @@
this.metered = metered;
}
+ /**
+ * Create parameters from a stable AIDL-compatible parcel.
+ */
+ public static DhcpServingParams fromParcelableObject(@NonNull DhcpServingParamsParcel parcel)
+ throws InvalidParameterException {
+ final LinkAddress serverAddr = new LinkAddress(
+ intToInet4AddressHTH(parcel.serverAddr),
+ parcel.serverAddrPrefixLength);
+ return new Builder()
+ .setServerAddr(serverAddr)
+ .setDefaultRouters(toInet4AddressSet(parcel.defaultRouters))
+ .setDnsServers(toInet4AddressSet(parcel.dnsServers))
+ .setExcludedAddrs(toInet4AddressSet(parcel.excludedAddrs))
+ .setDhcpLeaseTimeSecs(parcel.dhcpLeaseTimeSecs)
+ .setLinkMtu(parcel.linkMtu)
+ .setMetered(parcel.metered)
+ .build();
+ }
+
+ private static Set<Inet4Address> toInet4AddressSet(@Nullable int[] addrs) {
+ if (addrs == null) {
+ return new HashSet<>(0);
+ }
+
+ final HashSet<Inet4Address> res = new HashSet<>();
+ for (int addr : addrs) {
+ res.add(intToInet4AddressHTH(addr));
+ }
+ return res;
+ }
+
@NonNull
public Inet4Address getServerInet4Addr() {
return (Inet4Address) serverAddr.getAddress();
@@ -134,13 +167,13 @@
* of the parameters.
*/
public static class Builder {
- private LinkAddress serverAddr;
- private Set<Inet4Address> defaultRouters;
- private Set<Inet4Address> dnsServers;
- private Set<Inet4Address> excludedAddrs;
- private long dhcpLeaseTimeSecs;
- private int linkMtu = MTU_UNSET;
- private boolean metered;
+ private LinkAddress mServerAddr;
+ private Set<Inet4Address> mDefaultRouters;
+ private Set<Inet4Address> mDnsServers;
+ private Set<Inet4Address> mExcludedAddrs;
+ private long mDhcpLeaseTimeSecs;
+ private int mLinkMtu = MTU_UNSET;
+ private boolean mMetered;
/**
* Set the server address and served prefix for the DHCP server.
@@ -148,7 +181,7 @@
* <p>This parameter is required.
*/
public Builder setServerAddr(@NonNull LinkAddress serverAddr) {
- this.serverAddr = serverAddr;
+ this.mServerAddr = serverAddr;
return this;
}
@@ -159,7 +192,7 @@
* always be set explicitly before building the {@link DhcpServingParams}.
*/
public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
- this.defaultRouters = defaultRouters;
+ this.mDefaultRouters = defaultRouters;
return this;
}
@@ -189,7 +222,7 @@
* {@link DhcpServingParams}.
*/
public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
- this.dnsServers = dnsServers;
+ this.mDnsServers = dnsServers;
return this;
}
@@ -219,7 +252,7 @@
* and do not need to be set here.
*/
public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
- this.excludedAddrs = excludedAddrs;
+ this.mExcludedAddrs = excludedAddrs;
return this;
}
@@ -239,7 +272,7 @@
* <p>This parameter is required.
*/
public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
- this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
+ this.mDhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
return this;
}
@@ -250,7 +283,7 @@
* is optional and defaults to {@link #MTU_UNSET}.
*/
public Builder setLinkMtu(int linkMtu) {
- this.linkMtu = linkMtu;
+ this.mLinkMtu = linkMtu;
return this;
}
@@ -260,7 +293,7 @@
* <p>If not set, the default value is false.
*/
public Builder setMetered(boolean metered) {
- this.metered = metered;
+ this.mMetered = metered;
return this;
}
@@ -274,54 +307,57 @@
*/
@NonNull
public DhcpServingParams build() throws InvalidParameterException {
- if (serverAddr == null) {
+ if (mServerAddr == null) {
throw new InvalidParameterException("Missing serverAddr");
}
- if (defaultRouters == null) {
+ if (mDefaultRouters == null) {
throw new InvalidParameterException("Missing defaultRouters");
}
- if (dnsServers == null) {
+ if (mDnsServers == null) {
// Empty set is OK, but enforce explicitly setting it
throw new InvalidParameterException("Missing dnsServers");
}
- if (dhcpLeaseTimeSecs <= 0 || dhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
- throw new InvalidParameterException("Invalid lease time: " + dhcpLeaseTimeSecs);
+ if (mDhcpLeaseTimeSecs <= 0 || mDhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
+ throw new InvalidParameterException("Invalid lease time: " + mDhcpLeaseTimeSecs);
}
- if (linkMtu != MTU_UNSET && (linkMtu < IPV4_MIN_MTU || linkMtu > IPV4_MAX_MTU)) {
- throw new InvalidParameterException("Invalid link MTU: " + linkMtu);
+ if (mLinkMtu != MTU_UNSET && (mLinkMtu < IPV4_MIN_MTU || mLinkMtu > IPV4_MAX_MTU)) {
+ throw new InvalidParameterException("Invalid link MTU: " + mLinkMtu);
}
- if (!serverAddr.isIPv4()) {
+ if (!mServerAddr.isIPv4()) {
throw new InvalidParameterException("serverAddr must be IPv4");
}
- if (serverAddr.getPrefixLength() < MIN_PREFIX_LENGTH
- || serverAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
+ if (mServerAddr.getPrefixLength() < MIN_PREFIX_LENGTH
+ || mServerAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
throw new InvalidParameterException("Prefix length is not in supported range");
}
- final IpPrefix prefix = makeIpPrefix(serverAddr);
- for (Inet4Address addr : defaultRouters) {
+ final IpPrefix prefix = makeIpPrefix(mServerAddr);
+ for (Inet4Address addr : mDefaultRouters) {
if (!prefix.contains(addr)) {
throw new InvalidParameterException(String.format(
- "Default router %s is not in server prefix %s", addr, serverAddr));
+ "Default router %s is not in server prefix %s", addr, mServerAddr));
}
}
final Set<Inet4Address> excl = new HashSet<>();
- if (excludedAddrs != null) {
- excl.addAll(excludedAddrs);
+ if (mExcludedAddrs != null) {
+ excl.addAll(mExcludedAddrs);
}
- excl.add((Inet4Address) serverAddr.getAddress());
- excl.addAll(defaultRouters);
- excl.addAll(dnsServers);
+ excl.add((Inet4Address) mServerAddr.getAddress());
+ excl.addAll(mDefaultRouters);
+ excl.addAll(mDnsServers);
- return new DhcpServingParams(serverAddr,
- Collections.unmodifiableSet(new HashSet<>(defaultRouters)),
- Collections.unmodifiableSet(new HashSet<>(dnsServers)),
+ return new DhcpServingParams(mServerAddr,
+ Collections.unmodifiableSet(new HashSet<>(mDefaultRouters)),
+ Collections.unmodifiableSet(new HashSet<>(mDnsServers)),
Collections.unmodifiableSet(excl),
- dhcpLeaseTimeSecs, linkMtu, metered);
+ mDhcpLeaseTimeSecs, mLinkMtu, mMetered);
}
}
+ /**
+ * Utility method to create an IpPrefix with the address and prefix length of a LinkAddress.
+ */
@NonNull
static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) {
return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
new file mode 100644
index 0000000..f068c3a
--- /dev/null
+++ b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
@@ -0,0 +1,172 @@
+/*
+ * 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 android.net.dhcp;
+
+import static android.net.NetworkUtils.inet4AddressToIntHTH;
+
+import android.annotation.NonNull;
+import android.net.LinkAddress;
+
+import com.google.android.collect.Sets;
+
+import java.net.Inet4Address;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Subclass of {@link DhcpServingParamsParcel} with additional utility methods for building.
+ *
+ * <p>This utility class does not check for validity of the parameters: invalid parameters are
+ * reported by the receiving module when unparceling the parcel.
+ *
+ * @see DhcpServingParams
+ * @hide
+ */
+public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel {
+ public static final int MTU_UNSET = 0;
+
+ /**
+ * Set the server address and served prefix for the DHCP server.
+ *
+ * <p>This parameter is required.
+ */
+ public DhcpServingParamsParcelExt setServerAddr(@NonNull LinkAddress serverAddr) {
+ this.serverAddr = inet4AddressToIntHTH((Inet4Address) serverAddr.getAddress());
+ this.serverAddrPrefixLength = serverAddr.getPrefixLength();
+ return this;
+ }
+
+ /**
+ * Set the default routers to be advertised to DHCP clients.
+ *
+ * <p>Each router must be inside the served prefix. This may be an empty set, but it must
+ * always be set explicitly.
+ */
+ public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
+ this.defaultRouters = toIntArray(defaultRouters);
+ return this;
+ }
+
+ /**
+ * Set the default routers to be advertised to DHCP clients.
+ *
+ * <p>Each router must be inside the served prefix. This may be an empty list of routers,
+ * but it must always be set explicitly.
+ */
+ public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
+ return setDefaultRouters(Sets.newArraySet(defaultRouters));
+ }
+
+ /**
+ * Convenience method to build the parameters with no default router.
+ *
+ * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
+ */
+ public DhcpServingParamsParcelExt setNoDefaultRouter() {
+ return setDefaultRouters();
+ }
+
+ /**
+ * Set the DNS servers to be advertised to DHCP clients.
+ *
+ * <p>This may be an empty set, but it must always be set explicitly.
+ */
+ public DhcpServingParamsParcelExt setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
+ this.dnsServers = toIntArray(dnsServers);
+ return this;
+ }
+
+ /**
+ * Set the DNS servers to be advertised to DHCP clients.
+ *
+ * <p>This may be an empty list of servers, but it must always be set explicitly.
+ */
+ public DhcpServingParamsParcelExt setDnsServers(@NonNull Inet4Address... dnsServers) {
+ return setDnsServers(Sets.newArraySet(dnsServers));
+ }
+
+ /**
+ * Convenience method to build the parameters with no DNS server.
+ *
+ * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
+ */
+ public DhcpServingParamsParcelExt setNoDnsServer() {
+ return setDnsServers();
+ }
+
+ /**
+ * Set excluded addresses that the DHCP server is not allowed to assign to clients.
+ *
+ * <p>This parameter is optional. DNS servers and default routers are always excluded
+ * and do not need to be set here.
+ */
+ public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
+ this.excludedAddrs = toIntArray(excludedAddrs);
+ return this;
+ }
+
+ /**
+ * Set excluded addresses that the DHCP server is not allowed to assign to clients.
+ *
+ * <p>This parameter is optional. DNS servers and default routers are always excluded
+ * and do not need to be set here.
+ */
+ public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
+ return setExcludedAddrs(Sets.newArraySet(excludedAddrs));
+ }
+
+ /**
+ * Set the lease time for leases assigned by the DHCP server.
+ *
+ * <p>This parameter is required.
+ */
+ public DhcpServingParamsParcelExt setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
+ this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
+ return this;
+ }
+
+ /**
+ * Set the link MTU to be advertised to DHCP clients.
+ *
+ * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
+ * is optional and defaults to {@link #MTU_UNSET}.
+ */
+ public DhcpServingParamsParcelExt setLinkMtu(int linkMtu) {
+ this.linkMtu = linkMtu;
+ return this;
+ }
+
+ /**
+ * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
+ *
+ * <p>If not set, the default value is false.
+ */
+ public DhcpServingParamsParcelExt setMetered(boolean metered) {
+ this.metered = metered;
+ return this;
+ }
+
+ private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) {
+ int[] res = new int[addrs.size()];
+ int i = 0;
+ for (Inet4Address addr : addrs) {
+ res[i] = inet4AddressToIntHTH(addr);
+ i++;
+ }
+ return res;
+ }
+}
diff --git a/services/startop/Android.bp b/services/startop/Android.bp
new file mode 100644
index 0000000..093b4ec
--- /dev/null
+++ b/services/startop/Android.bp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+java_library_static {
+ name: "services.startop",
+
+ static_libs: [
+ // frameworks/base/startop/iorap
+ "services.startop.iorap",
+ ],
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 8b65e76..20f72bf 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -613,7 +613,7 @@
}
@Test
- public void testGetAllowedPackages() throws Exception {
+ public void testGetAllowedPackages_byUser() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
mIpm, approvalLevel);
@@ -681,6 +681,30 @@
}
@Test
+ public void testGetAllowedPackages() throws Exception {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+ mIpm, APPROVAL_BY_COMPONENT);
+ loadXml(service);
+ service.mApprovalLevel = APPROVAL_BY_PACKAGE;
+ loadXml(service);
+
+ List<String> allowedPackages = new ArrayList<>();
+ allowedPackages.add("this.is.a.package.name");
+ allowedPackages.add("another.package");
+ allowedPackages.add("secondary");
+ allowedPackages.add("this.is.another.package");
+ allowedPackages.add("package");
+ allowedPackages.add("component");
+ allowedPackages.add("bananas!");
+
+ Set<String> actual = service.getAllowedPackages();
+ assertEquals(allowedPackages.size(), actual.size());
+ for (String pkg : allowedPackages) {
+ assertTrue(actual.contains(pkg));
+ }
+ }
+
+ @Test
public void testOnUserRemoved() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 569c6d4..fe5840f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -31,6 +31,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -38,6 +39,9 @@
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -144,6 +148,13 @@
return display;
}
+ /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
+ TestActivityDisplay addNewActivityDisplayAt(DisplayInfo info, int position) {
+ final TestActivityDisplay display = createNewActivityDisplay(info);
+ mRootActivityContainer.addChild(display, position);
+ return display;
+ }
+
/**
* Builder for creating new activities.
*/
@@ -234,6 +245,10 @@
mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
spyOn(activity);
activity.mAppWindowToken = mock(AppWindowToken.class);
+ doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility();
+ doCallRealMethod().when(activity.mAppWindowToken)
+ .setOrientation(anyInt(), any(), any());
+ doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt());
doNothing().when(activity).removeWindowContainer();
if (mTaskRecord != null) {
@@ -346,6 +361,7 @@
mStack.addTask(task, true, "creating test task");
task.setStack(mStack);
task.setTask();
+ mStack.getWindowContainerController().mContainer.addChild(task.mTask, 0);
}
task.touchActiveTime();
@@ -365,7 +381,10 @@
setTask();
}
- private void setTask() {
+ void setTask() {
+ Task mockTask = mock(Task.class);
+ mockTask.mTaskRecord = this;
+ doCallRealMethod().when(mockTask).onDescendantOrientationChanged(any(), any());
setTask(mock(Task.class));
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 7da85af..00bec3f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -21,6 +21,11 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
@@ -133,17 +138,6 @@
assertTrue(task.returnsToHomeStack());
}
- /** Ensures that bounds are clipped to their parent. */
- @Test
- public void testAppBounds_BoundsClipping() {
- final Rect shiftedBounds = new Rect(mParentBounds);
- shiftedBounds.offset(10, 10);
- final Rect expectedBounds = new Rect(mParentBounds);
- expectedBounds.intersect(shiftedBounds);
- testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, shiftedBounds,
- expectedBounds);
- }
-
/** Ensures that empty bounds are not propagated to the configuration. */
@Test
public void testAppBounds_EmptyBounds() {
@@ -167,18 +161,108 @@
final Rect insetBounds = new Rect(mParentBounds);
insetBounds.inset(5, 5, 5, 5);
testStackBoundsConfiguration(
- WINDOWING_MODE_FULLSCREEN, mParentBounds, insetBounds, insetBounds);
+ WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds);
}
- /** Ensures that full screen free form bounds are clipped */
+ /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
@Test
- public void testAppBounds_FullScreenFreeFormBounds() {
+ public void testBoundsOnModeChangeFreeformToFullscreen() {
ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+ ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ TaskRecord task = stack.getChildAt(0);
+ task.getRootActivity().mAppWindowToken.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
DisplayInfo info = new DisplayInfo();
display.mDisplay.getDisplayInfo(info);
final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
- testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds,
- mParentBounds);
+ final Rect freeformBounds = new Rect(fullScreenBounds);
+ freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+ (int) (freeformBounds.height() * 0.2));
+ task.setBounds(freeformBounds);
+
+ assertEquals(freeformBounds, task.getBounds());
+
+ // FULLSCREEN inherits bounds
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertEquals(fullScreenBounds, task.getBounds());
+ assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
+
+ // FREEFORM restores bounds
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(freeformBounds, task.getBounds());
+ }
+
+ /**
+ * This is a temporary hack to trigger an onConfigurationChange at the task level after an
+ * orientation is requested. Normally this is done by the onDescendentOrientationChanged call
+ * up the WM hierarchy, but since the WM hierarchy is mocked out, it doesn't happen here.
+ * TODO: remove this when we either get a WM hierarchy or when hierarchies are merged.
+ */
+ private void setActivityRequestedOrientation(ActivityRecord activity, int orientation) {
+ activity.setRequestedOrientation(orientation);
+ ConfigurationContainer taskRecord = activity.getParent();
+ taskRecord.onConfigurationChanged(taskRecord.getParent().getConfiguration());
+ }
+
+ /**
+ * Tests that a task with forced orientation has orientation-consistent bounds within the
+ * parent.
+ */
+ @Test
+ public void testFullscreenBoundsForcedOrientation() {
+ final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+ final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
+ DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = fullScreenBounds.width();
+ info.logicalHeight = fullScreenBounds.height();
+ ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
+ assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
+ ActivityStack stack = new StackBuilder(mRootActivityContainer)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ TaskRecord task = stack.getChildAt(0);
+ ActivityRecord root = task.getRootActivity();
+ ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
+ assertEquals(root, task.getRootActivity());
+
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed portrait fits within parent
+ setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT);
+ assertEquals(root, task.getRootActivity());
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
+ assertTrue(task.getBounds().width() < task.getBounds().height());
+ assertEquals(fullScreenBounds.height(), task.getBounds().height());
+
+ // Setting non-root app has no effect
+ setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE);
+ assertTrue(task.getBounds().width() < task.getBounds().height());
+
+ // Setting app to unspecified restores
+ setActivityRequestedOrientation(root, SCREEN_ORIENTATION_UNSPECIFIED);
+ assertEquals(fullScreenBounds, task.getBounds());
+
+ // Setting app to fixed landscape and changing display
+ setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE);
+ display.setBounds(fullScreenBoundsPort);
+ assertTrue(task.getBounds().width() > task.getBounds().height());
+ assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+
+ // in FREEFORM, no constraint
+ final Rect freeformBounds = new Rect(display.getBounds());
+ freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+ (int) (freeformBounds.height() * 0.2));
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.setBounds(freeformBounds);
+ assertEquals(freeformBounds, task.getBounds());
+
+ // FULLSCREEN letterboxes bounds
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertTrue(task.getBounds().width() > task.getBounds().height());
+ assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+
+ // FREEFORM restores bounds as before
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(freeformBounds, task.getBounds());
}
/** Ensures that the alias intent won't have target component resolved. */
diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp
index b3b0900..59a80fb 100644
--- a/startop/iorap/Android.bp
+++ b/startop/iorap/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
java_library_static {
- name: "libiorap-java",
+ name: "services.startop.iorap",
aidl: {
include_dirs: [
@@ -21,6 +21,8 @@
],
},
+ libs: ["services.core"],
+
srcs: [
":iorap-aidl",
"**/*.java",
diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
new file mode 100644
index 0000000..c2e4581
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
@@ -0,0 +1,368 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.annotation.LongDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+// TODO: fix this. either move this class into system server or add a dependency on
+// these wm classes to libiorap-java and libiorap-java-tests (somehow).
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
+import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Objects;
+
+/**
+ * Provide a hint to iorapd that an app launch sequence has transitioned state.<br /><br />
+ *
+ * Knowledge of when an activity starts/stops can be used by iorapd to increase system
+ * performance (e.g. by launching perfetto tracing to record an io profile, or by
+ * playing back an ioprofile via readahead) over the long run.<br /><br />
+ *
+ * /@see com.google.android.startop.iorap.IIorap#onAppLaunchEvent <br /><br />
+ * @see com.android.server.wm.ActivityMetricsLaunchObserver
+ * ActivityMetricsLaunchObserver for the possible event states.
+ * @hide
+ */
+public abstract class AppLaunchEvent implements Parcelable {
+ @LongDef
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SequenceId {}
+
+ public final @SequenceId
+ long sequenceId;
+
+ protected AppLaunchEvent(@SequenceId long sequenceId) {
+ this.sequenceId = sequenceId;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof AppLaunchEvent) {
+ return equals((AppLaunchEvent) other);
+ }
+ return false;
+ }
+
+ protected boolean equals(AppLaunchEvent other) {
+ return sequenceId == other.sequenceId;
+ }
+
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() +
+ "{" + "sequenceId=" + Long.toString(sequenceId) +
+ toStringBody() + "}";
+ }
+
+ protected String toStringBody() { return ""; };
+
+ // List of possible variants:
+
+ public static final class IntentStarted extends AppLaunchEvent {
+ @NonNull
+ public final Intent intent;
+
+ public IntentStarted(@SequenceId long sequenceId, Intent intent) {
+ super(sequenceId);
+ this.intent = intent;
+
+ Objects.requireNonNull(intent, "intent");
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof IntentStarted) {
+ return intent.equals(((IntentStarted)other).intent) &&
+ super.equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ protected String toStringBody() {
+ return ", intent=" + intent.toString();
+ }
+
+
+ @Override
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ super.writeToParcelImpl(p, flags);
+ intent.writeToParcel(p, flags);
+ }
+
+ IntentStarted(Parcel p) {
+ super(p);
+ intent = Intent.CREATOR.createFromParcel(p);
+ }
+ }
+
+ public static final class IntentFailed extends AppLaunchEvent {
+ public IntentFailed(@SequenceId long sequenceId) {
+ super(sequenceId);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof IntentFailed) {
+ return super.equals(other);
+ }
+ return false;
+ }
+
+ IntentFailed(Parcel p) {
+ super(p);
+ }
+ }
+
+ public static abstract class BaseWithActivityRecordData extends AppLaunchEvent {
+ public final @NonNull
+ @ActivityRecordProto byte[] activityRecordSnapshot;
+
+ protected BaseWithActivityRecordData(@SequenceId long sequenceId,
+ @NonNull @ActivityRecordProto byte[] snapshot) {
+ super(sequenceId);
+ activityRecordSnapshot = snapshot;
+
+ Objects.requireNonNull(snapshot, "snapshot");
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof BaseWithActivityRecordData) {
+ return activityRecordSnapshot.equals(
+ ((BaseWithActivityRecordData)other).activityRecordSnapshot) &&
+ super.equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ protected String toStringBody() {
+ return ", " + activityRecordSnapshot.toString();
+ }
+
+ @Override
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ super.writeToParcelImpl(p, flags);
+ ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
+ }
+
+ BaseWithActivityRecordData(Parcel p) {
+ super(p);
+ activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
+ }
+ }
+
+ public static final class ActivityLaunched extends BaseWithActivityRecordData {
+ public final @ActivityMetricsLaunchObserver.Temperature
+ int temperature;
+
+ public ActivityLaunched(@SequenceId long sequenceId,
+ @NonNull @ActivityRecordProto byte[] snapshot,
+ @ActivityMetricsLaunchObserver.Temperature int temperature) {
+ super(sequenceId, snapshot);
+ this.temperature = temperature;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ActivityLaunched) {
+ return temperature == ((ActivityLaunched)other).temperature &&
+ super.equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ protected String toStringBody() {
+ return ", temperature=" + Integer.toString(temperature);
+ }
+
+ @Override
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ super.writeToParcelImpl(p, flags);
+ p.writeInt(temperature);
+ }
+
+ ActivityLaunched(Parcel p) {
+ super(p);
+ temperature = p.readInt();
+ }
+ }
+
+ public static final class ActivityLaunchFinished extends BaseWithActivityRecordData {
+ public ActivityLaunchFinished(@SequenceId long sequenceId,
+ @NonNull @ActivityRecordProto byte[] snapshot) {
+ super(sequenceId, snapshot);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ActivityLaunched) {
+ return super.equals(other);
+ }
+ return false;
+ }
+ }
+
+ public static class ActivityLaunchCancelled extends AppLaunchEvent {
+ public final @Nullable
+ @ActivityRecordProto byte[] activityRecordSnapshot;
+
+ public ActivityLaunchCancelled(@SequenceId long sequenceId,
+ @Nullable @ActivityRecordProto byte[] snapshot) {
+ super(sequenceId);
+ activityRecordSnapshot = snapshot;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ActivityLaunchCancelled) {
+ return Objects.equals(activityRecordSnapshot,
+ ((ActivityLaunchCancelled)other).activityRecordSnapshot) &&
+ super.equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ protected String toStringBody() {
+ return ", " + activityRecordSnapshot.toString();
+ }
+
+ @Override
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ super.writeToParcelImpl(p, flags);
+ if (activityRecordSnapshot != null) {
+ p.writeBoolean(true);
+ ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
+ } else {
+ p.writeBoolean(false);
+ }
+ }
+
+ ActivityLaunchCancelled(Parcel p) {
+ super(p);
+ if (p.readBoolean()) {
+ activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
+ } else {
+ activityRecordSnapshot = null;
+ }
+ }
+ }
+
+ @Override
+ public @ContentsFlags int describeContents() { return 0; }
+
+ @Override
+ public void writeToParcel(Parcel p, @WriteFlags int flags) {
+ p.writeInt(getTypeIndex());
+
+ writeToParcelImpl(p, flags);
+ }
+
+
+ public static Creator<AppLaunchEvent> CREATOR =
+ new Creator<AppLaunchEvent>() {
+ @Override
+ public AppLaunchEvent createFromParcel(Parcel source) {
+ int typeIndex = source.readInt();
+
+ Class<?> kls = getClassFromTypeIndex(typeIndex);
+ if (kls == null) {
+ throw new IllegalArgumentException("Invalid type index: " + typeIndex);
+ }
+
+ try {
+ return (AppLaunchEvent) kls.getConstructor(Parcel.class).newInstance(source);
+ } catch (InstantiationException e) {
+ throw new AssertionError(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ } catch (InvocationTargetException e) {
+ throw new AssertionError(e);
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public AppLaunchEvent[] newArray(int size) {
+ return new AppLaunchEvent[0];
+ }
+ };
+
+ protected void writeToParcelImpl(Parcel p, int flags) {
+ p.writeLong(sequenceId);
+ }
+
+ protected AppLaunchEvent(Parcel p) {
+ sequenceId = p.readLong();
+ }
+
+ private int getTypeIndex() {
+ for (int i = 0; i < sTypes.length; ++i) {
+ if (sTypes[i].equals(this.getClass())) {
+ return i;
+ }
+ }
+ throw new AssertionError("sTypes did not include this type: " + this.getClass());
+ }
+
+ private static @Nullable Class<?> getClassFromTypeIndex(int typeIndex) {
+ if (typeIndex >= 0 && typeIndex < sTypes.length) {
+ return sTypes[typeIndex];
+ }
+ return null;
+ }
+
+ // Index position matters: It is used to encode the specific type in parceling.
+ // Keep up-to-date with C++ side.
+ private static Class<?>[] sTypes = new Class[] {
+ IntentStarted.class,
+ IntentFailed.class,
+ ActivityLaunched.class,
+ ActivityLaunchFinished.class,
+ ActivityLaunchCancelled.class,
+ };
+
+ // TODO: move to @ActivityRecordProto byte[] once we have unit tests.
+ public static class ActivityRecordProtoParcelable {
+ public static void write(Parcel p, @ActivityRecordProto byte[] activityRecordSnapshot,
+ int flags) {
+ p.writeByteArray(activityRecordSnapshot);
+ }
+
+ public static @ActivityRecordProto byte[] create(Parcel p) {
+ byte[] data = p.createByteArray();
+
+ return data;
+ }
+ }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
new file mode 100644
index 0000000..7fcad36
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -0,0 +1,216 @@
+/*
+ * 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.google.android.startop.iorap;
+// TODO: rename to com.android.server.startop.iorap
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
+import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
+import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+/**
+ * System-server-local proxy into the {@code IIorap} native service.
+ */
+public class IorapForwardingService extends SystemService {
+
+ public static final boolean DEBUG = true; // TODO: read from a getprop?
+ public static final String TAG = "IorapForwardingService";
+
+ private IIorap mIorapRemote;
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public IorapForwardingService(Context context) {
+ super(context);
+ }
+
+ //<editor-fold desc="Providers">
+ /*
+ * Providers for external dependencies:
+ * - These are marked as protected to allow tests to inject different values via mocks.
+ */
+
+ @VisibleForTesting
+ protected ActivityMetricsLaunchObserverRegistry provideLaunchObserverRegistry() {
+ ActivityTaskManagerInternal amtInternal =
+ LocalServices.getService(ActivityTaskManagerInternal.class);
+ ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
+ amtInternal.getLaunchObserverRegistry();
+ return launchObserverRegistry;
+ }
+
+ @VisibleForTesting
+ protected IIorap provideIorapRemote() {
+ try {
+ return IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"));
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ // TODO: how do we handle service being missing?
+ throw new AssertionError(e);
+ }
+ }
+
+ //</editor-fold>
+
+ @Override
+ public void onStart() {
+ if (DEBUG) {
+ Log.v(TAG, "onStart");
+ }
+
+ // Connect to the native binder service.
+ mIorapRemote = provideIorapRemote();
+ invokeRemote( () -> mIorapRemote.setTaskListener(new RemoteTaskListener()) );
+
+ // Listen to App Launch Sequence events from ActivityTaskManager,
+ // and forward them to the native binder service.
+ ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
+ provideLaunchObserverRegistry();
+ launchObserverRegistry.registerLaunchObserver(new AppLaunchObserver());
+ }
+
+ private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
+ // We add a synthetic sequence ID here to make it easier to differentiate new
+ // launch sequences on the native side.
+ private @AppLaunchEvent.SequenceId long mSequenceId = -1;
+
+ @Override
+ public void onIntentStarted(@NonNull Intent intent) {
+ // #onIntentStarted [is the only transition that] initiates a new launch sequence.
+ ++mSequenceId;
+
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onIntentStarted(%d, %s)",
+ mSequenceId, intent));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.IntentStarted(mSequenceId, intent))
+ );
+ }
+
+ @Override
+ public void onIntentFailed() {
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onIntentFailed(%d)", mSequenceId));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.IntentFailed(mSequenceId))
+ );
+ }
+
+ @Override
+ public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
+ @Temperature int temperature) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunched(%d, %s, %d)",
+ mSequenceId, activity, temperature));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.ActivityLaunched(mSequenceId, activity, temperature))
+ );
+ }
+
+ @Override
+ public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchCancelled(%d, %s)",
+ mSequenceId, activity));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId,
+ activity)));
+ }
+
+ @Override
+ public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchFinished(%d, %s)",
+ mSequenceId, activity));
+ }
+
+ invokeRemote(() ->
+ mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+ new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId, activity))
+ );
+ }
+ }
+
+ private class RemoteTaskListener extends ITaskListener.Stub {
+ @Override
+ public void onProgress(RequestId requestId, TaskResult result) throws RemoteException {
+ if (DEBUG) {
+ Log.v(TAG,
+ String.format("RemoteTaskListener#onProgress(%s, %s)", requestId, result));
+ }
+
+ // TODO: implement rest.
+ }
+
+ @Override
+ public void onComplete(RequestId requestId, TaskResult result) throws RemoteException {
+ if (DEBUG) {
+ Log.v(TAG,
+ String.format("RemoteTaskListener#onComplete(%s, %s)", requestId, result));
+ }
+
+ // TODO: implement rest.
+ }
+ }
+
+ private interface RemoteRunnable {
+ void run() throws RemoteException;
+ }
+
+ private static void invokeRemote(RemoteRunnable r) {
+ try {
+ r.run();
+ } catch (RemoteException e) {
+ // TODO: what do we do with exceptions?
+ throw new AssertionError("not implemented", e);
+ }
+ }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
index 2c79319..adb3a91 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
@@ -71,7 +71,7 @@
@Override
public String toString() {
- return String.format("{requestId: %ld}", requestId);
+ return String.format("{requestId: %d}", requestId);
}
@Override
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
index 7605784..5ac4a46 100644
--- a/startop/iorap/tests/Android.bp
+++ b/startop/iorap/tests/Android.bp
@@ -18,8 +18,15 @@
srcs: ["src/**/*.kt"],
static_libs: [
- // non-test dependencies
- "libiorap-java",
+ // Non-test dependencies
+
+ // library under test
+ "services.startop.iorap",
+ // need the system_server code to be on the classpath,
+ "services.core",
+
+ // Test Dependencies
+
// test android dependencies
"platform-test-annotations",
"android-support-test",
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index b906d0b..3299117 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.app.Service;
import android.content.Intent;
@@ -27,8 +28,8 @@
import android.os.RemoteException;
import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.ICallRedirectionService;
import com.android.internal.telecom.ICallRedirectionAdapter;
+import com.android.internal.telecom.ICallRedirectionService;
/**
* This service can be implemented to interact between Telecom and its implementor
@@ -62,22 +63,35 @@
/**
* Telecom calls this method to inform the implemented {@link CallRedirectionService} of
- * a new outgoing call which is being placed.
+ * a new outgoing call which is being placed. Telecom does not request to redirect emergency
+ * calls and does not request to redirect calls with gateway information.
*
- * The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
- * {@link #redirectCall(Uri, PhoneAccountHandle)}, and {@link #cancelCall()} only from here.
+ * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from
+ * the implemented {@link CallRedirectionService} set by users.
*
- * @param handle the phone number dialed by the user
- * @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+ * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
+ * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only
+ * from here.
+ *
+ * @param handle the phone number dialed by the user, represented in E.164 format if possible
+ * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+ * @param allowInteractiveResponse a boolean to tell if the implemented
+ * {@link CallRedirectionService} should allow interactive
+ * responses with users. Will be {@code false} if, for example
+ * the device is in car mode and the user would not be able to
+ * interact with their device.
*/
- public abstract void onPlaceCall(Uri handle, PhoneAccountHandle targetPhoneAccount);
+ public abstract void onPlaceCall(@NonNull Uri handle,
+ @NonNull PhoneAccountHandle initialPhoneAccount,
+ boolean allowInteractiveResponse);
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes
- * are required to the outgoing call, and that the call should be placed as-is.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * no changes are required to the outgoing call, and that the call should be placed as-is.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
*/
public final void placeCallUnmodified() {
@@ -89,29 +103,39 @@
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes
- * are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * changes are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing
+ * call. Telecom will cancel the call if the implemented {@link CallRedirectionService}
+ * replies Telecom a handle for an emergency number.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
* @param handle the new phone number to dial
* @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
* If {@code null}, no change will be made to the
* {@link PhoneAccountHandle} used to place the call.
+ * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
+ * if the confirmFirst is true, and if the redirection request of this
+ * response was sent with a true flag of allowInteractiveResponse via
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
*/
- public final void redirectCall(Uri handle, PhoneAccountHandle targetPhoneAccount) {
+ public final void redirectCall(@NonNull Uri handle,
+ @NonNull PhoneAccountHandle targetPhoneAccount,
+ boolean confirmFirst) {
try {
- mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount);
+ mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
} catch (RemoteException e) {
}
}
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing
- * call should be canceled entirely.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * an outgoing call should be canceled entirely.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
*/
public final void cancelCall() {
@@ -137,7 +161,8 @@
SomeArgs args = (SomeArgs) msg.obj;
try {
mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1;
- onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3);
+ onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3,
+ (boolean) args.arg4);
} finally {
args.recycle();
}
@@ -152,15 +177,20 @@
* Telecom calls this method to inform the CallRedirectionService of a new outgoing call
* which is about to be placed.
* @param handle the phone number dialed by the user
- * @param targetPhoneAccount the URI of the number the user dialed
+ * @param initialPhoneAccount the URI of the number the user dialed
+ * @param allowInteractiveResponse a boolean to tell if the implemented
+ * {@link CallRedirectionService} should allow interactive
+ * responses with users.
*/
@Override
- public void placeCall(ICallRedirectionAdapter adapter, Uri handle,
- PhoneAccountHandle targetPhoneAccount) {
+ public void placeCall(@NonNull ICallRedirectionAdapter adapter, @NonNull Uri handle,
+ @NonNull PhoneAccountHandle initialPhoneAccount,
+ boolean allowInteractiveResponse) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = adapter;
args.arg2 = handle;
- args.arg3 = targetPhoneAccount;
+ args.arg3 = initialPhoneAccount;
+ args.arg4 = allowInteractiveResponse;
mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
}
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
index 46bf983..0a42a3f 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
@@ -31,5 +31,6 @@
void placeCallUnmodified();
- void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount);
+ void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount,
+ boolean confirmFirst);
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
index d8d360b..c1bc440 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
@@ -30,5 +30,5 @@
*/
oneway interface ICallRedirectionService {
void placeCall(in ICallRedirectionAdapter adapter, in Uri handle,
- in PhoneAccountHandle targetPhoneAccount);
+ in PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse);
}
diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java
new file mode 100644
index 0000000..4a6f20a
--- /dev/null
+++ b/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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 android.net.dhcp;
+
+import static android.net.InetAddresses.parseNumericAddress;
+
+import static com.google.android.collect.Sets.newHashSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.LinkAddress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DhcpServingParamsParcelExtTest {
+ private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123");
+ private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b;
+ private static final int TEST_PREFIX_LENGTH = 17;
+ private static final int TEST_LEASE_TIME_SECS = 120;
+ private static final int TEST_MTU = 1000;
+ private static final Set<Inet4Address> TEST_ADDRESS_SET =
+ newHashSet(inet4Addr("192.168.1.123"), inet4Addr("192.168.1.124"));
+ private static final Set<Integer> TEST_ADDRESS_SET_PARCELED =
+ newHashSet(0xc0a8017b, 0xc0a8017c);
+
+ private DhcpServingParamsParcelExt mParcel;
+
+ @Before
+ public void setUp() {
+ mParcel = new DhcpServingParamsParcelExt();
+ }
+
+ @Test
+ public void testSetServerAddr() {
+ mParcel.setServerAddr(new LinkAddress(TEST_ADDRESS, TEST_PREFIX_LENGTH));
+
+ assertEquals(TEST_ADDRESS_PARCELED, mParcel.serverAddr);
+ assertEquals(TEST_PREFIX_LENGTH, mParcel.serverAddrPrefixLength);
+ }
+
+ @Test
+ public void testSetDefaultRouters() {
+ mParcel.setDefaultRouters(TEST_ADDRESS_SET);
+ assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.defaultRouters));
+ }
+
+ @Test
+ public void testSetDnsServers() {
+ mParcel.setDnsServers(TEST_ADDRESS_SET);
+ assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.dnsServers));
+ }
+
+ @Test
+ public void testSetExcludedAddrs() {
+ mParcel.setExcludedAddrs(TEST_ADDRESS_SET);
+ assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.excludedAddrs));
+ }
+
+ @Test
+ public void testSetDhcpLeaseTimeSecs() {
+ mParcel.setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS);
+ assertEquals(TEST_LEASE_TIME_SECS, mParcel.dhcpLeaseTimeSecs);
+ }
+
+ @Test
+ public void testSetLinkMtu() {
+ mParcel.setLinkMtu(TEST_MTU);
+ assertEquals(TEST_MTU, mParcel.linkMtu);
+ }
+
+ @Test
+ public void testSetMetered() {
+ mParcel.setMetered(true);
+ assertTrue(mParcel.metered);
+ mParcel.setMetered(false);
+ assertFalse(mParcel.metered);
+ }
+
+ private static Inet4Address inet4Addr(String addr) {
+ return (Inet4Address) parseNumericAddress(addr);
+ }
+
+ private static Set<Integer> asSet(int[] ints) {
+ return IntStream.of(ints).boxed().collect(Collectors.toSet());
+ }
+}
diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java b/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java
index b6a4073..2ab2246 100644
--- a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java
@@ -16,6 +16,7 @@
package android.net.dhcp;
+import static android.net.NetworkUtils.inet4AddressToIntHTH;
import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
import static junit.framework.Assert.assertEquals;
@@ -27,6 +28,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.LinkAddress;
+import android.net.NetworkUtils;
import android.net.dhcp.DhcpServingParams.InvalidParameterException;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -35,8 +37,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.lang.reflect.Modifier;
import java.net.Inet4Address;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -56,6 +60,7 @@
private static final int TEST_MTU = 1500;
private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
+ private static final boolean TEST_METERED = true;
@Before
public void setUp() {
@@ -65,7 +70,8 @@
.setDnsServers(TEST_DNS_SERVERS)
.setServerAddr(TEST_LINKADDR)
.setLinkMtu(TEST_MTU)
- .setExcludedAddrs(TEST_EXCLUDED_ADDRS);
+ .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
+ .setMetered(TEST_METERED);
}
@Test
@@ -91,6 +97,7 @@
assertEquals(TEST_DNS_SERVERS, params.dnsServers);
assertEquals(TEST_LINKADDR, params.serverAddr);
assertEquals(TEST_MTU, params.linkMtu);
+ assertEquals(TEST_METERED, params.metered);
assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS);
assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS);
@@ -159,6 +166,39 @@
mBuilder.setDefaultRouters(parseAddr("192.168.254.254")).build();
}
+ @Test
+ public void testFromParcelableObject() throws InvalidParameterException {
+ final DhcpServingParams params = mBuilder.build();
+ final DhcpServingParamsParcel parcel = new DhcpServingParamsParcel();
+ parcel.defaultRouters = toIntArray(TEST_DEFAULT_ROUTERS);
+ parcel.dhcpLeaseTimeSecs = TEST_LEASE_TIME_SECS;
+ parcel.dnsServers = toIntArray(TEST_DNS_SERVERS);
+ parcel.serverAddr = inet4AddressToIntHTH(TEST_SERVER_ADDR);
+ parcel.serverAddrPrefixLength = TEST_LINKADDR.getPrefixLength();
+ parcel.linkMtu = TEST_MTU;
+ parcel.excludedAddrs = toIntArray(TEST_EXCLUDED_ADDRS);
+ parcel.metered = TEST_METERED;
+ final DhcpServingParams parceled = DhcpServingParams.fromParcelableObject(parcel);
+
+ assertEquals(params.defaultRouters, parceled.defaultRouters);
+ assertEquals(params.dhcpLeaseTimeSecs, parceled.dhcpLeaseTimeSecs);
+ assertEquals(params.dnsServers, parceled.dnsServers);
+ assertEquals(params.serverAddr, parceled.serverAddr);
+ assertEquals(params.linkMtu, parceled.linkMtu);
+ assertEquals(params.excludedAddrs, parceled.excludedAddrs);
+ assertEquals(params.metered, parceled.metered);
+
+ // Ensure that we do not miss any field if added in the future
+ final long numFields = Arrays.stream(DhcpServingParams.class.getDeclaredFields())
+ .filter(f -> !Modifier.isStatic(f.getModifiers()))
+ .count();
+ assertEquals(7, numFields);
+ }
+
+ private static int[] toIntArray(Collection<Inet4Address> addrs) {
+ return addrs.stream().mapToInt(NetworkUtils::inet4AddressToIntHTH).toArray();
+ }
+
private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
for (final T elem : subset) {
assertContains(set, elem);
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 7b2f07d..fef0ed7 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -64,7 +64,7 @@
Map getAllMatchingFqdnsForScanResults(in List<ScanResult> scanResult);
- List<OsuProvider> getMatchingOsuProviders(in List<ScanResult> scanResult);
+ Map getMatchingOsuProviders(in List<ScanResult> scanResult);
Map getMatchingPasspointConfigsForOsuProviders(in List<OsuProvider> osuProviders);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f2a3b42..ad2ed81 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1234,12 +1234,13 @@
* An empty list will be returned if no match is found.
*
* @param scanResults a list of ScanResult
- * @return A list of {@link OsuProvider} that does not contain duplicate entries.
+ * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
* @throws UnsupportedOperationException if Passpoint is not enabled on the device.
* @hide
*/
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public List<OsuProvider> getMatchingOsuProviders(List<ScanResult> scanResults) {
+ public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
+ List<ScanResult> scanResults) {
try {
return mService.getMatchingOsuProviders(scanResults);
} catch (RemoteException e) {
diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java
index 2396108..fd4eacc 100644
--- a/wifi/java/com/android/server/wifi/AbstractWifiService.java
+++ b/wifi/java/com/android/server/wifi/AbstractWifiService.java
@@ -124,7 +124,8 @@
}
@Override
- public List<OsuProvider> getMatchingOsuProviders(List<ScanResult> scanResults) {
+ public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
+ List<ScanResult> scanResults) {
throw new UnsupportedOperationException();
}