CarResultStubMap.java
/*
* Copyright 2021 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 androidx.car.app.hardware.common;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static java.util.Objects.requireNonNull;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.car.app.serialization.Bundleable;
import androidx.car.app.serialization.BundlerException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Executor;
/**
* Convenience class wrapping calls to the car host that involve subscribing and unsubscribing to
* an ongoing listener.
*
* @param <T> represents the result data type which this stub is returning
* @param <U> represents the parameter data type which this stub is indexing on
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
public class CarResultStubMap<T, U> {
private final HashMap<U, CarResultStub<T>> mStubMap = new HashMap<>();
private final T mUnsupportedValue;
private final int mResultType;
private final CarHardwareHostDispatcher mHostDispatcher;
/**
* Creates an instance of the result stub map.
*
* @param resultType the result type to fetch
* @param unsupportedValue value to be returned if the host does not support the result type
* @param hostDispatcher dispatcher to be used for host calls
*
* @throws NullPointerException if {@code unsupportedValue} is {@code null} or if
* {@code hostDispatcher} is {@code null}
*/
public CarResultStubMap(int resultType, @NonNull T unsupportedValue,
@NonNull CarHardwareHostDispatcher hostDispatcher) {
mResultType = resultType;
mUnsupportedValue = requireNonNull(unsupportedValue);
mHostDispatcher = requireNonNull(hostDispatcher);
}
/**
* Adds a listener for the given result type and parameter.
*
* <p>This call also kicks off the initial call to the host if needed. If the
* {@code listener} was added previously then the executor is updated.
*
* @param params the requested listener params or {@code null}
* @param executor the executor which will be used for invoking the listener
* @param listener listener for the results
*
* @throws NullPointerException if {@code executor} is {@code null} or if {@code listener} is
* {@code null}
*/
public void addListener(@Nullable U params,
@NonNull Executor executor, @NonNull OnCarDataAvailableListener<T> listener) {
requireNonNull(executor);
requireNonNull(listener);
CarResultStub<T> stub = mStubMap.get(params);
if (stub != null) {
stub.addListener(executor, listener);
return;
}
try {
Bundleable bundle = params == null ? null : Bundleable.create(params);
stub = new CarResultStub<T>(mResultType,
bundle, false,
mUnsupportedValue,
mHostDispatcher);
stub.addListener(executor, listener);
mStubMap.put(params, stub);
} catch (BundlerException e) {
throw new IllegalArgumentException("Invalid params");
}
}
/**
* Removes a listener which was previously added from all params for which is it associated.
*
* @throws NullPointerException if {@code listener} is {@code null}
*/
public void removeListener(@NonNull OnCarDataAvailableListener<T> listener) {
requireNonNull(listener);
Iterator<Map.Entry<U, CarResultStub<T>>> iter = mStubMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<U, CarResultStub<T>> entry = iter.next();
if (entry.getValue().removeListener(listener)) {
iter.remove();
}
}
}
}