diff --git a/core/java/android/app/usage/TimeSparseArray.java b/core/java/android/app/usage/TimeSparseArray.java index 7974fa706285e..5764fa85579c6 100644 --- a/core/java/android/app/usage/TimeSparseArray.java +++ b/core/java/android/app/usage/TimeSparseArray.java @@ -17,6 +17,7 @@ package android.app.usage; import android.util.LongSparseArray; +import android.util.Slog; /** * An array that indexes by a long timestamp, representing milliseconds since the epoch. @@ -24,6 +25,8 @@ import android.util.LongSparseArray; * {@hide} */ public class TimeSparseArray extends LongSparseArray { + private static final String TAG = TimeSparseArray.class.getSimpleName(); + public TimeSparseArray() { super(); } @@ -69,6 +72,25 @@ public class TimeSparseArray extends LongSparseArray { } } + /** + * {@inheritDoc} + * + * Overridden to ensure no collisions. The key (time in milliseconds) is incremented till an + * empty place is found. + */ + @Override + public void put(long key, E value) { + final long origKey = key; + while (indexOfKey(key) >= 0) { + key++; + } + if (origKey != key) { + Slog.w(TAG, "Value " + value + " supposed to be inserted at " + origKey + + " displaced to " + key); + } + super.put(key, value); + } + /** * Finds the index of the first element whose timestamp is less than or equal to * the given time. diff --git a/core/tests/coretests/src/android/app/usage/TimeSparseArrayTest.java b/core/tests/coretests/src/android/app/usage/TimeSparseArrayTest.java new file mode 100644 index 0000000000000..db4674070f1d2 --- /dev/null +++ b/core/tests/coretests/src/android/app/usage/TimeSparseArrayTest.java @@ -0,0 +1,47 @@ +/* + * 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.app.usage; + +import static org.junit.Assert.assertTrue; + +import android.os.SystemClock; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class TimeSparseArrayTest { + @Test + public void testDuplicateKeysNotDropped() { + final TimeSparseArray testTimeSparseArray = new TimeSparseArray<>(); + final long key = SystemClock.elapsedRealtime(); + for (int i = 0; i < 5; i++) { + testTimeSparseArray.put(key, i); + } + for (int i = 0; i < 5; i++) { + final int valueIndex = testTimeSparseArray.indexOfValue(i); + assertTrue("Value " + i + " not found; intended key: " + key , valueIndex >= 0); + final long keyForValue = testTimeSparseArray.keyAt(valueIndex); + assertTrue("Value " + i + " stored too far (at " + keyForValue + ") from intended key " + + key, Math.abs(keyForValue - key) < 100); + } + } +}