Loading api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ package android { field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES"; field @Deprecated public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE"; field public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE"; field public static final String BIND_CONTROLS = "android.permission.BIND_CONTROLS"; field public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN"; field public static final String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE"; field public static final String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE"; Loading Loading @@ -43401,6 +43402,7 @@ package android.service.controls { method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>); method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForAllAvailable(); method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForSuggested(); method public static void requestAddControl(@NonNull android.content.Context, @NonNull android.content.ComponentName, @NonNull android.service.controls.Control); field public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService"; field @NonNull public static final String TAG = "ControlsProviderService"; } core/java/android/service/controls/ControlsProviderService.java +44 −0 Original line number Diff line number Diff line Loading @@ -15,11 +15,14 @@ */ package android.service.controls; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; Loading Loading @@ -51,6 +54,20 @@ public abstract class ControlsProviderService extends Service { @SdkConstant(SdkConstantType.SERVICE_ACTION) public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService"; /** * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_ADD_CONTROL = "android.service.controls.action.ADD_CONTROL"; /** * @hide */ public static final String EXTRA_CONTROL = "android.service.controls.extra.CONTROL"; /** * @hide */ Loading Loading @@ -325,6 +342,33 @@ public abstract class ControlsProviderService extends Service { } } /** * Request SystemUI to prompt the user to add a control to favorites. * * @param context A context * @param componentName Component name of the {@link ControlsProviderService} * @param control A stateless control to show to the user */ public static void requestAddControl(@NonNull Context context, @NonNull ComponentName componentName, @NonNull Control control) { Preconditions.checkNotNull(context); Preconditions.checkNotNull(componentName); Preconditions.checkNotNull(control); final ComponentName sysuiComponent = ComponentName.unflattenFromString( context.getResources().getString( com.android.internal.R.string.config_systemUIServiceComponent)); Intent intent = new Intent(ACTION_ADD_CONTROL); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, componentName); intent.setPackage(sysuiComponent.getPackageName()); if (isStatelessControl(control)) { intent.putExtra(EXTRA_CONTROL, control); } else { intent.putExtra(EXTRA_CONTROL, new Control.StatelessBuilder(control).build()); } context.sendBroadcast(intent, Manifest.permission.BIND_CONTROLS); } private static class SubscriptionAdapter extends IControlsSubscription.Stub { final Subscription mSubscription; Loading core/res/AndroidManifest.xml +1 −2 Original line number Diff line number Diff line Loading @@ -3084,8 +3084,7 @@ <!-- Allows SystemUI to request third party controls. <p>Should only be requested by the System and required by ControlsService declarations. @hide {@link android.service.controls.ControlsProviderService} declarations. --> <permission android:name="android.permission.BIND_CONTROLS" android:protectionLevel="signature" /> Loading core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +35 −0 Original line number Diff line number Diff line Loading @@ -25,9 +25,13 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.Manifest; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IIntentSender; import android.content.Intent; import android.content.res.Resources; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; Loading @@ -44,6 +48,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; Loading @@ -59,6 +64,11 @@ import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) public class ControlProviderServiceTest { private static final ComponentName TEST_SYSUI_COMPONENT = ComponentName.unflattenFromString("sysui/.test.cls"); private static final ComponentName TEST_COMPONENT = ComponentName.unflattenFromString("test.pkg/.test.cls"); private IBinder mToken = new Binder(); @Mock private IControlsActionCallback.Stub mActionCallback; Loading @@ -66,6 +76,12 @@ public class ControlProviderServiceTest { private IControlsSubscriber.Stub mSubscriber; @Mock private IIntentSender mIIntentSender; @Mock private Resources mResources; @Mock private Context mContext; @Captor private ArgumentCaptor<Intent> mIntentArgumentCaptor; private PendingIntent mPendingIntent; private FakeControlsProviderService mControlsProviderService; Loading @@ -81,6 +97,10 @@ public class ControlProviderServiceTest { when(mSubscriber.asBinder()).thenCallRealMethod(); when(mSubscriber.queryLocalInterface(any())).thenReturn(mSubscriber); when(mResources.getString(com.android.internal.R.string.config_systemUIServiceComponent)) .thenReturn(TEST_SYSUI_COMPONENT.flattenToString()); when(mContext.getResources()).thenReturn(mResources); Bundle b = new Bundle(); b.putBinder(ControlsProviderService.CALLBACK_TOKEN, mToken); Intent intent = new Intent(); Loading Loading @@ -223,6 +243,21 @@ public class ControlProviderServiceTest { ControlAction.RESPONSE_OK); } @Test public void testRequestAdd() { Control control = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build(); ControlsProviderService.requestAddControl(mContext, TEST_COMPONENT, control); verify(mContext).sendBroadcast(mIntentArgumentCaptor.capture(), eq(Manifest.permission.BIND_CONTROLS)); Intent intent = mIntentArgumentCaptor.getValue(); assertEquals(ControlsProviderService.ACTION_ADD_CONTROL, intent.getAction()); assertEquals(TEST_SYSUI_COMPONENT.getPackageName(), intent.getPackage()); assertEquals(TEST_COMPONENT, intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME)); assertTrue(equals(control, intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL))); } private static boolean equals(Control c1, Control c2) { if (c1 == c2) return true; if (c1 == null || c2 == null) return false; Loading Loading
api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ package android { field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES"; field @Deprecated public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE"; field public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE"; field public static final String BIND_CONTROLS = "android.permission.BIND_CONTROLS"; field public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN"; field public static final String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE"; field public static final String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE"; Loading Loading @@ -43401,6 +43402,7 @@ package android.service.controls { method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>); method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForAllAvailable(); method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForSuggested(); method public static void requestAddControl(@NonNull android.content.Context, @NonNull android.content.ComponentName, @NonNull android.service.controls.Control); field public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService"; field @NonNull public static final String TAG = "ControlsProviderService"; }
core/java/android/service/controls/ControlsProviderService.java +44 −0 Original line number Diff line number Diff line Loading @@ -15,11 +15,14 @@ */ package android.service.controls; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; Loading Loading @@ -51,6 +54,20 @@ public abstract class ControlsProviderService extends Service { @SdkConstant(SdkConstantType.SERVICE_ACTION) public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService"; /** * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_ADD_CONTROL = "android.service.controls.action.ADD_CONTROL"; /** * @hide */ public static final String EXTRA_CONTROL = "android.service.controls.extra.CONTROL"; /** * @hide */ Loading Loading @@ -325,6 +342,33 @@ public abstract class ControlsProviderService extends Service { } } /** * Request SystemUI to prompt the user to add a control to favorites. * * @param context A context * @param componentName Component name of the {@link ControlsProviderService} * @param control A stateless control to show to the user */ public static void requestAddControl(@NonNull Context context, @NonNull ComponentName componentName, @NonNull Control control) { Preconditions.checkNotNull(context); Preconditions.checkNotNull(componentName); Preconditions.checkNotNull(control); final ComponentName sysuiComponent = ComponentName.unflattenFromString( context.getResources().getString( com.android.internal.R.string.config_systemUIServiceComponent)); Intent intent = new Intent(ACTION_ADD_CONTROL); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, componentName); intent.setPackage(sysuiComponent.getPackageName()); if (isStatelessControl(control)) { intent.putExtra(EXTRA_CONTROL, control); } else { intent.putExtra(EXTRA_CONTROL, new Control.StatelessBuilder(control).build()); } context.sendBroadcast(intent, Manifest.permission.BIND_CONTROLS); } private static class SubscriptionAdapter extends IControlsSubscription.Stub { final Subscription mSubscription; Loading
core/res/AndroidManifest.xml +1 −2 Original line number Diff line number Diff line Loading @@ -3084,8 +3084,7 @@ <!-- Allows SystemUI to request third party controls. <p>Should only be requested by the System and required by ControlsService declarations. @hide {@link android.service.controls.ControlsProviderService} declarations. --> <permission android:name="android.permission.BIND_CONTROLS" android:protectionLevel="signature" /> Loading
core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +35 −0 Original line number Diff line number Diff line Loading @@ -25,9 +25,13 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.Manifest; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IIntentSender; import android.content.Intent; import android.content.res.Resources; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; Loading @@ -44,6 +48,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; Loading @@ -59,6 +64,11 @@ import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) public class ControlProviderServiceTest { private static final ComponentName TEST_SYSUI_COMPONENT = ComponentName.unflattenFromString("sysui/.test.cls"); private static final ComponentName TEST_COMPONENT = ComponentName.unflattenFromString("test.pkg/.test.cls"); private IBinder mToken = new Binder(); @Mock private IControlsActionCallback.Stub mActionCallback; Loading @@ -66,6 +76,12 @@ public class ControlProviderServiceTest { private IControlsSubscriber.Stub mSubscriber; @Mock private IIntentSender mIIntentSender; @Mock private Resources mResources; @Mock private Context mContext; @Captor private ArgumentCaptor<Intent> mIntentArgumentCaptor; private PendingIntent mPendingIntent; private FakeControlsProviderService mControlsProviderService; Loading @@ -81,6 +97,10 @@ public class ControlProviderServiceTest { when(mSubscriber.asBinder()).thenCallRealMethod(); when(mSubscriber.queryLocalInterface(any())).thenReturn(mSubscriber); when(mResources.getString(com.android.internal.R.string.config_systemUIServiceComponent)) .thenReturn(TEST_SYSUI_COMPONENT.flattenToString()); when(mContext.getResources()).thenReturn(mResources); Bundle b = new Bundle(); b.putBinder(ControlsProviderService.CALLBACK_TOKEN, mToken); Intent intent = new Intent(); Loading Loading @@ -223,6 +243,21 @@ public class ControlProviderServiceTest { ControlAction.RESPONSE_OK); } @Test public void testRequestAdd() { Control control = new Control.StatelessBuilder("TEST_ID", mPendingIntent).build(); ControlsProviderService.requestAddControl(mContext, TEST_COMPONENT, control); verify(mContext).sendBroadcast(mIntentArgumentCaptor.capture(), eq(Manifest.permission.BIND_CONTROLS)); Intent intent = mIntentArgumentCaptor.getValue(); assertEquals(ControlsProviderService.ACTION_ADD_CONTROL, intent.getAction()); assertEquals(TEST_SYSUI_COMPONENT.getPackageName(), intent.getPackage()); assertEquals(TEST_COMPONENT, intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME)); assertTrue(equals(control, intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL))); } private static boolean equals(Control c1, Control c2) { if (c1 == c2) return true; if (c1 == null || c2 == null) return false; Loading