Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00f0fc4c authored by Weilin Xu's avatar Weilin Xu
Browse files

Use unique identifier in radio manager and service

Used unique program idenfier as key for programs in program list and
program info caches of broadcast radio service clients for HIDL 2.0
and AIDL HAL.

Bug: 273967346
Test: atest ProgramListTest
Change-Id: Ife9bc40bc50807767a13aef141e63aca136cba0e
parent 81b28863
Loading
Loading
Loading
Loading
+67 −29
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
import android.util.ArraySet;

import com.android.internal.annotations.GuardedBy;

@@ -34,7 +35,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * @hide
@@ -45,8 +45,8 @@ public final class ProgramList implements AutoCloseable {
    private final Object mLock = new Object();

    @GuardedBy("mLock")
    private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mPrograms =
            new ArrayMap<>();
    private final Map<ProgramSelector.Identifier, Map<UniqueProgramIdentifier,
            RadioManager.ProgramInfo>> mPrograms = new ArrayMap<>();

    @GuardedBy("mLock")
    private final List<ListCallback> mListCallbacks = new ArrayList<>();
@@ -193,7 +193,7 @@ public final class ProgramList implements AutoCloseable {

    void apply(Chunk chunk) {
        List<ProgramSelector.Identifier> removedList = new ArrayList<>();
        List<ProgramSelector.Identifier> changedList = new ArrayList<>();
        Set<ProgramSelector.Identifier> changedSet = new ArraySet<>();
        List<ProgramList.ListCallback> listCallbacksCopied;
        List<OnCompleteListener> onCompleteListenersCopied = new ArrayList<>();
        synchronized (mLock) {
@@ -203,19 +203,27 @@ public final class ProgramList implements AutoCloseable {
            listCallbacksCopied = new ArrayList<>(mListCallbacks);

            if (chunk.isPurge()) {
                Iterator<Map.Entry<ProgramSelector.Identifier, RadioManager.ProgramInfo>>
                        programsIterator = mPrograms.entrySet().iterator();
                Iterator<Map.Entry<ProgramSelector.Identifier, Map<UniqueProgramIdentifier,
                        RadioManager.ProgramInfo>>> programsIterator =
                        mPrograms.entrySet().iterator();
                while (programsIterator.hasNext()) {
                    RadioManager.ProgramInfo removed = programsIterator.next().getValue();
                    if (removed != null) {
                        removedList.add(removed.getSelector().getPrimaryId());
                    Map.Entry<ProgramSelector.Identifier, Map<UniqueProgramIdentifier,
                            RadioManager.ProgramInfo>> removed = programsIterator.next();
                    if (removed.getValue() != null) {
                        removedList.add(removed.getKey());
                    }
                    programsIterator.remove();
                }
            }

            chunk.getRemoved().stream().forEach(id -> removeLocked(id, removedList));
            chunk.getModified().stream().forEach(info -> putLocked(info, changedList));
            Iterator<UniqueProgramIdentifier> removedIterator = chunk.getRemoved().iterator();
            while (removedIterator.hasNext()) {
                removeLocked(removedIterator.next(), removedList);
            }
            Iterator<RadioManager.ProgramInfo> modifiedIterator = chunk.getModified().iterator();
            while (modifiedIterator.hasNext()) {
                putLocked(modifiedIterator.next(), changedSet);
            }

            if (chunk.isComplete()) {
                mIsComplete = true;
@@ -228,9 +236,11 @@ public final class ProgramList implements AutoCloseable {
                listCallbacksCopied.get(cbIndex).onItemRemoved(removedList.get(i));
            }
        }
        for (int i = 0; i < changedList.size(); i++) {
        Iterator<ProgramSelector.Identifier> changedIterator = changedSet.iterator();
        while (changedIterator.hasNext()) {
            ProgramSelector.Identifier changedId = changedIterator.next();
            for (int cbIndex = 0; cbIndex < listCallbacksCopied.size(); cbIndex++) {
                listCallbacksCopied.get(cbIndex).onItemChanged(changedList.get(i));
                listCallbacksCopied.get(cbIndex).onItemChanged(changedId);
            }
        }
        if (chunk.isComplete()) {
@@ -242,20 +252,31 @@ public final class ProgramList implements AutoCloseable {

    @GuardedBy("mLock")
    private void putLocked(RadioManager.ProgramInfo value,
            List<ProgramSelector.Identifier> changedIdentifierList) {
        ProgramSelector.Identifier key = value.getSelector().getPrimaryId();
        mPrograms.put(Objects.requireNonNull(key), value);
        ProgramSelector.Identifier sel = value.getSelector().getPrimaryId();
        changedIdentifierList.add(sel);
            Set<ProgramSelector.Identifier> changedIdentifierSet) {
        UniqueProgramIdentifier key = new UniqueProgramIdentifier(
                value.getSelector());
        ProgramSelector.Identifier primaryKey = Objects.requireNonNull(key.getPrimaryId());
        if (!mPrograms.containsKey(primaryKey)) {
            mPrograms.put(primaryKey, new ArrayMap<>());
        }
        mPrograms.get(primaryKey).put(key, value);
        changedIdentifierSet.add(primaryKey);
    }

    @GuardedBy("mLock")
    private void removeLocked(ProgramSelector.Identifier key,
    private void removeLocked(UniqueProgramIdentifier key,
            List<ProgramSelector.Identifier> removedIdentifierList) {
        RadioManager.ProgramInfo removed = mPrograms.remove(Objects.requireNonNull(key));
        ProgramSelector.Identifier primaryKey = Objects.requireNonNull(key.getPrimaryId());
        if (!mPrograms.containsKey(primaryKey)) {
            return;
        }
        Map<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries = mPrograms
                .get(primaryKey);
        RadioManager.ProgramInfo removed = entries.remove(Objects.requireNonNull(key));
        if (removed == null) return;
        ProgramSelector.Identifier sel = removed.getSelector().getPrimaryId();
        removedIdentifierList.add(sel);
        if (entries.size() == 0) {
            removedIdentifierList.add(primaryKey);
        }
    }

    /**
@@ -264,10 +285,21 @@ public final class ProgramList implements AutoCloseable {
     * @return the new List<> object; it won't receive any further updates
     */
    public @NonNull List<RadioManager.ProgramInfo> toList() {
        List<RadioManager.ProgramInfo> list = new ArrayList<>();
        synchronized (mLock) {
            return mPrograms.values().stream().collect(Collectors.toList());
            Iterator<Map.Entry<ProgramSelector.Identifier, Map<UniqueProgramIdentifier,
                    RadioManager.ProgramInfo>>> listIterator = mPrograms.entrySet().iterator();
            while (listIterator.hasNext()) {
                Iterator<Map.Entry<UniqueProgramIdentifier,
                        RadioManager.ProgramInfo>> prorgramsIterator = listIterator.next()
                        .getValue().entrySet().iterator();
                while (prorgramsIterator.hasNext()) {
                    list.add(prorgramsIterator.next().getValue());
                }
            }
        }
        return list;
    }

    /**
     * Returns the program with a specified primary identifier.
@@ -276,9 +308,15 @@ public final class ProgramList implements AutoCloseable {
     * @return the program info, or null if there is no such program on the list
     */
    public @Nullable RadioManager.ProgramInfo get(@NonNull ProgramSelector.Identifier id) {
        Map<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries;
        synchronized (mLock) {
            return mPrograms.get(Objects.requireNonNull(id));
            entries = mPrograms.get(Objects.requireNonNull(id,
                    "Primary identifier can not be null"));
        }
        if (entries == null) {
            return null;
        }
        return entries.entrySet().iterator().next().getValue();
    }

    /**
@@ -404,7 +442,7 @@ public final class ProgramList implements AutoCloseable {
         * Checks, if non-tunable entries that define tree structure on the
         * program list (i.e. DAB ensembles) should be included.
         *
         * @see {@link ProgramSelector.Identifier#isCategory()}
         * @see ProgramSelector.Identifier#isCategoryType()
         */
        public boolean areCategoriesIncluded() {
            return mIncludeCategories;
@@ -459,11 +497,11 @@ public final class ProgramList implements AutoCloseable {
        private final boolean mPurge;
        private final boolean mComplete;
        private final @NonNull Set<RadioManager.ProgramInfo> mModified;
        private final @NonNull Set<ProgramSelector.Identifier> mRemoved;
        private final @NonNull Set<UniqueProgramIdentifier> mRemoved;

        public Chunk(boolean purge, boolean complete,
                @Nullable Set<RadioManager.ProgramInfo> modified,
                @Nullable Set<ProgramSelector.Identifier> removed) {
                @Nullable Set<UniqueProgramIdentifier> removed) {
            mPurge = purge;
            mComplete = complete;
            mModified = (modified != null) ? modified : Collections.emptySet();
@@ -474,7 +512,7 @@ public final class ProgramList implements AutoCloseable {
            mPurge = in.readByte() != 0;
            mComplete = in.readByte() != 0;
            mModified = Utils.createSet(in, RadioManager.ProgramInfo.CREATOR);
            mRemoved = Utils.createSet(in, ProgramSelector.Identifier.CREATOR);
            mRemoved = Utils.createSet(in, UniqueProgramIdentifier.CREATOR);
        }

        @Override
@@ -512,7 +550,7 @@ public final class ProgramList implements AutoCloseable {
            return mModified;
        }

        public @NonNull Set<ProgramSelector.Identifier> getRemoved() {
        public @NonNull Set<UniqueProgramIdentifier> getRemoved() {
            return mRemoved;
        }

+5 −30
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.hardware.broadcastradio.Metadata;
import android.hardware.broadcastradio.ProgramFilter;
import android.hardware.broadcastradio.ProgramIdentifier;
import android.hardware.broadcastradio.ProgramInfo;
import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.broadcastradio.Properties;
import android.hardware.broadcastradio.Result;
import android.hardware.broadcastradio.VendorKeyValue;
@@ -38,6 +37,7 @@ import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
import android.hardware.radio.RadioTuner;
import android.hardware.radio.UniqueProgramIdentifier;
import android.os.Build;
import android.os.ParcelableException;
import android.os.ServiceSpecificException;
@@ -553,31 +553,6 @@ final class ConversionUtils {
        return hwFilter;
    }

    static ProgramList.Chunk chunkFromHalProgramListChunk(ProgramListChunk chunk) {
        Set<RadioManager.ProgramInfo> modified = new ArraySet<>(chunk.modified.length);
        for (int i = 0; i < chunk.modified.length; i++) {
            RadioManager.ProgramInfo modifiedInfo =
                    programInfoFromHalProgramInfo(chunk.modified[i]);
            if (modifiedInfo == null) {
                Slogf.w(TAG, "Program info %s in program list chunk is not valid",
                        chunk.modified[i]);
                continue;
            }
            modified.add(modifiedInfo);
        }
        Set<ProgramSelector.Identifier> removed = new ArraySet<>();
        if (chunk.removed != null) {
            for (int i = 0; i < chunk.removed.length; i++) {
                ProgramSelector.Identifier removedId =
                        identifierFromHalProgramIdentifier(chunk.removed[i]);
                if (removedId != null) {
                    removed.add(removedId);
                }
            }
        }
        return new ProgramList.Chunk(chunk.purge, chunk.complete, modified, removed);
    }

    private static boolean isNewIdentifierInU(ProgramSelector.Identifier id) {
        return id.getType() == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT;
    }
@@ -630,11 +605,11 @@ final class ConversionUtils {
                modified.add(info);
            }
        }
        Set<ProgramSelector.Identifier> removed = new ArraySet<>();
        Iterator<ProgramSelector.Identifier> removedIterator = chunk.getRemoved().iterator();
        Set<UniqueProgramIdentifier> removed = new ArraySet<>();
        Iterator<UniqueProgramIdentifier> removedIterator = chunk.getRemoved().iterator();
        while (removedIterator.hasNext()) {
            ProgramSelector.Identifier id = removedIterator.next();
            if (!isNewIdentifierInU(id)) {
            UniqueProgramIdentifier id = removedIterator.next();
            if (!isNewIdentifierInU(id.getPrimaryId())) {
                removed.add(id);
            }
        }
+108 −53
Original line number Diff line number Diff line
@@ -17,9 +17,11 @@
package com.android.server.broadcastradio.aidl;

import android.annotation.Nullable;
import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.ProgramSelector.Identifier;
import android.hardware.radio.RadioManager;
import android.hardware.radio.UniqueProgramIdentifier;
import android.util.ArrayMap;
import android.util.ArraySet;

@@ -30,7 +32,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
@@ -40,24 +41,25 @@ final class ProgramInfoCache {

    private static final String TAG = "BcRadioAidlSrv.cache";
    /**
     * Maximum number of {@link RadioManager#ProgramInfo} elements that will be put into a
     * Maximum number of {@link RadioManager.ProgramInfo} elements that will be put into a
     * ProgramList.Chunk.mModified array. Used to try to ensure a single ProgramList.Chunk
     * stays within the AIDL data size limit.
     */
    private static final int MAX_NUM_MODIFIED_PER_CHUNK = 100;

    /**
     * Maximum number of {@link ProgramSelector#Identifier} elements that will be put
     * into the removed array of {@link ProgramList#Chunk}. Used to try to ensure a single
     * {@link ProgramList#Chunk} stays within the AIDL data size limit.
     * Maximum number of {@link Identifier} elements that will be put into the removed array
     * of {@link ProgramList.Chunk}. Use to attempt and keep the single {@link ProgramList.Chunk}
     * within the AIDL data size limit.
     */
    private static final int MAX_NUM_REMOVED_PER_CHUNK = 500;

    /**
     * Map from primary identifier to corresponding {@link RadioManager#ProgramInfo}.
     * Map from primary identifier to {@link UniqueProgramIdentifier} and then to corresponding
     * {@link RadioManager.ProgramInfo}.
     */
    private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mProgramInfoMap =
            new ArrayMap<>();
    private final ArrayMap<Identifier, ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo>>
            mProgramInfoMap = new ArrayMap<>();

    /**
     * Flag indicating whether mProgramInfoMap is considered complete based upon the received
@@ -81,13 +83,17 @@ final class ProgramInfoCache {
        mFilter = filter;
        mComplete = complete;
        for (int i = 0; i < programInfos.length; i++) {
            mProgramInfoMap.put(programInfos[i].getSelector().getPrimaryId(), programInfos[i]);
            putInfo(programInfos[i]);
        }
    }

    @VisibleForTesting
    List<RadioManager.ProgramInfo> toProgramInfoList() {
        return new ArrayList<>(mProgramInfoMap.values());
        List<RadioManager.ProgramInfo> programInfoList = new ArrayList<>();
        for (int index = 0; index < mProgramInfoMap.size(); index++) {
            programInfoList.addAll(mProgramInfoMap.valueAt(index).values());
        }
        return programInfoList;
    }

    @Override
@@ -97,10 +103,14 @@ final class ProgramInfoCache {
        sb.append(", mFilter = ");
        sb.append(mFilter);
        sb.append(", mProgramInfoMap = [");
        mProgramInfoMap.forEach((id, programInfo) -> {
        for (int index = 0; index < mProgramInfoMap.size(); index++) {
            ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries =
                    mProgramInfoMap.valueAt(index);
            for (int entryIndex = 0; entryIndex < entries.size(); entryIndex++) {
                sb.append(", ");
            sb.append(programInfo);
        });
                sb.append(entries.valueAt(entryIndex));
            }
        }
        return sb.append("])").toString();
    }

@@ -114,8 +124,7 @@ final class ProgramInfoCache {
    }

    @VisibleForTesting
    void updateFromHalProgramListChunk(
            android.hardware.broadcastradio.ProgramListChunk chunk) {
    void updateFromHalProgramListChunk(ProgramListChunk chunk) {
        if (chunk.purge) {
            mProgramInfoMap.clear();
        }
@@ -125,8 +134,9 @@ final class ProgramInfoCache {
            if (programInfo == null) {
                Slogf.e(TAG, "Program info in program info %s in chunk is not valid",
                        chunk.modified[i]);
                continue;
            }
            mProgramInfoMap.put(programInfo.getSelector().getPrimaryId(), programInfo);
            putInfo(programInfo);
        }
        if (chunk.removed != null) {
            for (int i = 0; i < chunk.removed.length; i++) {
@@ -155,25 +165,31 @@ final class ProgramInfoCache {
            purge = true;
        }

        Set<RadioManager.ProgramInfo> modified = new ArraySet<>();
        Set<ProgramSelector.Identifier> removed = new ArraySet<>(mProgramInfoMap.keySet());
        for (Map.Entry<ProgramSelector.Identifier, RadioManager.ProgramInfo> entry
                : other.mProgramInfoMap.entrySet()) {
            ProgramSelector.Identifier id = entry.getKey();
        ArraySet<RadioManager.ProgramInfo> modified = new ArraySet<>();
        ArraySet<UniqueProgramIdentifier> removed = new ArraySet<>();
        for (int index = 0; index < mProgramInfoMap.size(); index++) {
            removed.addAll(mProgramInfoMap.valueAt(index).keySet());
        }
        for (int index = 0; index < other.mProgramInfoMap.size(); index++) {
            Identifier id = other.mProgramInfoMap.keyAt(index);
            if (!passesFilter(id)) {
                continue;
            }
            removed.remove(id);
            ArrayMap<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries =
                    other.mProgramInfoMap.valueAt(index);
            for (int entryIndex = 0; entryIndex < entries.size(); entryIndex++) {
                removed.remove(entries.keyAt(entryIndex));

            RadioManager.ProgramInfo newInfo = entry.getValue();
                RadioManager.ProgramInfo newInfo = entries.valueAt(entryIndex);
                if (!shouldIncludeInModified(newInfo)) {
                    continue;
                }
            mProgramInfoMap.put(id, newInfo);
                putInfo(newInfo);
                modified.add(newInfo);
            }
        for (ProgramSelector.Identifier rem : removed) {
            mProgramInfoMap.remove(rem);
        }
        for (int removedIndex = 0; removedIndex < removed.size(); removedIndex++) {
            removeUniqueId(removed.valueAt(removedIndex));
        }
        mComplete = other.mComplete;
        return buildChunks(purge, mComplete, modified, maxNumModifiedPerChunk, removed,
@@ -181,45 +197,61 @@ final class ProgramInfoCache {
    }

    @Nullable
    List<ProgramList.Chunk> filterAndApplyChunk(ProgramList.Chunk chunk) {
    List<ProgramList.Chunk> filterAndApplyChunk(ProgramListChunk chunk) {
        return filterAndApplyChunkInternal(chunk, MAX_NUM_MODIFIED_PER_CHUNK,
                MAX_NUM_REMOVED_PER_CHUNK);
    }

    @VisibleForTesting
    @Nullable
    List<ProgramList.Chunk> filterAndApplyChunkInternal(ProgramList.Chunk chunk,
    List<ProgramList.Chunk> filterAndApplyChunkInternal(ProgramListChunk chunk,
            int maxNumModifiedPerChunk, int maxNumRemovedPerChunk) {
        if (chunk.isPurge()) {
        if (chunk.purge) {
            mProgramInfoMap.clear();
        }

        Set<RadioManager.ProgramInfo> modified = new ArraySet<>();
        Set<ProgramSelector.Identifier> removed = new ArraySet<>();
        for (RadioManager.ProgramInfo info : chunk.getModified()) {
            ProgramSelector.Identifier id = info.getSelector().getPrimaryId();
            if (!passesFilter(id) || !shouldIncludeInModified(info)) {
        for (int i = 0; i < chunk.modified.length; i++) {
            RadioManager.ProgramInfo info =
                    ConversionUtils.programInfoFromHalProgramInfo(chunk.modified[i]);
            if (info == null) {
                Slogf.w(TAG, "Program info %s in program list chunk is not valid",
                        chunk.modified[i]);
                continue;
            }
            mProgramInfoMap.put(id, info);
            Identifier primaryId = info.getSelector().getPrimaryId();
            if (!passesFilter(primaryId) || !shouldIncludeInModified(info)) {
                continue;
            }
            putInfo(info);
            modified.add(info);
        }
        for (ProgramSelector.Identifier id : chunk.getRemoved()) {
            if (mProgramInfoMap.containsKey(id)) {
                mProgramInfoMap.remove(id);
                removed.add(id);
        Set<UniqueProgramIdentifier> removed = new ArraySet<>();
        if (chunk.removed != null) {
            for (int i = 0; i < chunk.removed.length; i++) {
                Identifier removedId = ConversionUtils.identifierFromHalProgramIdentifier(
                        chunk.removed[i]);
                if (removedId == null) {
                    Slogf.w(TAG, "Removed identifier %s in program list chunk is not valid",
                            chunk.modified[i]);
                    continue;
                }
                if (mProgramInfoMap.containsKey(removedId)) {
                    removed.addAll(mProgramInfoMap.get(removedId).keySet());
                    mProgramInfoMap.remove(removedId);
                }
            }
        if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.isComplete()
                && !chunk.isPurge()) {
        }
        if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.complete
                && !chunk.purge) {
            return null;
        }
        mComplete = chunk.isComplete();
        return buildChunks(chunk.isPurge(), mComplete, modified, maxNumModifiedPerChunk, removed,
        mComplete = chunk.complete;
        return buildChunks(chunk.purge, mComplete, modified, maxNumModifiedPerChunk, removed,
                maxNumRemovedPerChunk);
    }

    private boolean passesFilter(ProgramSelector.Identifier id) {
    private boolean passesFilter(Identifier id) {
        if (mFilter == null) {
            return true;
        }
@@ -233,9 +265,32 @@ final class ProgramInfoCache {
        return mFilter.areCategoriesIncluded() || !id.isCategoryType();
    }

    private void putInfo(RadioManager.ProgramInfo info) {
        Identifier primaryId = info.getSelector().getPrimaryId();
        if (!mProgramInfoMap.containsKey(primaryId)) {
            mProgramInfoMap.put(primaryId, new ArrayMap<>());
        }
        mProgramInfoMap.get(primaryId).put(new UniqueProgramIdentifier(info.getSelector()), info);
    }

    private void removeUniqueId(UniqueProgramIdentifier uniqueId) {
        Identifier primaryId =  uniqueId.getPrimaryId();
        if (!mProgramInfoMap.containsKey(primaryId)) {
            return;
        }
        mProgramInfoMap.get(primaryId).remove(uniqueId);
        if (mProgramInfoMap.get(primaryId).isEmpty()) {
            mProgramInfoMap.remove(primaryId);
        }
    }

    private boolean shouldIncludeInModified(RadioManager.ProgramInfo newInfo) {
        RadioManager.ProgramInfo oldInfo = mProgramInfoMap.get(
                newInfo.getSelector().getPrimaryId());
        Identifier primaryId = newInfo.getSelector().getPrimaryId();
        RadioManager.ProgramInfo oldInfo = null;
        if (mProgramInfoMap.containsKey(primaryId)) {
            UniqueProgramIdentifier uniqueId = new UniqueProgramIdentifier(newInfo.getSelector());
            oldInfo = mProgramInfoMap.get(primaryId).get(uniqueId);
        }
        if (oldInfo == null) {
            return true;
        }
@@ -251,7 +306,7 @@ final class ProgramInfoCache {

    private static List<ProgramList.Chunk> buildChunks(boolean purge, boolean complete,
            @Nullable Collection<RadioManager.ProgramInfo> modified, int maxNumModifiedPerChunk,
            @Nullable Collection<ProgramSelector.Identifier> removed, int maxNumRemovedPerChunk) {
            @Nullable Collection<UniqueProgramIdentifier> removed, int maxNumRemovedPerChunk) {
        // Communication protocol requires that if purge is set, removed is empty.
        if (purge) {
            removed = null;
@@ -275,7 +330,7 @@ final class ProgramInfoCache {
        int modifiedPerChunk = 0;
        int removedPerChunk = 0;
        Iterator<RadioManager.ProgramInfo> modifiedIter = null;
        Iterator<ProgramSelector.Identifier> removedIter = null;
        Iterator<UniqueProgramIdentifier> removedIter = null;
        if (modified != null) {
            modifiedPerChunk = roundUpFraction(modified.size(), numChunks);
            modifiedIter = modified.iterator();
@@ -287,7 +342,7 @@ final class ProgramInfoCache {
        List<ProgramList.Chunk> chunks = new ArrayList<>(numChunks);
        for (int i = 0; i < numChunks; i++) {
            ArraySet<RadioManager.ProgramInfo> modifiedChunk = new ArraySet<>();
            ArraySet<ProgramSelector.Identifier> removedChunk = new ArraySet<>();
            ArraySet<UniqueProgramIdentifier> removedChunk = new ArraySet<>();
            if (modifiedIter != null) {
                for (int j = 0; j < modifiedPerChunk && modifiedIter.hasNext(); j++) {
                    modifiedChunk.add(modifiedIter.next());
+3 −4
Original line number Diff line number Diff line
@@ -142,12 +142,11 @@ final class RadioModule {
        public void onProgramListUpdated(ProgramListChunk programListChunk) {
            fireLater(() -> {
                synchronized (mLock) {
                    android.hardware.radio.ProgramList.Chunk chunk =
                            ConversionUtils.chunkFromHalProgramListChunk(programListChunk);
                    mProgramInfoCache.filterAndApplyChunk(chunk);
                    mProgramInfoCache.filterAndApplyChunk(programListChunk);

                    for (int i = 0; i < mAidlTunerSessions.size(); i++) {
                        mAidlTunerSessions.valueAt(i).onMergedProgramListUpdateFromHal(chunk);
                        mAidlTunerSessions.valueAt(i).onMergedProgramListUpdateFromHal(
                                programListChunk);
                    }
                }
            });
+2 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading