Loading core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -38383,6 +38383,7 @@ package android.service.controls { method @NonNull public CharSequence getSubtitle(); method @NonNull public CharSequence getTitle(); method @Nullable public CharSequence getZone(); method public boolean isAuthRequired(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.controls.Control> CREATOR; field public static final int STATUS_DISABLED = 4; // 0x4 Loading @@ -38397,6 +38398,7 @@ package android.service.controls { ctor public Control.StatefulBuilder(@NonNull android.service.controls.Control); method @NonNull public android.service.controls.Control build(); method @NonNull public android.service.controls.Control.StatefulBuilder setAppIntent(@NonNull android.app.PendingIntent); method @NonNull public android.service.controls.Control.StatefulBuilder setAuthRequired(boolean); method @NonNull public android.service.controls.Control.StatefulBuilder setControlId(@NonNull String); method @NonNull public android.service.controls.Control.StatefulBuilder setControlTemplate(@NonNull android.service.controls.templates.ControlTemplate); method @NonNull public android.service.controls.Control.StatefulBuilder setCustomColor(@Nullable android.content.res.ColorStateList); core/java/android/service/controls/Control.java +34 −3 Original line number Diff line number Diff line Loading @@ -121,6 +121,7 @@ public final class Control implements Parcelable { private final @Status int mStatus; private final @NonNull ControlTemplate mControlTemplate; private final @NonNull CharSequence mStatusText; private final boolean mAuthRequired; /** * @param controlId the unique persistent identifier for this object. Loading @@ -137,6 +138,8 @@ public final class Control implements Parcelable { * @param status * @param controlTemplate * @param statusText * @param authRequired true if the control can not be interacted with until the device is * unlocked */ Control(@NonNull String controlId, @DeviceTypes.DeviceType int deviceType, Loading @@ -149,7 +152,8 @@ public final class Control implements Parcelable { @Nullable ColorStateList customColor, @Status int status, @NonNull ControlTemplate controlTemplate, @NonNull CharSequence statusText) { @NonNull CharSequence statusText, boolean authRequired) { Preconditions.checkNotNull(controlId); Preconditions.checkNotNull(title); Preconditions.checkNotNull(subtitle); Loading Loading @@ -180,6 +184,7 @@ public final class Control implements Parcelable { } mControlTemplate = controlTemplate; mStatusText = statusText; mAuthRequired = authRequired; } /** Loading Loading @@ -219,6 +224,7 @@ public final class Control implements Parcelable { ControlTemplateWrapper wrapper = ControlTemplateWrapper.CREATOR.createFromParcel(in); mControlTemplate = wrapper.getWrappedTemplate(); mStatusText = in.readCharSequence(); mAuthRequired = in.readBoolean(); } /** Loading Loading @@ -336,6 +342,13 @@ public final class Control implements Parcelable { return mStatusText; } /** * @return true if the control can not be interacted with until the device is unlocked */ public boolean isAuthRequired() { return mAuthRequired; } @Override public int describeContents() { return 0; Loading Loading @@ -376,6 +389,7 @@ public final class Control implements Parcelable { dest.writeInt(mStatus); new ControlTemplateWrapper(mControlTemplate).writeToParcel(dest, flags); dest.writeCharSequence(mStatusText); dest.writeBoolean(mAuthRequired); } public static final @NonNull Creator<Control> CREATOR = new Creator<Control>() { Loading Loading @@ -409,6 +423,7 @@ public final class Control implements Parcelable { * <li> Status: {@link Status#STATUS_UNKNOWN} * <li> Control template: {@link ControlTemplate#getNoTemplateObject} * <li> Status text: {@code ""} * <li> Auth Required: {@code true} * </ul> */ @SuppressLint("MutableBareField") Loading Loading @@ -585,7 +600,8 @@ public final class Control implements Parcelable { mCustomColor, STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE, ""); "", true /* authRequired */); } } Loading @@ -607,6 +623,7 @@ public final class Control implements Parcelable { * <li> Status: {@link Status#STATUS_UNKNOWN} * <li> Control template: {@link ControlTemplate#getNoTemplateObject} * <li> Status text: {@code ""} * <li> Auth Required: {@code true} * </ul> */ public static final class StatefulBuilder { Loading @@ -623,6 +640,7 @@ public final class Control implements Parcelable { private @Status int mStatus = STATUS_UNKNOWN; private @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE; private @NonNull CharSequence mStatusText = ""; private boolean mAuthRequired = true; /** * @param controlId the identifier for the {@link Control}. Loading Loading @@ -655,6 +673,7 @@ public final class Control implements Parcelable { mStatus = control.mStatus; mControlTemplate = control.mControlTemplate; mStatusText = control.mStatusText; mAuthRequired = control.mAuthRequired; } /** Loading Loading @@ -820,6 +839,17 @@ public final class Control implements Parcelable { return this; } /** * @param authRequired true if the control can not be interacted with until the device is * unlocked * @return {@code this} */ @NonNull public StatefulBuilder setAuthRequired(boolean authRequired) { mAuthRequired = authRequired; return this; } /** * @return a valid {@link Control} */ Loading @@ -836,7 +866,8 @@ public final class Control implements Parcelable { mCustomColor, mStatus, mControlTemplate, mStatusText); mStatusText, mAuthRequired); } } } core/java/android/service/controls/ControlsProviderService.java +6 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,9 @@ public abstract class ControlsProviderService extends Service { * Calls to {@link Subscriber#onComplete} will not be expected. Instead, wait for the call from * {@link Subscription#cancel} to indicate that updates are no longer required. It is expected * that controls provided by this publisher were created using {@link Control.StatefulBuilder}. * * By default, all controls require the device to be unlocked in order for the user to interact * with it. This can be modified per Control by {@link Control.StatefulBuilder#setAuthRequired}. */ @NonNull public abstract Publisher<Control> createPublisherFor(@NonNull List<String> controlIds); Loading @@ -127,6 +130,9 @@ public abstract class ControlsProviderService extends Service { * {@link ControlAction.ResponseResult}. The Integer should indicate whether the action * was received successfully, or if additional prompts should be presented to * the user. Any visual control updates should be sent via the Publisher. * By default, all invocations of this method will require the device be unlocked. This can * be modified per Control by {@link Control.StatefulBuilder#setAuthRequired}. */ public abstract void performControlAction(@NonNull String controlId, @NonNull ControlAction action, @NonNull Consumer<Integer> consumer); Loading core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -347,6 +347,7 @@ public class ControlProviderServiceTest { && Objects.equals(c1.getCustomColor(), c2.getCustomColor()) && c1.getStatus() == c2.getStatus() && Objects.equals(c1.getControlTemplate(), c2.getControlTemplate()) && Objects.equals(c1.isAuthRequired(), c2.isAuthRequired()) && Objects.equals(c1.getStatusText(), c2.getStatusText()); } Loading packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +53 −24 Original line number Diff line number Diff line Loading @@ -77,23 +77,37 @@ class ControlActionCoordinatorImpl @Inject constructor( override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) { controlsMetricsLogger.touch(cvh, isLocked) bouncerOrRun(createAction(cvh.cws.ci.controlId, { bouncerOrRun( createAction( cvh.cws.ci.controlId, { cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) cvh.action(BooleanAction(templateId, !isChecked)) }, true /* blockable */)) }, true /* blockable */ ), isAuthRequired(cvh) ) } override fun touch(cvh: ControlViewHolder, templateId: String, control: Control) { controlsMetricsLogger.touch(cvh, isLocked) val blockable = cvh.usePanel() bouncerOrRun(createAction(cvh.cws.ci.controlId, { bouncerOrRun( createAction( cvh.cws.ci.controlId, { cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) if (cvh.usePanel()) { showDetail(cvh, control.getAppIntent()) } else { cvh.action(CommandAction(templateId)) } }, blockable)) }, blockable ), isAuthRequired(cvh) ) } override fun drag(isEdge: Boolean) { Loading @@ -106,20 +120,33 @@ class ControlActionCoordinatorImpl @Inject constructor( override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) { controlsMetricsLogger.drag(cvh, isLocked) bouncerOrRun(createAction(cvh.cws.ci.controlId, { cvh.action(FloatAction(templateId, newValue)) }, false /* blockable */)) bouncerOrRun( createAction( cvh.cws.ci.controlId, { cvh.action(FloatAction(templateId, newValue)) }, false /* blockable */ ), isAuthRequired(cvh) ) } override fun longPress(cvh: ControlViewHolder) { controlsMetricsLogger.longPress(cvh, isLocked) bouncerOrRun(createAction(cvh.cws.ci.controlId, { // Long press snould only be called when there is valid control state, otherwise ignore bouncerOrRun( createAction( cvh.cws.ci.controlId, { // Long press snould only be called when there is valid control state, // otherwise ignore cvh.cws.control?.let { cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) showDetail(cvh, it.getAppIntent()) } }, false /* blockable */)) }, false /* blockable */ ), isAuthRequired(cvh) ) } override fun runPendingAction(controlId: String) { Loading @@ -135,6 +162,8 @@ class ControlActionCoordinatorImpl @Inject constructor( actionsInProgress.remove(controlId) } private fun isAuthRequired(cvh: ControlViewHolder) = cvh.cws.control?.isAuthRequired() ?: true private fun shouldRunAction(controlId: String) = if (actionsInProgress.add(controlId)) { uiExecutor.executeDelayed({ Loading @@ -146,8 +175,8 @@ class ControlActionCoordinatorImpl @Inject constructor( } @VisibleForTesting fun bouncerOrRun(action: Action) { if (keyguardStateController.isShowing()) { fun bouncerOrRun(action: Action, authRequired: Boolean) { if (keyguardStateController.isShowing() && authRequired) { if (isLocked) { context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) Loading Loading
core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -38383,6 +38383,7 @@ package android.service.controls { method @NonNull public CharSequence getSubtitle(); method @NonNull public CharSequence getTitle(); method @Nullable public CharSequence getZone(); method public boolean isAuthRequired(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.controls.Control> CREATOR; field public static final int STATUS_DISABLED = 4; // 0x4 Loading @@ -38397,6 +38398,7 @@ package android.service.controls { ctor public Control.StatefulBuilder(@NonNull android.service.controls.Control); method @NonNull public android.service.controls.Control build(); method @NonNull public android.service.controls.Control.StatefulBuilder setAppIntent(@NonNull android.app.PendingIntent); method @NonNull public android.service.controls.Control.StatefulBuilder setAuthRequired(boolean); method @NonNull public android.service.controls.Control.StatefulBuilder setControlId(@NonNull String); method @NonNull public android.service.controls.Control.StatefulBuilder setControlTemplate(@NonNull android.service.controls.templates.ControlTemplate); method @NonNull public android.service.controls.Control.StatefulBuilder setCustomColor(@Nullable android.content.res.ColorStateList);
core/java/android/service/controls/Control.java +34 −3 Original line number Diff line number Diff line Loading @@ -121,6 +121,7 @@ public final class Control implements Parcelable { private final @Status int mStatus; private final @NonNull ControlTemplate mControlTemplate; private final @NonNull CharSequence mStatusText; private final boolean mAuthRequired; /** * @param controlId the unique persistent identifier for this object. Loading @@ -137,6 +138,8 @@ public final class Control implements Parcelable { * @param status * @param controlTemplate * @param statusText * @param authRequired true if the control can not be interacted with until the device is * unlocked */ Control(@NonNull String controlId, @DeviceTypes.DeviceType int deviceType, Loading @@ -149,7 +152,8 @@ public final class Control implements Parcelable { @Nullable ColorStateList customColor, @Status int status, @NonNull ControlTemplate controlTemplate, @NonNull CharSequence statusText) { @NonNull CharSequence statusText, boolean authRequired) { Preconditions.checkNotNull(controlId); Preconditions.checkNotNull(title); Preconditions.checkNotNull(subtitle); Loading Loading @@ -180,6 +184,7 @@ public final class Control implements Parcelable { } mControlTemplate = controlTemplate; mStatusText = statusText; mAuthRequired = authRequired; } /** Loading Loading @@ -219,6 +224,7 @@ public final class Control implements Parcelable { ControlTemplateWrapper wrapper = ControlTemplateWrapper.CREATOR.createFromParcel(in); mControlTemplate = wrapper.getWrappedTemplate(); mStatusText = in.readCharSequence(); mAuthRequired = in.readBoolean(); } /** Loading Loading @@ -336,6 +342,13 @@ public final class Control implements Parcelable { return mStatusText; } /** * @return true if the control can not be interacted with until the device is unlocked */ public boolean isAuthRequired() { return mAuthRequired; } @Override public int describeContents() { return 0; Loading Loading @@ -376,6 +389,7 @@ public final class Control implements Parcelable { dest.writeInt(mStatus); new ControlTemplateWrapper(mControlTemplate).writeToParcel(dest, flags); dest.writeCharSequence(mStatusText); dest.writeBoolean(mAuthRequired); } public static final @NonNull Creator<Control> CREATOR = new Creator<Control>() { Loading Loading @@ -409,6 +423,7 @@ public final class Control implements Parcelable { * <li> Status: {@link Status#STATUS_UNKNOWN} * <li> Control template: {@link ControlTemplate#getNoTemplateObject} * <li> Status text: {@code ""} * <li> Auth Required: {@code true} * </ul> */ @SuppressLint("MutableBareField") Loading Loading @@ -585,7 +600,8 @@ public final class Control implements Parcelable { mCustomColor, STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE, ""); "", true /* authRequired */); } } Loading @@ -607,6 +623,7 @@ public final class Control implements Parcelable { * <li> Status: {@link Status#STATUS_UNKNOWN} * <li> Control template: {@link ControlTemplate#getNoTemplateObject} * <li> Status text: {@code ""} * <li> Auth Required: {@code true} * </ul> */ public static final class StatefulBuilder { Loading @@ -623,6 +640,7 @@ public final class Control implements Parcelable { private @Status int mStatus = STATUS_UNKNOWN; private @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE; private @NonNull CharSequence mStatusText = ""; private boolean mAuthRequired = true; /** * @param controlId the identifier for the {@link Control}. Loading Loading @@ -655,6 +673,7 @@ public final class Control implements Parcelable { mStatus = control.mStatus; mControlTemplate = control.mControlTemplate; mStatusText = control.mStatusText; mAuthRequired = control.mAuthRequired; } /** Loading Loading @@ -820,6 +839,17 @@ public final class Control implements Parcelable { return this; } /** * @param authRequired true if the control can not be interacted with until the device is * unlocked * @return {@code this} */ @NonNull public StatefulBuilder setAuthRequired(boolean authRequired) { mAuthRequired = authRequired; return this; } /** * @return a valid {@link Control} */ Loading @@ -836,7 +866,8 @@ public final class Control implements Parcelable { mCustomColor, mStatus, mControlTemplate, mStatusText); mStatusText, mAuthRequired); } } }
core/java/android/service/controls/ControlsProviderService.java +6 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,9 @@ public abstract class ControlsProviderService extends Service { * Calls to {@link Subscriber#onComplete} will not be expected. Instead, wait for the call from * {@link Subscription#cancel} to indicate that updates are no longer required. It is expected * that controls provided by this publisher were created using {@link Control.StatefulBuilder}. * * By default, all controls require the device to be unlocked in order for the user to interact * with it. This can be modified per Control by {@link Control.StatefulBuilder#setAuthRequired}. */ @NonNull public abstract Publisher<Control> createPublisherFor(@NonNull List<String> controlIds); Loading @@ -127,6 +130,9 @@ public abstract class ControlsProviderService extends Service { * {@link ControlAction.ResponseResult}. The Integer should indicate whether the action * was received successfully, or if additional prompts should be presented to * the user. Any visual control updates should be sent via the Publisher. * By default, all invocations of this method will require the device be unlocked. This can * be modified per Control by {@link Control.StatefulBuilder#setAuthRequired}. */ public abstract void performControlAction(@NonNull String controlId, @NonNull ControlAction action, @NonNull Consumer<Integer> consumer); Loading
core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -347,6 +347,7 @@ public class ControlProviderServiceTest { && Objects.equals(c1.getCustomColor(), c2.getCustomColor()) && c1.getStatus() == c2.getStatus() && Objects.equals(c1.getControlTemplate(), c2.getControlTemplate()) && Objects.equals(c1.isAuthRequired(), c2.isAuthRequired()) && Objects.equals(c1.getStatusText(), c2.getStatusText()); } Loading
packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +53 −24 Original line number Diff line number Diff line Loading @@ -77,23 +77,37 @@ class ControlActionCoordinatorImpl @Inject constructor( override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) { controlsMetricsLogger.touch(cvh, isLocked) bouncerOrRun(createAction(cvh.cws.ci.controlId, { bouncerOrRun( createAction( cvh.cws.ci.controlId, { cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) cvh.action(BooleanAction(templateId, !isChecked)) }, true /* blockable */)) }, true /* blockable */ ), isAuthRequired(cvh) ) } override fun touch(cvh: ControlViewHolder, templateId: String, control: Control) { controlsMetricsLogger.touch(cvh, isLocked) val blockable = cvh.usePanel() bouncerOrRun(createAction(cvh.cws.ci.controlId, { bouncerOrRun( createAction( cvh.cws.ci.controlId, { cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) if (cvh.usePanel()) { showDetail(cvh, control.getAppIntent()) } else { cvh.action(CommandAction(templateId)) } }, blockable)) }, blockable ), isAuthRequired(cvh) ) } override fun drag(isEdge: Boolean) { Loading @@ -106,20 +120,33 @@ class ControlActionCoordinatorImpl @Inject constructor( override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) { controlsMetricsLogger.drag(cvh, isLocked) bouncerOrRun(createAction(cvh.cws.ci.controlId, { cvh.action(FloatAction(templateId, newValue)) }, false /* blockable */)) bouncerOrRun( createAction( cvh.cws.ci.controlId, { cvh.action(FloatAction(templateId, newValue)) }, false /* blockable */ ), isAuthRequired(cvh) ) } override fun longPress(cvh: ControlViewHolder) { controlsMetricsLogger.longPress(cvh, isLocked) bouncerOrRun(createAction(cvh.cws.ci.controlId, { // Long press snould only be called when there is valid control state, otherwise ignore bouncerOrRun( createAction( cvh.cws.ci.controlId, { // Long press snould only be called when there is valid control state, // otherwise ignore cvh.cws.control?.let { cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) showDetail(cvh, it.getAppIntent()) } }, false /* blockable */)) }, false /* blockable */ ), isAuthRequired(cvh) ) } override fun runPendingAction(controlId: String) { Loading @@ -135,6 +162,8 @@ class ControlActionCoordinatorImpl @Inject constructor( actionsInProgress.remove(controlId) } private fun isAuthRequired(cvh: ControlViewHolder) = cvh.cws.control?.isAuthRequired() ?: true private fun shouldRunAction(controlId: String) = if (actionsInProgress.add(controlId)) { uiExecutor.executeDelayed({ Loading @@ -146,8 +175,8 @@ class ControlActionCoordinatorImpl @Inject constructor( } @VisibleForTesting fun bouncerOrRun(action: Action) { if (keyguardStateController.isShowing()) { fun bouncerOrRun(action: Action, authRequired: Boolean) { if (keyguardStateController.isShowing() && authRequired) { if (isLocked) { context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) Loading