Merge changes from topic "b249848655-BinderRanking" into udc-qpr-dev am: 78a4a54940
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23609377 Change-Id: I4f7ddc59ed5a4629dee565981b90436d0856561d Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
committed by
Automerger Merge Worker
commit
59110cd210
@@ -2962,6 +2962,10 @@ package android.service.notification {
|
|||||||
method @Deprecated public boolean isBound();
|
method @Deprecated public boolean isBound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NotificationRankingUpdate implements android.os.Parcelable {
|
||||||
|
method public final boolean isFdNotNullAndClosed();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
package android.service.quickaccesswallet {
|
package android.service.quickaccesswallet {
|
||||||
|
|||||||
@@ -16,32 +16,117 @@
|
|||||||
package android.service.notification;
|
package android.service.notification;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.annotation.TestApi;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.SharedMemory;
|
||||||
|
import android.system.ErrnoException;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Represents an update to notification rankings.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
|
@SuppressLint({"ParcelNotFinal", "ParcelCreator"})
|
||||||
|
@TestApi
|
||||||
public class NotificationRankingUpdate implements Parcelable {
|
public class NotificationRankingUpdate implements Parcelable {
|
||||||
private final NotificationListenerService.RankingMap mRankingMap;
|
private final NotificationListenerService.RankingMap mRankingMap;
|
||||||
|
|
||||||
|
// The ranking map is stored in shared memory when parceled, for sending across the binder.
|
||||||
|
// This is done because the ranking map can grow large if there are many notifications.
|
||||||
|
private SharedMemory mRankingMapFd = null;
|
||||||
|
private final String mSharedMemoryName = "NotificationRankingUpdatedSharedMemory";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
public NotificationRankingUpdate(NotificationListenerService.Ranking[] rankings) {
|
public NotificationRankingUpdate(NotificationListenerService.Ranking[] rankings) {
|
||||||
mRankingMap = new NotificationListenerService.RankingMap(rankings);
|
mRankingMap = new NotificationListenerService.RankingMap(rankings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
public NotificationRankingUpdate(Parcel in) {
|
public NotificationRankingUpdate(Parcel in) {
|
||||||
mRankingMap = in.readParcelable(getClass().getClassLoader(), android.service.notification.NotificationListenerService.RankingMap.class);
|
if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(
|
||||||
|
SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) {
|
||||||
|
// Recover the ranking map from the SharedMemory and store it in mapParcel.
|
||||||
|
final Parcel mapParcel = Parcel.obtain();
|
||||||
|
ByteBuffer buffer = null;
|
||||||
|
try {
|
||||||
|
// The ranking map should be stored in shared memory when it is parceled, so we
|
||||||
|
// unwrap the SharedMemory object.
|
||||||
|
mRankingMapFd = in.readParcelable(getClass().getClassLoader(), SharedMemory.class);
|
||||||
|
|
||||||
|
// In the case that the ranking map can't be read, readParcelable may return null.
|
||||||
|
// In this case, we set mRankingMap to null;
|
||||||
|
if (mRankingMapFd == null) {
|
||||||
|
mRankingMap = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We only need read-only access to the shared memory region.
|
||||||
|
buffer = mRankingMapFd.mapReadOnly();
|
||||||
|
if (buffer == null) {
|
||||||
|
mRankingMap = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] payload = new byte[buffer.remaining()];
|
||||||
|
buffer.get(payload);
|
||||||
|
mapParcel.unmarshall(payload, 0, payload.length);
|
||||||
|
mapParcel.setDataPosition(0);
|
||||||
|
|
||||||
|
mRankingMap = mapParcel.readParcelable(getClass().getClassLoader(),
|
||||||
|
android.service.notification.NotificationListenerService.RankingMap.class);
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
// TODO(b/284297289): remove throw when associated flag is moved to droidfood, to
|
||||||
|
// avoid crashes; change to Log.wtf.
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
mapParcel.recycle();
|
||||||
|
if (buffer != null) {
|
||||||
|
mRankingMapFd.unmap(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mRankingMap = in.readParcelable(getClass().getClassLoader(),
|
||||||
|
android.service.notification.NotificationListenerService.RankingMap.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirms that the SharedMemory file descriptor is closed. Should only be used for testing.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@TestApi
|
||||||
|
public final boolean isFdNotNullAndClosed() {
|
||||||
|
return mRankingMapFd != null && mRankingMapFd.getFd() == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
public NotificationListenerService.RankingMap getRankingMap() {
|
public NotificationListenerService.RankingMap getRankingMap() {
|
||||||
return mRankingMap;
|
return mRankingMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable Object o) {
|
public boolean equals(@Nullable Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
@@ -51,11 +136,51 @@ public class NotificationRankingUpdate implements Parcelable {
|
|||||||
return mRankingMap.equals(other.mRankingMap);
|
return mRankingMap.equals(other.mRankingMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel out, int flags) {
|
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||||||
out.writeParcelable(mRankingMap, flags);
|
if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(
|
||||||
|
SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) {
|
||||||
|
final Parcel mapParcel = Parcel.obtain();
|
||||||
|
try {
|
||||||
|
// Parcels the ranking map and measures its size.
|
||||||
|
mapParcel.writeParcelable(mRankingMap, flags);
|
||||||
|
int mapSize = mapParcel.dataSize();
|
||||||
|
|
||||||
|
// Creates a new SharedMemory object with enough space to hold the ranking map.
|
||||||
|
SharedMemory mRankingMapFd = SharedMemory.create(mSharedMemoryName, mapSize);
|
||||||
|
if (mRankingMapFd == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a read/write buffer mapping the entire shared memory region.
|
||||||
|
final ByteBuffer buffer = mRankingMapFd.mapReadWrite();
|
||||||
|
|
||||||
|
// Puts the ranking map into the shared memory region buffer.
|
||||||
|
buffer.put(mapParcel.marshall(), 0, mapSize);
|
||||||
|
|
||||||
|
// Protects the region from being written to, by setting it to be read-only.
|
||||||
|
mRankingMapFd.setProtect(OsConstants.PROT_READ);
|
||||||
|
|
||||||
|
// Puts the SharedMemory object in the parcel.
|
||||||
|
out.writeParcelable(mRankingMapFd, flags);
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
// TODO(b/284297289): remove throw when associated flag is moved to droidfood, to
|
||||||
|
// avoid crashes; change to Log.wtf.
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
mapParcel.recycle();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.writeParcelable(mRankingMap, flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
public static final @android.annotation.NonNull Parcelable.Creator<NotificationRankingUpdate> CREATOR
|
public static final @android.annotation.NonNull Parcelable.Creator<NotificationRankingUpdate> CREATOR
|
||||||
= new Parcelable.Creator<NotificationRankingUpdate>() {
|
= new Parcelable.Creator<NotificationRankingUpdate>() {
|
||||||
public NotificationRankingUpdate createFromParcel(Parcel parcel) {
|
public NotificationRankingUpdate createFromParcel(Parcel parcel) {
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ public class SystemUiSystemPropertiesFlags {
|
|||||||
/** Gating the holding of WakeLocks until NLSes are told about a new notification. */
|
/** Gating the holding of WakeLocks until NLSes are told about a new notification. */
|
||||||
public static final Flag WAKE_LOCK_FOR_POSTING_NOTIFICATION =
|
public static final Flag WAKE_LOCK_FOR_POSTING_NOTIFICATION =
|
||||||
devFlag("persist.sysui.notification.wake_lock_for_posting_notification");
|
devFlag("persist.sysui.notification.wake_lock_for_posting_notification");
|
||||||
|
|
||||||
|
/** Gating storing NotificationRankingUpdate ranking map in shared memory. */
|
||||||
|
public static final Flag RANKING_UPDATE_ASHMEM = devFlag(
|
||||||
|
"persist.sysui.notification.ranking_update_ashmem");
|
||||||
}
|
}
|
||||||
|
|
||||||
//// == End of flags. Everything below this line is the implementation. == ////
|
//// == End of flags. Everything below this line is the implementation. == ////
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.service.notification;
|
||||||
|
|
||||||
|
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
import static junit.framework.Assert.assertNull;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class NotificationRankingUpdateTest {
|
||||||
|
|
||||||
|
private static final String NOTIFICATION_CHANNEL_ID = "test_channel_id";
|
||||||
|
private static final String TEST_KEY = "key";
|
||||||
|
|
||||||
|
private NotificationChannel mNotificationChannel;
|
||||||
|
|
||||||
|
// TODO(b/284297289): remove this flag set once resolved.
|
||||||
|
@Parameterized.Parameters(name = "rankingUpdateAshmem={0}")
|
||||||
|
public static Boolean[] getRankingUpdateAshmem() {
|
||||||
|
return new Boolean[] { true, false };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parameterized.Parameter
|
||||||
|
public boolean mRankingUpdateAshmem;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mNotificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "test channel",
|
||||||
|
NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
|
|
||||||
|
SystemUiSystemPropertiesFlags.TEST_RESOLVER = flag -> {
|
||||||
|
if (flag.mSysPropKey.equals(RANKING_UPDATE_ASHMEM.mSysPropKey)) {
|
||||||
|
return mRankingUpdateAshmem;
|
||||||
|
}
|
||||||
|
return new SystemUiSystemPropertiesFlags.DebugResolver().isEnabled(flag);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
SystemUiSystemPropertiesFlags.TEST_RESOLVER = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationListenerService.Ranking createTestRanking(String key, int rank) {
|
||||||
|
NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
|
||||||
|
ranking.populate(
|
||||||
|
/* key= */ key,
|
||||||
|
/* rank= */ rank,
|
||||||
|
/* matchesInterruptionFilter= */ false,
|
||||||
|
/* visibilityOverride= */ 0,
|
||||||
|
/* suppressedVisualEffects= */ 0,
|
||||||
|
mNotificationChannel.getImportance(),
|
||||||
|
/* explanation= */ null,
|
||||||
|
/* overrideGroupKey= */ null,
|
||||||
|
mNotificationChannel,
|
||||||
|
/* overridePeople= */ null,
|
||||||
|
/* snoozeCriteria= */ null,
|
||||||
|
/* showBadge= */ true,
|
||||||
|
/* userSentiment= */ 0,
|
||||||
|
/* hidden= */ false,
|
||||||
|
/* lastAudiblyAlertedMs= */ -1,
|
||||||
|
/* noisy= */ false,
|
||||||
|
/* smartActions= */ null,
|
||||||
|
/* smartReplies= */ null,
|
||||||
|
/* canBubble= */ false,
|
||||||
|
/* isTextChanged= */ false,
|
||||||
|
/* isConversation= */ false,
|
||||||
|
/* shortcutInfo= */ null,
|
||||||
|
/* rankingAdjustment= */ 0,
|
||||||
|
/* isBubble= */ false,
|
||||||
|
/* proposedImportance= */ 0,
|
||||||
|
/* sensitiveContent= */ false
|
||||||
|
);
|
||||||
|
return ranking;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRankingUpdate_rankingConstructor() {
|
||||||
|
NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
|
||||||
|
NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
|
||||||
|
new NotificationListenerService.Ranking[]{ranking});
|
||||||
|
|
||||||
|
NotificationListenerService.RankingMap retrievedRankings = rankingUpdate.getRankingMap();
|
||||||
|
NotificationListenerService.Ranking retrievedRanking =
|
||||||
|
new NotificationListenerService.Ranking();
|
||||||
|
assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking));
|
||||||
|
assertEquals(123, retrievedRanking.getRank());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRankingUpdate_parcelConstructor() {
|
||||||
|
NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
|
||||||
|
NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
|
||||||
|
new NotificationListenerService.Ranking[]{ranking});
|
||||||
|
|
||||||
|
Parcel parceledRankingUpdate = Parcel.obtain();
|
||||||
|
rankingUpdate.writeToParcel(parceledRankingUpdate, 0);
|
||||||
|
parceledRankingUpdate.setDataPosition(0);
|
||||||
|
|
||||||
|
NotificationRankingUpdate retrievedRankingUpdate = new NotificationRankingUpdate(
|
||||||
|
parceledRankingUpdate);
|
||||||
|
|
||||||
|
NotificationListenerService.RankingMap retrievedRankings =
|
||||||
|
retrievedRankingUpdate.getRankingMap();
|
||||||
|
assertNotNull(retrievedRankings);
|
||||||
|
assertTrue(retrievedRankingUpdate.isFdNotNullAndClosed());
|
||||||
|
NotificationListenerService.Ranking retrievedRanking =
|
||||||
|
new NotificationListenerService.Ranking();
|
||||||
|
assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking));
|
||||||
|
assertEquals(123, retrievedRanking.getRank());
|
||||||
|
assertTrue(retrievedRankingUpdate.equals(rankingUpdate));
|
||||||
|
parceledRankingUpdate.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRankingUpdate_emptyParcelInCheck() {
|
||||||
|
NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
|
||||||
|
NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
|
||||||
|
new NotificationListenerService.Ranking[]{ranking});
|
||||||
|
|
||||||
|
Parcel parceledRankingUpdate = Parcel.obtain();
|
||||||
|
rankingUpdate.writeToParcel(parceledRankingUpdate, 0);
|
||||||
|
|
||||||
|
// This will fail to read the parceledRankingUpdate, because the data position hasn't
|
||||||
|
// been reset, so it'll find no data to read.
|
||||||
|
NotificationRankingUpdate retrievedRankingUpdate = new NotificationRankingUpdate(
|
||||||
|
parceledRankingUpdate);
|
||||||
|
assertNull(retrievedRankingUpdate.getRankingMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRankingUpdate_describeContents() {
|
||||||
|
NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
|
||||||
|
NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
|
||||||
|
new NotificationListenerService.Ranking[]{ranking});
|
||||||
|
assertEquals(0, rankingUpdate.describeContents());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRankingUpdate_equals() {
|
||||||
|
NotificationListenerService.Ranking ranking = createTestRanking(TEST_KEY, 123);
|
||||||
|
NotificationRankingUpdate rankingUpdate = new NotificationRankingUpdate(
|
||||||
|
new NotificationListenerService.Ranking[]{ranking});
|
||||||
|
// Reflexive equality.
|
||||||
|
assertTrue(rankingUpdate.equals(rankingUpdate));
|
||||||
|
// Null or wrong class inequality.
|
||||||
|
assertFalse(rankingUpdate.equals(null));
|
||||||
|
assertFalse(rankingUpdate.equals(ranking));
|
||||||
|
|
||||||
|
// Different ranking contents inequality.
|
||||||
|
NotificationListenerService.Ranking ranking2 = createTestRanking(TEST_KEY, 456);
|
||||||
|
NotificationRankingUpdate rankingUpdate2 = new NotificationRankingUpdate(
|
||||||
|
new NotificationListenerService.Ranking[]{ranking2});
|
||||||
|
assertFalse(rankingUpdate.equals(rankingUpdate2));
|
||||||
|
|
||||||
|
// Same ranking contents equality.
|
||||||
|
ranking2 = createTestRanking(TEST_KEY, 123);
|
||||||
|
rankingUpdate2 = new NotificationRankingUpdate(
|
||||||
|
new NotificationListenerService.Ranking[]{ranking2});
|
||||||
|
assertTrue(rankingUpdate.equals(rankingUpdate2));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user