Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -43305,6 +43305,7 @@ package android.service.controls { public abstract class ControlsProviderService extends android.app.Service { ctor public ControlsProviderService(); method public abstract void loadAvailableControls(@NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>); method public void loadSuggestedControls(int, @NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>); method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void performControlAction(@NonNull String, @NonNull android.service.controls.actions.ControlAction, @NonNull java.util.function.Consumer<java.lang.Integer>); method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>); core/java/android/service/controls/ControlsProviderService.java +51 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.util.Log; import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Flow.Publisher; import java.util.concurrent.Flow.Subscriber; Loading Loading @@ -72,6 +73,18 @@ public abstract class ControlsProviderService extends Service { */ public abstract void loadAvailableControls(@NonNull Consumer<List<Control>> consumer); /** * (Optional) The service may be asked to provide a small number of recommended controls, in * order to suggest some controls to the user for favoriting. The controls shall be built using * the stateless builder {@link Control.StatelessBuilder}, followed by an invocation to the * provided consumer to callback to the call originator. If the number of controls * is greater than maxNumber, the list will be truncated. */ public void loadSuggestedControls(int maxNumber, @NonNull Consumer<List<Control>> consumer) { // Override to change the default behavior consumer.accept(Collections.emptyList()); } /** * Return a valid Publisher for the given controlIds. This publisher will be asked * to provide updates for the given list of controlIds as long as the Subscription Loading Loading @@ -104,6 +117,11 @@ public abstract class ControlsProviderService extends Service { mHandler.obtainMessage(RequestHandler.MSG_LOAD, cb).sendToTarget(); } public void loadSuggested(int maxNumber, IControlsLoadCallback cb) { LoadMessage msg = new LoadMessage(maxNumber, cb); mHandler.obtainMessage(RequestHandler.MSG_LOAD_SUGGESTED, msg).sendToTarget(); } public void subscribe(List<String> controlIds, IControlsSubscriber subscriber) { SubscribeMessage msg = new SubscribeMessage(controlIds, subscriber); Loading @@ -128,6 +146,14 @@ public abstract class ControlsProviderService extends Service { private static final int MSG_LOAD = 1; private static final int MSG_SUBSCRIBE = 2; private static final int MSG_ACTION = 3; private static final int MSG_LOAD_SUGGESTED = 4; /** * This the maximum number of controls that can be loaded via * {@link ControlsProviderService#loadAvailablecontrols}. Anything over this number * will be truncated. */ private static final int MAX_NUMBER_OF_CONTROLS_ALLOWED = 1000; RequestHandler(Looper looper) { super(looper); Loading @@ -137,7 +163,14 @@ public abstract class ControlsProviderService extends Service { switch(msg.what) { case MSG_LOAD: final IControlsLoadCallback cb = (IControlsLoadCallback) msg.obj; ControlsProviderService.this.loadAvailableControls(consumerFor(cb)); ControlsProviderService.this.loadAvailableControls(consumerFor( MAX_NUMBER_OF_CONTROLS_ALLOWED, cb)); break; case MSG_LOAD_SUGGESTED: final LoadMessage lMsg = (LoadMessage) msg.obj; ControlsProviderService.this.loadSuggestedControls(lMsg.mMaxNumber, consumerFor(lMsg.mMaxNumber, lMsg.mCb)); break; case MSG_SUBSCRIBE: Loading Loading @@ -201,9 +234,15 @@ public abstract class ControlsProviderService extends Service { }; } private Consumer<List<Control>> consumerFor(IControlsLoadCallback cb) { private Consumer<List<Control>> consumerFor(int maxNumber, IControlsLoadCallback cb) { return (@NonNull List<Control> controls) -> { Preconditions.checkNotNull(controls); if (controls.size() > maxNumber) { Log.w(TAG, "Too many controls. Provided: " + controls.size() + ", Max allowed: " + maxNumber + ". Truncating the list."); controls = controls.subList(0, maxNumber); } List<Control> list = new ArrayList<>(); for (Control control: controls) { if (control == null) { Loading Loading @@ -268,4 +307,14 @@ public abstract class ControlsProviderService extends Service { this.mSubscriber = subscriber; } } private static class LoadMessage { final int mMaxNumber; final IControlsLoadCallback mCb; LoadMessage(int maxNumber, IControlsLoadCallback cb) { this.mMaxNumber = maxNumber; this.mCb = cb; } } } core/java/android/service/controls/IControlsProvider.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.service.controls.actions.ControlActionWrapper; oneway interface IControlsProvider { void load(IControlsLoadCallback cb); void loadSuggested(int maxNumber, IControlsLoadCallback cb); void subscribe(in List<String> controlIds, IControlsSubscriber subscriber); Loading core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +33 −0 Original line number Diff line number Diff line Loading @@ -146,6 +146,34 @@ public class ControlProviderServiceTest { assertEquals(Control.STATUS_UNKNOWN, l.get(0).getStatus()); } @Test public void testLoadSuggested_withMaxNumber() throws RemoteException { Control control1 = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build(); Control control2 = new Control.StatelessBuilder("TEST_ID_2", mPendingIntent) .setDeviceType(DeviceTypes.TYPE_AIR_FRESHENER).build(); @SuppressWarnings("unchecked") ArgumentCaptor<List<Control>> captor = ArgumentCaptor.forClass(List.class); ArrayList<Control> list = new ArrayList<>(); list.add(control1); list.add(control2); final int maxSuggested = 1; mControlsProviderService.setControls(list); mControlsProvider.loadSuggested(maxSuggested, mLoadCallback); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); verify(mLoadCallback).accept(eq(mToken), captor.capture()); List<Control> l = captor.getValue(); assertEquals(maxSuggested, l.size()); for (int i = 0; i < maxSuggested; ++i) { assertTrue(equals(list.get(i), l.get(i))); } } @Test public void testSubscribe() throws RemoteException { Control control = new Control.StatefulBuilder("TEST_ID", mPendingIntent) Loading Loading @@ -215,6 +243,11 @@ public class ControlProviderServiceTest { cb.accept(mControls); } @Override public void loadSuggestedControls(int maxNumber, Consumer<List<Control>> cb) { cb.accept(mControls); } @Override public Publisher<Control> publisherFor(List<String> ids) { return new Publisher<Control>() { Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -43305,6 +43305,7 @@ package android.service.controls { public abstract class ControlsProviderService extends android.app.Service { ctor public ControlsProviderService(); method public abstract void loadAvailableControls(@NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>); method public void loadSuggestedControls(int, @NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>); method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void performControlAction(@NonNull String, @NonNull android.service.controls.actions.ControlAction, @NonNull java.util.function.Consumer<java.lang.Integer>); method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>);
core/java/android/service/controls/ControlsProviderService.java +51 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.util.Log; import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Flow.Publisher; import java.util.concurrent.Flow.Subscriber; Loading Loading @@ -72,6 +73,18 @@ public abstract class ControlsProviderService extends Service { */ public abstract void loadAvailableControls(@NonNull Consumer<List<Control>> consumer); /** * (Optional) The service may be asked to provide a small number of recommended controls, in * order to suggest some controls to the user for favoriting. The controls shall be built using * the stateless builder {@link Control.StatelessBuilder}, followed by an invocation to the * provided consumer to callback to the call originator. If the number of controls * is greater than maxNumber, the list will be truncated. */ public void loadSuggestedControls(int maxNumber, @NonNull Consumer<List<Control>> consumer) { // Override to change the default behavior consumer.accept(Collections.emptyList()); } /** * Return a valid Publisher for the given controlIds. This publisher will be asked * to provide updates for the given list of controlIds as long as the Subscription Loading Loading @@ -104,6 +117,11 @@ public abstract class ControlsProviderService extends Service { mHandler.obtainMessage(RequestHandler.MSG_LOAD, cb).sendToTarget(); } public void loadSuggested(int maxNumber, IControlsLoadCallback cb) { LoadMessage msg = new LoadMessage(maxNumber, cb); mHandler.obtainMessage(RequestHandler.MSG_LOAD_SUGGESTED, msg).sendToTarget(); } public void subscribe(List<String> controlIds, IControlsSubscriber subscriber) { SubscribeMessage msg = new SubscribeMessage(controlIds, subscriber); Loading @@ -128,6 +146,14 @@ public abstract class ControlsProviderService extends Service { private static final int MSG_LOAD = 1; private static final int MSG_SUBSCRIBE = 2; private static final int MSG_ACTION = 3; private static final int MSG_LOAD_SUGGESTED = 4; /** * This the maximum number of controls that can be loaded via * {@link ControlsProviderService#loadAvailablecontrols}. Anything over this number * will be truncated. */ private static final int MAX_NUMBER_OF_CONTROLS_ALLOWED = 1000; RequestHandler(Looper looper) { super(looper); Loading @@ -137,7 +163,14 @@ public abstract class ControlsProviderService extends Service { switch(msg.what) { case MSG_LOAD: final IControlsLoadCallback cb = (IControlsLoadCallback) msg.obj; ControlsProviderService.this.loadAvailableControls(consumerFor(cb)); ControlsProviderService.this.loadAvailableControls(consumerFor( MAX_NUMBER_OF_CONTROLS_ALLOWED, cb)); break; case MSG_LOAD_SUGGESTED: final LoadMessage lMsg = (LoadMessage) msg.obj; ControlsProviderService.this.loadSuggestedControls(lMsg.mMaxNumber, consumerFor(lMsg.mMaxNumber, lMsg.mCb)); break; case MSG_SUBSCRIBE: Loading Loading @@ -201,9 +234,15 @@ public abstract class ControlsProviderService extends Service { }; } private Consumer<List<Control>> consumerFor(IControlsLoadCallback cb) { private Consumer<List<Control>> consumerFor(int maxNumber, IControlsLoadCallback cb) { return (@NonNull List<Control> controls) -> { Preconditions.checkNotNull(controls); if (controls.size() > maxNumber) { Log.w(TAG, "Too many controls. Provided: " + controls.size() + ", Max allowed: " + maxNumber + ". Truncating the list."); controls = controls.subList(0, maxNumber); } List<Control> list = new ArrayList<>(); for (Control control: controls) { if (control == null) { Loading Loading @@ -268,4 +307,14 @@ public abstract class ControlsProviderService extends Service { this.mSubscriber = subscriber; } } private static class LoadMessage { final int mMaxNumber; final IControlsLoadCallback mCb; LoadMessage(int maxNumber, IControlsLoadCallback cb) { this.mMaxNumber = maxNumber; this.mCb = cb; } } }
core/java/android/service/controls/IControlsProvider.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import android.service.controls.actions.ControlActionWrapper; oneway interface IControlsProvider { void load(IControlsLoadCallback cb); void loadSuggested(int maxNumber, IControlsLoadCallback cb); void subscribe(in List<String> controlIds, IControlsSubscriber subscriber); Loading
core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +33 −0 Original line number Diff line number Diff line Loading @@ -146,6 +146,34 @@ public class ControlProviderServiceTest { assertEquals(Control.STATUS_UNKNOWN, l.get(0).getStatus()); } @Test public void testLoadSuggested_withMaxNumber() throws RemoteException { Control control1 = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build(); Control control2 = new Control.StatelessBuilder("TEST_ID_2", mPendingIntent) .setDeviceType(DeviceTypes.TYPE_AIR_FRESHENER).build(); @SuppressWarnings("unchecked") ArgumentCaptor<List<Control>> captor = ArgumentCaptor.forClass(List.class); ArrayList<Control> list = new ArrayList<>(); list.add(control1); list.add(control2); final int maxSuggested = 1; mControlsProviderService.setControls(list); mControlsProvider.loadSuggested(maxSuggested, mLoadCallback); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); verify(mLoadCallback).accept(eq(mToken), captor.capture()); List<Control> l = captor.getValue(); assertEquals(maxSuggested, l.size()); for (int i = 0; i < maxSuggested; ++i) { assertTrue(equals(list.get(i), l.get(i))); } } @Test public void testSubscribe() throws RemoteException { Control control = new Control.StatefulBuilder("TEST_ID", mPendingIntent) Loading Loading @@ -215,6 +243,11 @@ public class ControlProviderServiceTest { cb.accept(mControls); } @Override public void loadSuggestedControls(int maxNumber, Consumer<List<Control>> cb) { cb.accept(mControls); } @Override public Publisher<Control> publisherFor(List<String> ids) { return new Publisher<Control>() { Loading