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

Commit a3ef50bc authored by Matt Pietal's avatar Matt Pietal Committed by Android (Google) Code Review
Browse files

Merge "Controls API - New method for suggested controls"

parents e8759cc7 587a5f7f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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>);
+51 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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);
@@ -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);
@@ -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:
@@ -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) {
@@ -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;
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -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);

+33 −0
Original line number Diff line number Diff line
@@ -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)
@@ -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>() {