Loading core/java/android/hardware/radio/RadioMetadata.java +25 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,9 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; /** Loading Loading @@ -257,9 +260,22 @@ public final class RadioMetadata implements Parcelable { private final Bundle mBundle; // Lazily computed hash code based upon the contents of mBundle. private Integer mHashCode; @Override public int hashCode() { return mBundle.hashCode(); if (mHashCode == null) { List<String> keys = new ArrayList<String>(mBundle.keySet()); keys.sort(null); Object[] objs = new Object[2 * keys.size()]; for (int i = 0; i < keys.size(); i++) { objs[2 * i] = keys.get(i); objs[2 * i + 1] = mBundle.get(keys.get(i)); } mHashCode = Arrays.hashCode(objs); } return mHashCode; } @Override Loading Loading @@ -626,6 +642,8 @@ public final class RadioMetadata implements Parcelable { String key = getKeyFromNativeKey(nativeKey); try { putInt(mBundle, key, value); // Invalidate mHashCode to force it to be recomputed. mHashCode = null; return 0; } catch (IllegalArgumentException ex) { return -1; Loading @@ -639,6 +657,8 @@ public final class RadioMetadata implements Parcelable { return -1; } mBundle.putString(key, value); // Invalidate mHashCode to force it to be recomputed. mHashCode = null; return 0; } Loading @@ -653,6 +673,8 @@ public final class RadioMetadata implements Parcelable { bmp = BitmapFactory.decodeByteArray(value, 0, value.length); if (bmp != null) { mBundle.putParcelable(key, bmp); // Invalidate mHashCode to force it to be recomputed. mHashCode = null; return 0; } } catch (Exception e) { Loading @@ -668,6 +690,8 @@ public final class RadioMetadata implements Parcelable { } mBundle.putParcelable(key, new RadioMetadata.Clock( utcEpochSeconds, timezoneOffsetInMinutes)); // Invalidate mHashCode to force it to be recomputed. mHashCode = null; return 0; } } core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java +1 −59 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.broadcastradio.hal2; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; Loading @@ -41,7 +40,6 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; Loading @@ -49,7 +47,6 @@ import org.mockito.stubbing.Answer; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Tests for v2 HAL RadioModule. Loading Loading @@ -293,61 +290,6 @@ public class StartProgramListUpdatesFanoutTest { } ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet, removedSet); verify(clientMock).onProgramListUpdated(argThat(new ChunkMatcher(expectedChunk))); verify(clientMock).onProgramListUpdated(expectedChunk); } // TODO(b/130750904): Remove this class and replace "argThat(new ChunkMatcher(chunk))" with // "eq(chunk)". // // Ideally, this class wouldn't exist, but currently RadioManager.ProgramInfo#hashCode() can // return different values for objects that satisfy ProgramInfo#equals(). As a short term // workaround, this class performs the O(N^2) comparison between the Chunks' mModified sets. // // To test if ProgramInfo#hashCode() has been fixed, remove commenting from // testProgramInfoHashCode() below. private class ChunkMatcher implements ArgumentMatcher<ProgramList.Chunk> { private final ProgramList.Chunk mExpected; ChunkMatcher(ProgramList.Chunk expected) { mExpected = expected; } @Override public boolean matches(ProgramList.Chunk actual) { if ((mExpected.isPurge() != actual.isPurge()) || (mExpected.isComplete() != actual.isComplete()) || (!mExpected.getRemoved().equals(actual.getRemoved()))) { return false; } Set<RadioManager.ProgramInfo> expectedModified = mExpected.getModified(); Set<RadioManager.ProgramInfo> actualModified = new HashSet<>(actual.getModified()); if (expectedModified.size() != actualModified.size()) { return false; } for (RadioManager.ProgramInfo expectedInfo : expectedModified) { boolean found = false; for (RadioManager.ProgramInfo actualInfo : actualModified) { if (expectedInfo.equals(actualInfo)) { found = true; actualModified.remove(actualInfo); break; } } if (!found) { return false; } } return true; } } // @Test // public void testProgramInfoHashCode() { // RadioManager.ProgramInfo info1 = TestUtils.makeProgramInfo( // ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0); // RadioManager.ProgramInfo info2 = TestUtils.makeProgramInfo( // ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0); // assertEquals(info1, info2); // assertEquals(info1.hashCode(), info2.hashCode()); // } } Loading
core/java/android/hardware/radio/RadioMetadata.java +25 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,9 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; /** Loading Loading @@ -257,9 +260,22 @@ public final class RadioMetadata implements Parcelable { private final Bundle mBundle; // Lazily computed hash code based upon the contents of mBundle. private Integer mHashCode; @Override public int hashCode() { return mBundle.hashCode(); if (mHashCode == null) { List<String> keys = new ArrayList<String>(mBundle.keySet()); keys.sort(null); Object[] objs = new Object[2 * keys.size()]; for (int i = 0; i < keys.size(); i++) { objs[2 * i] = keys.get(i); objs[2 * i + 1] = mBundle.get(keys.get(i)); } mHashCode = Arrays.hashCode(objs); } return mHashCode; } @Override Loading Loading @@ -626,6 +642,8 @@ public final class RadioMetadata implements Parcelable { String key = getKeyFromNativeKey(nativeKey); try { putInt(mBundle, key, value); // Invalidate mHashCode to force it to be recomputed. mHashCode = null; return 0; } catch (IllegalArgumentException ex) { return -1; Loading @@ -639,6 +657,8 @@ public final class RadioMetadata implements Parcelable { return -1; } mBundle.putString(key, value); // Invalidate mHashCode to force it to be recomputed. mHashCode = null; return 0; } Loading @@ -653,6 +673,8 @@ public final class RadioMetadata implements Parcelable { bmp = BitmapFactory.decodeByteArray(value, 0, value.length); if (bmp != null) { mBundle.putParcelable(key, bmp); // Invalidate mHashCode to force it to be recomputed. mHashCode = null; return 0; } } catch (Exception e) { Loading @@ -668,6 +690,8 @@ public final class RadioMetadata implements Parcelable { } mBundle.putParcelable(key, new RadioMetadata.Clock( utcEpochSeconds, timezoneOffsetInMinutes)); // Invalidate mHashCode to force it to be recomputed. mHashCode = null; return 0; } }
core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java +1 −59 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.broadcastradio.hal2; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; Loading @@ -41,7 +40,6 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; Loading @@ -49,7 +47,6 @@ import org.mockito.stubbing.Answer; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Tests for v2 HAL RadioModule. Loading Loading @@ -293,61 +290,6 @@ public class StartProgramListUpdatesFanoutTest { } ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet, removedSet); verify(clientMock).onProgramListUpdated(argThat(new ChunkMatcher(expectedChunk))); verify(clientMock).onProgramListUpdated(expectedChunk); } // TODO(b/130750904): Remove this class and replace "argThat(new ChunkMatcher(chunk))" with // "eq(chunk)". // // Ideally, this class wouldn't exist, but currently RadioManager.ProgramInfo#hashCode() can // return different values for objects that satisfy ProgramInfo#equals(). As a short term // workaround, this class performs the O(N^2) comparison between the Chunks' mModified sets. // // To test if ProgramInfo#hashCode() has been fixed, remove commenting from // testProgramInfoHashCode() below. private class ChunkMatcher implements ArgumentMatcher<ProgramList.Chunk> { private final ProgramList.Chunk mExpected; ChunkMatcher(ProgramList.Chunk expected) { mExpected = expected; } @Override public boolean matches(ProgramList.Chunk actual) { if ((mExpected.isPurge() != actual.isPurge()) || (mExpected.isComplete() != actual.isComplete()) || (!mExpected.getRemoved().equals(actual.getRemoved()))) { return false; } Set<RadioManager.ProgramInfo> expectedModified = mExpected.getModified(); Set<RadioManager.ProgramInfo> actualModified = new HashSet<>(actual.getModified()); if (expectedModified.size() != actualModified.size()) { return false; } for (RadioManager.ProgramInfo expectedInfo : expectedModified) { boolean found = false; for (RadioManager.ProgramInfo actualInfo : actualModified) { if (expectedInfo.equals(actualInfo)) { found = true; actualModified.remove(actualInfo); break; } } if (!found) { return false; } } return true; } } // @Test // public void testProgramInfoHashCode() { // RadioManager.ProgramInfo info1 = TestUtils.makeProgramInfo( // ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0); // RadioManager.ProgramInfo info2 = TestUtils.makeProgramInfo( // ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0); // assertEquals(info1, info2); // assertEquals(info1.hashCode(), info2.hashCode()); // } }