diff options
| author | 2019-12-30 12:30:24 -0500 | |
|---|---|---|
| committer | 2019-12-30 13:24:28 -0500 | |
| commit | ee57f49c7d8ab4d6c22608ae8de224b356f5b94e (patch) | |
| tree | 80b17675e5b71fd61272246fa2e8090639fe3995 | |
| parent | 6b7926d1fccd554da360b9c42d7d820c0c7f4a5e (diff) | |
Merge ControlState into Control
All the information that was sent with a ControlState is now sent with a
new updated Control object. That way, overriding Type and changes to
name can be done inside subscribe.
Modified ControlsProviderService to encapsulate the callback service and
provide public methods to send information to SystemUI. In particular,
onLoad verifies that all Control passed do not have status information
and erases that information if it has any.
Add token for reusing the same Callback binder.
Test: build
Change-Id: I6ce5e9ad53899ea588b23e0f067b5d1f86a0bb18
8 files changed, 313 insertions, 430 deletions
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java index df18eb626c5e..43a308cf82cb 100644 --- a/core/java/android/service/controls/Control.java +++ b/core/java/android/service/controls/Control.java @@ -16,6 +16,7 @@ package android.service.controls; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; @@ -28,28 +29,26 @@ import android.util.Log; import com.android.internal.util.Preconditions; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Represents a physical object that can be represented by a {@link ControlTemplate} and whose * properties may be modified through a {@link ControlAction}. * - * The information is provided by a {@link ControlProviderService} and represents static + * The information is provided by a {@link ControlsProviderService} and represents static * information (not current status) about the device. * <p> * Each control needs a unique (per provider) identifier that is persistent across reboots of the * system. * <p> * Each {@link Control} will have a name, a subtitle and will optionally belong to a structure - * and zone. Some of these values are defined by the user and/or the {@link ControlProviderService} + * and zone. Some of these values are defined by the user and/or the {@link ControlsProviderService} * and will be used to display the control as well as group them for management. * <p> * Each object will have an associated {@link DeviceTypes.DeviceType}. This will determine the icons and colors * used to display it. * <p> - * The {@link ControlTemplate.TemplateType} provided will be used as a hint when displaying this in - * non-interactive situations (for example when there's no state to display). This template is not - * the one that will be shown with the current state and provide interactions. That template is set - * using {@link ControlState}. - * <p> * An {@link Intent} linking to the provider Activity that expands on this {@link Control} and * allows for further actions should be provided. * @hide @@ -57,17 +56,52 @@ import com.android.internal.util.Preconditions; public class Control implements Parcelable { private static final String TAG = "Control"; - ; + private static final int NUM_STATUS = 5; + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + STATUS_UNKNOWN, + STATUS_OK, + STATUS_NOT_FOUND, + STATUS_ERROR, + STATUS_DISABLED, + }) + public @interface Status {}; + + public static final int STATUS_UNKNOWN = 0; + + /** + * The device corresponding to the {@link Control} is responding correctly. + */ + public static final int STATUS_OK = 1; + + /** + * The device corresponding to the {@link Control} cannot be found or was removed. + */ + public static final int STATUS_NOT_FOUND = 2; + + /** + * The device corresponding to the {@link Control} is in an error state. + */ + public static final int STATUS_ERROR = 3; + + /** + * The {@link Control} is currently disabled. + */ + public static final int STATUS_DISABLED = 4; private final @NonNull String mControlId; - private final @DeviceTypes.DeviceType - int mDeviceType; + private final @DeviceTypes.DeviceType int mDeviceType; private final @NonNull CharSequence mTitle; private final @NonNull CharSequence mSubtitle; private final @Nullable CharSequence mStructure; private final @Nullable CharSequence mZone; private final @NonNull PendingIntent mAppIntent; - private final @ControlTemplate.TemplateType int mPrimaryType; + private final @Status int mStatus; + private final @NonNull ControlTemplate mControlTemplate; + private final @NonNull CharSequence mStatusText; /** * @param controlId the unique persistent identifier for this object. @@ -79,7 +113,6 @@ public class Control implements Parcelable { * @param zone * @param appIntent a {@link PendingIntent} linking to a page to interact with the * corresponding device. - * @param primaryType the primary template for this type. */ public Control(@NonNull String controlId, @DeviceTypes.DeviceType int deviceType, @@ -88,11 +121,15 @@ public class Control implements Parcelable { @Nullable CharSequence structure, @Nullable CharSequence zone, @NonNull PendingIntent appIntent, - int primaryType) { + @Status int status, + @NonNull ControlTemplate controlTemplate, + @NonNull CharSequence statusText) { Preconditions.checkNotNull(controlId); Preconditions.checkNotNull(title); Preconditions.checkNotNull(subtitle); Preconditions.checkNotNull(appIntent); + Preconditions.checkNotNull(controlTemplate); + Preconditions.checkNotNull(statusText); mControlId = controlId; if (!DeviceTypes.validDeviceType(deviceType)) { Log.e(TAG, "Invalid device type:" + deviceType); @@ -105,7 +142,14 @@ public class Control implements Parcelable { mStructure = structure; mZone = zone; mAppIntent = appIntent; - mPrimaryType = primaryType; + if (status < 0 || status >= NUM_STATUS) { + mStatus = STATUS_UNKNOWN; + Log.e(TAG, "Status unknown:" + status); + } else { + mStatus = status; + } + mControlTemplate = controlTemplate; + mStatusText = statusText; } public Control(Parcel in) { @@ -124,7 +168,9 @@ public class Control implements Parcelable { mZone = null; } mAppIntent = PendingIntent.CREATOR.createFromParcel(in); - mPrimaryType = in.readInt(); + mStatus = in.readInt(); + mControlTemplate = ControlTemplate.CREATOR.createFromParcel(in); + mStatusText = in.readCharSequence(); } @NonNull @@ -162,9 +208,19 @@ public class Control implements Parcelable { return mAppIntent; } - @android.service.controls.templates.ControlTemplate.TemplateType - public int getPrimaryType() { - return mPrimaryType; + @Status + public int getStatus() { + return mStatus; + } + + @NonNull + public ControlTemplate getControlTemplate() { + return mControlTemplate; + } + + @NonNull + public CharSequence getStatusText() { + return mStatusText; } @Override @@ -191,7 +247,9 @@ public class Control implements Parcelable { dest.writeByte((byte) 0); } mAppIntent.writeToParcel(dest, flags); - dest.writeInt(mPrimaryType); + dest.writeInt(mStatus); + mControlTemplate.writeToParcel(dest, flags); + dest.writeCharSequence(mStatusText); } public static final Creator<Control> CREATOR = new Creator<Control>() { @@ -209,32 +267,39 @@ public class Control implements Parcelable { /** * Builder class for {@link Control}. * - * This class facilitates the creation of {@link Control}. It provides the following - * defaults for non-optional parameters: + * This class facilitates the creation of {@link Control} with no state. + * It provides the following defaults for non-optional parameters: * <ul> * <li> Device type: {@link DeviceTypes#TYPE_UNKNOWN} * <li> Title: {@code ""} * <li> Subtitle: {@code ""} - * <li> Primary template: {@link ControlTemplate#TYPE_NONE} + * </ul> + * This fixes the values relating to state of the {@link Control} as required by + * {@link ControlsProviderService#onLoad}: + * <ul> + * <li> Status: {@link Status#STATUS_UNKNOWN} + * <li> Control template: {@link ControlTemplate#NO_TEMPLATE} + * <li> Status text: {@code ""} * </ul> */ - public static class Builder { - private static final String TAG = "Control.Builder"; - private @NonNull String mControlId; - private @DeviceTypes.DeviceType - int mDeviceType = DeviceTypes.TYPE_UNKNOWN; - private @NonNull CharSequence mTitle = ""; - private @NonNull CharSequence mSubtitle = ""; - private @Nullable CharSequence mStructure; - private @Nullable CharSequence mZone; - private @NonNull PendingIntent mAppIntent; - private @ControlTemplate.TemplateType int mPrimaryType = ControlTemplate.TYPE_NONE; + public static class StatelessBuilder { + private static final String TAG = "StatelessBuilder"; + protected @NonNull String mControlId; + protected @DeviceTypes.DeviceType int mDeviceType = DeviceTypes.TYPE_UNKNOWN; + protected @NonNull CharSequence mTitle = ""; + protected @NonNull CharSequence mSubtitle = ""; + protected @Nullable CharSequence mStructure; + protected @Nullable CharSequence mZone; + protected @NonNull PendingIntent mAppIntent; + protected @Status int mStatus = STATUS_UNKNOWN; + protected @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE; + protected @NonNull CharSequence mStatusText = ""; /** * @param controlId the identifier for the {@link Control}. * @param appIntent the pending intent linking to the device Activity. */ - public Builder(@NonNull String controlId, + public StatelessBuilder(@NonNull String controlId, @NonNull PendingIntent appIntent) { Preconditions.checkNotNull(controlId); Preconditions.checkNotNull(appIntent); @@ -243,10 +308,10 @@ public class Control implements Parcelable { } /** - * Creates a {@link Builder} using an existing {@link Control} as a base. + * Creates a {@link StatelessBuilder} using an existing {@link Control} as a base. * @param control base for the builder. */ - public Builder(@NonNull Control control) { + public StatelessBuilder(@NonNull Control control) { Preconditions.checkNotNull(control); mControlId = control.mControlId; mDeviceType = control.mDeviceType; @@ -255,7 +320,6 @@ public class Control implements Parcelable { mStructure = control.mStructure; mZone = control.mZone; mAppIntent = control.mAppIntent; - mPrimaryType = control.mPrimaryType; } /** @@ -263,14 +327,14 @@ public class Control implements Parcelable { * @return {@code this} */ @NonNull - public Builder setControlId(@NonNull String controlId) { + public StatelessBuilder setControlId(@NonNull String controlId) { Preconditions.checkNotNull(controlId); mControlId = controlId; return this; } @NonNull - public Builder setDeviceType(@DeviceTypes.DeviceType int deviceType) { + public StatelessBuilder setDeviceType(@DeviceTypes.DeviceType int deviceType) { if (!DeviceTypes.validDeviceType(deviceType)) { Log.e(TAG, "Invalid device type:" + deviceType); mDeviceType = DeviceTypes.TYPE_UNKNOWN; @@ -285,27 +349,27 @@ public class Control implements Parcelable { * @return {@code this} */ @NonNull - public Builder setTitle(@NonNull CharSequence title) { + public StatelessBuilder setTitle(@NonNull CharSequence title) { Preconditions.checkNotNull(title); mTitle = title; return this; } @NonNull - public Builder setSubtitle(@NonNull CharSequence subtitle) { + public StatelessBuilder setSubtitle(@NonNull CharSequence subtitle) { Preconditions.checkNotNull(subtitle); mSubtitle = subtitle; return this; } @NonNull - public Builder setStructure(@Nullable CharSequence structure) { + public StatelessBuilder setStructure(@Nullable CharSequence structure) { mStructure = structure; return this; } @NonNull - public Builder setZone(@Nullable CharSequence zone) { + public StatelessBuilder setZone(@Nullable CharSequence zone) { mZone = zone; return this; } @@ -315,23 +379,13 @@ public class Control implements Parcelable { * @return {@code this} */ @NonNull - public Builder setAppIntent(@NonNull PendingIntent appIntent) { + public StatelessBuilder setAppIntent(@NonNull PendingIntent appIntent) { Preconditions.checkNotNull(appIntent); mAppIntent = appIntent; return this; } /** - * @param type type to use as default in the {@link Control} - * @return {@code this} - */ - @NonNull - public Builder setPrimaryType(@ControlTemplate.TemplateType int type) { - mPrimaryType = type; - return this; - } - - /** * Build a {@link Control} * @return a valid {@link Control} */ @@ -344,7 +398,108 @@ public class Control implements Parcelable { mStructure, mZone, mAppIntent, - mPrimaryType); + mStatus, + mControlTemplate, + mStatusText); + } + } + + public static class StatefulBuilder extends StatelessBuilder { + private static final String TAG = "StatefulBuilder"; + + /** + * @param controlId the identifier for the {@link Control}. + * @param appIntent the pending intent linking to the device Activity. + */ + public StatefulBuilder(@NonNull String controlId, + @NonNull PendingIntent appIntent) { + super(controlId, appIntent); + } + + public StatefulBuilder(@NonNull Control control) { + super(control); + mStatus = control.mStatus; + mControlTemplate = control.mControlTemplate; + mStatusText = control.mStatusText; + } + + /** + * @param controlId the identifier for the {@link Control}. + * @return {@code this} + */ + @NonNull + public StatefulBuilder setControlId(@NonNull String controlId) { + super.setControlId(controlId); + return this; + } + + @NonNull + public StatefulBuilder setDeviceType(@DeviceTypes.DeviceType int deviceType) { + super.setDeviceType(deviceType); + return this; + } + + /** + * @param title the user facing name of the {@link Control} + * @return {@code this} + */ + @NonNull + public StatefulBuilder setTitle(@NonNull CharSequence title) { + super.setTitle(title); + return this; + } + + @NonNull + public StatefulBuilder setSubtitle(@NonNull CharSequence subtitle) { + super.setSubtitle(subtitle); + return this; + } + + @NonNull + public StatefulBuilder setStructure(@Nullable CharSequence structure) { + super.setStructure(structure); + return this; + } + + @NonNull + public StatefulBuilder setZone(@Nullable CharSequence zone) { + super.setZone(zone); + return this; + } + + /** + * @param appIntent an {@link Intent} linking to an Activity for the {@link Control} + * @return {@code this} + */ + @NonNull + public StatefulBuilder setAppIntent(@NonNull PendingIntent appIntent) { + super.setAppIntent(appIntent); + return this; + } + + @NonNull + public StatefulBuilder setStatus(@Status int status) { + if (status < 0 || status >= NUM_STATUS) { + mStatus = STATUS_UNKNOWN; + Log.e(TAG, "Status unknown:" + status); + } else { + mStatus = status; + } + return this; + } + + @NonNull + public StatefulBuilder setControlTemplate(@NonNull ControlTemplate controlTemplate) { + Preconditions.checkNotNull(controlTemplate); + mControlTemplate = controlTemplate; + return this; + } + + @NonNull + public StatefulBuilder setStatusText(@NonNull CharSequence statusText) { + Preconditions.checkNotNull(statusText); + mStatusText = statusText; + return this; } } } diff --git a/core/java/android/service/controls/ControlState.aidl b/core/java/android/service/controls/ControlState.aidl deleted file mode 100644 index 520d85b47d3e..000000000000 --- a/core/java/android/service/controls/ControlState.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2019, 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 android.service.controls; - -parcelable ControlState;
\ No newline at end of file diff --git a/core/java/android/service/controls/ControlState.java b/core/java/android/service/controls/ControlState.java deleted file mode 100644 index 998fb54613ba..000000000000 --- a/core/java/android/service/controls/ControlState.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (C) 2019 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 android.service.controls; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.PendingIntent; -import android.os.Parcel; -import android.os.Parcelable; -import android.service.controls.templates.ControlTemplate; -import android.util.Log; - -import com.android.internal.util.Preconditions; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Current state for a {@link Control}. - * - * Collects information to render the current state of a {@link Control} as well as possible action - * that can be performed on it. - * <p> - * Additionally, this object is used to modify elements from the {@link Control} such as device - * type, and intents. This information will last until it is again modified by a - * {@link ControlState}. - * @hide - */ -public final class ControlState implements Parcelable { - - private static final String TAG = "ControlState"; - - /** - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - STATUS_OK, - STATUS_NOT_FOUND, - STATUS_ERROR, - STATUS_DISABLED, - }) - public @interface Status {}; - - /** - * The device corresponding to the {@link Control} is responding correctly. - */ - public static final int STATUS_OK = 0; - - /** - * The device corresponding to the {@link Control} cannot be found or was removed. - */ - public static final int STATUS_NOT_FOUND = 1; - - /** - * The device corresponding to the {@link Control} is in an error state. - */ - public static final int STATUS_ERROR = 2; - - /** - * The {@link Control} is currently disabled. - */ - public static final int STATUS_DISABLED = 3; - - private final @NonNull String mControlId; - private final @DeviceTypes.DeviceType int mDeviceType; - private final @Status int mStatus; - private final @NonNull ControlTemplate mControlTemplate; - private final @NonNull CharSequence mStatusText; - private final @Nullable PendingIntent mAppIntent; - - /** - * @param controlId the identifier of the {@link Control} this object refers to. - * @param status the current status of the {@link Control}. - * @param deviceType the {@link DeviceTypes.DeviceType} to replace the one set in the - * {@link Control} or set in the last {@link ControlState}. In order to keep - * the current device type for this {@link Control}, the old value must be - * passed. - * @param controlTemplate the template to be used to render the {@link Control}. This can be - * of a different {@link ControlTemplate.TemplateType} than the - * one defined in {@link Control#getPrimaryType} - * @param statusText the user facing text describing the current status. - * @param appIntent the {@link PendingIntent} to replace the one set in the {@link Control} or - * set in the last {@link ControlState}. Pass {@code null} to use the last - * value set for this {@link Control}. - */ - public ControlState(@NonNull String controlId, - @DeviceTypes.DeviceType int deviceType, - @Status int status, - @NonNull ControlTemplate controlTemplate, - @NonNull CharSequence statusText, - @Nullable PendingIntent appIntent) { - Preconditions.checkNotNull(controlId); - Preconditions.checkNotNull(controlTemplate); - Preconditions.checkNotNull(statusText); - mControlId = controlId; - if (!DeviceTypes.validDeviceType(deviceType)) { - Log.e(TAG, "Invalid device type:" + deviceType); - mDeviceType = DeviceTypes.TYPE_UNKNOWN; - } else { - mDeviceType = deviceType; - } - mStatus = status; - mControlTemplate = controlTemplate; - mStatusText = statusText; - mAppIntent = appIntent; - } - - ControlState(Parcel in) { - mControlId = in.readString(); - mDeviceType = in.readInt(); - mStatus = in.readInt(); - mControlTemplate = ControlTemplate.CREATOR.createFromParcel(in); - mStatusText = in.readCharSequence(); - if (in.readByte() == 1) { - mAppIntent = PendingIntent.CREATOR.createFromParcel(in); - } else { - mAppIntent = null; - } - } - - @Override - public int describeContents() { - return 0; - } - - @NonNull - public String getControlId() { - return mControlId; - } - - @DeviceTypes.DeviceType - public int getDeviceType() { - return mDeviceType; - } - - @Nullable - public PendingIntent getAppIntent() { - return mAppIntent; - } - - @Status - public int getStatus() { - return mStatus; - } - - @NonNull - public ControlTemplate getControlTemplate() { - return mControlTemplate; - } - - @NonNull - public CharSequence getStatusText() { - return mStatusText; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mControlId); - dest.writeInt(mDeviceType); - dest.writeInt(mStatus); - mControlTemplate.writeToParcel(dest, flags); - dest.writeCharSequence(mStatusText); - if (mAppIntent != null) { - dest.writeByte((byte) 1); - mAppIntent.writeToParcel(dest, flags); - } else { - dest.writeByte((byte) 0); - } - } - - public static final Creator<ControlState> CREATOR = new Creator<ControlState>() { - @Override - public ControlState createFromParcel(Parcel source) { - return new ControlState(source); - } - - @Override - public ControlState[] newArray(int size) { - return new ControlState[size]; - } - }; - - /** - * Builder class for {@link ControlState}. - * - * This class facilitates the creation of {@link ControlState}. It provides the following - * defaults for non-optional parameters: - * <ul> - * <li> Device type: {@link DeviceTypes#TYPE_UNKNOWN} - * <li> Status: {@link ControlState#STATUS_OK} - * <li> Control template: {@link ControlTemplate#NO_TEMPLATE} - * <li> Status text: {@code ""} - * </ul> - */ - public static class Builder { - private static final String TAG = "ControlState.Builder"; - - private @NonNull String mControlId; - private @DeviceTypes.DeviceType - int mDeviceType = DeviceTypes.TYPE_UNKNOWN; - private @Status int mStatus = STATUS_OK; - private @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE; - private @NonNull CharSequence mStatusText = ""; - private @Nullable PendingIntent mAppIntent; - - /** - * @param controlId the identifier of the {@link Control} that the resulting - * {@link ControlState} refers to. - */ - public Builder(@NonNull String controlId) { - Preconditions.checkNotNull(controlId); - mControlId = controlId; - } - - /** - * Creates a {@link Builder} using an existing {@link ControlState} as a base. - * @param controlState base for the builder. - */ - public Builder(@NonNull ControlState controlState) { - Preconditions.checkNotNull(controlState); - mControlId = controlState.mControlId; - mDeviceType = controlState.mDeviceType; - mStatus = controlState.mStatus; - mControlTemplate = controlState.mControlTemplate; - mStatusText = controlState.mStatusText; - mAppIntent = controlState.mAppIntent; - } - - - /** - * @param controlId the identifier of the {@link Control} for the resulting object. - * @return {@code this} - */ - @NonNull - public Builder setControlId(@NonNull String controlId) { - mControlId = controlId; - return this; - } - - /** - * @param deviceType the device type of the {@link Control}. - * @return {@code this} - */ - @NonNull - public Builder setDeviceType(@DeviceTypes.DeviceType int deviceType) { - if (!DeviceTypes.validDeviceType(deviceType)) { - Log.e(TAG, "Invalid device type:" + deviceType); - mDeviceType = DeviceTypes.TYPE_UNKNOWN; - } else { - mDeviceType = deviceType; - } - return this; - } - - /** - * @param status the current status of the {@link Control} - * @return {@code this} - */ - @NonNull - public Builder setStatus(@Status int status) { - mStatus = status; - return this; - } - - /** - * @param controlTemplate the template to use when rendering the {@code Control}. - * @return {@code this} - */ - @NonNull - public Builder setControlTemplate(@NonNull ControlTemplate controlTemplate) { - Preconditions.checkNotNull(controlTemplate); - mControlTemplate = controlTemplate; - return this; - } - - /** - * @param statusText the user-visible description of the status. - * @return {@code this} - */ - @NonNull - public Builder setStatusText(@NonNull CharSequence statusText) { - Preconditions.checkNotNull(statusText); - mStatusText = statusText; - return this; - } - - /** - * @param appIntent the Pending Intent to replace the one defined in the corresponding - * {@link Control} or set by the last {@link ControlState}. Pass - * {@code null} to keep the last value. - * @return {@code this} - */ - @NonNull - public Builder setAppIntent(@Nullable PendingIntent appIntent) { - mAppIntent = appIntent; - return this; - } - - /** - * @return a new {@link ControlState} - */ - public ControlState build() { - return new ControlState(mControlId, mDeviceType, mStatus, mControlTemplate, mStatusText, - mAppIntent); - } - - /** - * Creates a new {@link ControlState.Builder} for the given {@link Control}. - * - * This will set the corresponding identifier as well as the device type. - * @param control the {@link Control} to create a state for. - * @return a {@link ControlState.Builder} for a {@link Control} - */ - public static Builder createForControl(Control control) { - return new Builder(control.getControlId()).setDeviceType(control.getDeviceType()); - } - } -} - diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java index 8a95f4d0f566..2fd51a1578f6 100644 --- a/core/java/android/service/controls/ControlsProviderService.java +++ b/core/java/android/service/controls/ControlsProviderService.java @@ -20,13 +20,21 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Service; import android.content.Intent; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.service.controls.actions.ControlAction; +import android.service.controls.templates.ControlTemplate; +import android.text.TextUtils; +import android.util.Log; +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; import java.util.List; /** @@ -38,8 +46,14 @@ public abstract class ControlsProviderService extends Service { @SdkConstant(SdkConstantType.SERVICE_ACTION) public static final String CONTROLS_ACTION = "android.service.controls.ControlsProviderService"; + public static final String CALLBACK_BUNDLE = "CALLBACK_BUNDLE"; + public static final String CALLBACK_BINDER = "CALLBACK_BINDER"; + public static final String CALLBACK_TOKEN = "CALLBACK_TOKEN"; + + public final String TAG = getClass().getSimpleName(); private IControlsProviderCallback mCallback; + private IBinder mToken; private RequestHandler mHandler; /** @@ -67,16 +81,80 @@ public abstract class ControlsProviderService extends Service { */ public abstract void onAction(@NonNull String controlId, @NonNull ControlAction action); - protected IControlsProviderCallback getControlsProviderCallback() { - return mCallback; + /** + * Sends a list of the controls available from this service. + * + * The items in the list must not have state information (as created by + * {@link Control.StatelessBuilder}). + * @param controls + */ + public void onLoad(@NonNull List<Control> controls) { + Preconditions.checkNotNull(controls); + List<Control> list = new ArrayList<>(); + for (Control control: controls) { + if (control == null) { + Log.e(TAG, "onLoad: null control."); + } + if (isStateless(control)) { + list.add(control); + } else { + Log.w(TAG, "onLoad: control is not stateless."); + list.add(new Control.StatelessBuilder(control).build()); + } + } + try { + mCallback.onLoad(mToken, list); + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + } + + /** + * Sends a list of the controls requested by {@link ControlsProviderService#subscribe} with + * their state. + * @param statefulControls + */ + public void onRefreshState(@NonNull List<Control> statefulControls) { + Preconditions.checkNotNull(statefulControls); + try { + mCallback.onRefreshState(mToken, statefulControls); + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + } + + /** + * Sends the response of a command in the specified {@link Control}. + * @param controlId + * @param response + */ + public void onControlActionResponse( + @NonNull String controlId, @ControlAction.ResponseResult int response) { + Preconditions.checkNotNull(controlId); + if (!ControlAction.isValidResponse(response)) { + Log.e(TAG, "Not valid response result: " + response); + response = ControlAction.RESPONSE_UNKNOWN; + } + try { + mCallback.onControlActionResponse(mToken, controlId, response); + } catch (RemoteException ex) { + ex.rethrowAsRuntimeException(); + } + } + + private boolean isStateless(Control control) { + return (control.getStatus() == Control.STATUS_UNKNOWN + && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE + && TextUtils.isEmpty(control.getStatusText())); } @Override public IBinder onBind(Intent intent) { mHandler = new RequestHandler(Looper.getMainLooper()); - Bundle bundle = intent.getBundleExtra("CALLBACK_BUNDLE"); - IBinder callbackBinder = bundle.getBinder("CALLBACK_BINDER"); + Bundle bundle = intent.getBundleExtra(CALLBACK_BUNDLE); + IBinder callbackBinder = bundle.getBinder(CALLBACK_BINDER); + mToken = bundle.getBinder(CALLBACK_TOKEN); mCallback = IControlsProviderCallback.Stub.asInterface(callbackBinder); return new IControlsProvider.Stub() { diff --git a/core/java/android/service/controls/IControlsProviderCallback.aidl b/core/java/android/service/controls/IControlsProviderCallback.aidl index 3dbb68c1c7f0..91f6a7980ce6 100644 --- a/core/java/android/service/controls/IControlsProviderCallback.aidl +++ b/core/java/android/service/controls/IControlsProviderCallback.aidl @@ -17,13 +17,12 @@ package android.service.controls; import android.service.controls.Control; -import android.service.controls.ControlState; /** @hide */ oneway interface IControlsProviderCallback { - void onLoad(in List<Control> controls); + void onLoad(in IBinder token, in List<Control> controls); - void onRefreshState(in List<ControlState> controlStates); + void onRefreshState(in IBinder token, in List<Control> statefulControls); - void onControlActionResponse(in String controlId, int response); + void onControlActionResponse(in IBinder token, in String controlId, int response); }
\ No newline at end of file diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java index 63ae9bd6810f..83d1cf824f1f 100644 --- a/core/java/android/service/controls/actions/ControlAction.java +++ b/core/java/android/service/controls/actions/ControlAction.java @@ -23,8 +23,8 @@ import android.annotation.Nullable; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.service.controls.templates.ControlTemplate; import android.service.controls.IControlsProviderCallback; +import android.service.controls.templates.ControlTemplate; import com.android.internal.util.Preconditions; @@ -82,11 +82,17 @@ public abstract class ControlAction implements Parcelable { public static final @ActionType int TYPE_COMMAND = 5; + + public static final boolean isValidResponse(@ResponseResult int response) { + return (response >= 0 && response < NUM_RESPONSE_TYPES); + } + private static final int NUM_RESPONSE_TYPES = 6; /** * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ + RESPONSE_UNKNOWN, RESPONSE_OK, RESPONSE_FAIL, RESPONSE_CHALLENGE_ACK, @@ -95,31 +101,33 @@ public abstract class ControlAction implements Parcelable { }) public @interface ResponseResult {}; + public static final @ResponseResult int RESPONSE_UNKNOWN = 0; + /** * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that * the action has been performed. The action may still fail later and the state may not change. */ - public static final @ResponseResult int RESPONSE_OK = 0; + public static final @ResponseResult int RESPONSE_OK = 1; /** * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that * the action has failed. */ - public static final @ResponseResult int RESPONSE_FAIL = 1; + public static final @ResponseResult int RESPONSE_FAIL = 2; /** * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that * in order for the action to be performed, acknowledgment from the user is required. */ - public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 2; + public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 3; /** * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that * in order for the action to be performed, a PIN is required. */ - public static final @ResponseResult int RESPONSE_CHALLENGE_PIN = 3; + public static final @ResponseResult int RESPONSE_CHALLENGE_PIN = 4; /** * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that * in order for the action to be performed, an alphanumeric passphrase is required. */ - public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 4; + public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 5; /** * The {@link ActionType} associated with this class. diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java index f39b26efee49..bf194f8efcda 100644 --- a/core/java/android/service/controls/templates/ControlTemplate.java +++ b/core/java/android/service/controls/templates/ControlTemplate.java @@ -23,7 +23,6 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.service.controls.Control; -import android.service.controls.ControlState; import android.service.controls.actions.ControlAction; import com.android.internal.util.Preconditions; @@ -34,12 +33,11 @@ import java.lang.annotation.RetentionPolicy; /** * An abstract input template for a {@link Control}. * - * Specifies what layout is presented to the user when a {@link ControlState} is assigned to a - * particular {@link Control}. + * Specifies what layout is presented to the user for a given {@link Control}. * <p> * Some instances of {@link Control} can originate actions (via user interaction) to modify its - * associated state. The actions available to a given {@link Control} in a particular - * {@link ControlState} are determined by its {@link ControlTemplate}. + * associated state. The actions available to a given {@link Control} are determined by its + * {@link ControlTemplate}. * @see ControlAction * @hide */ diff --git a/core/java/android/service/controls/templates/RangeTemplate.java b/core/java/android/service/controls/templates/RangeTemplate.java index 5624f88b16a3..bb79d83b1825 100644 --- a/core/java/android/service/controls/templates/RangeTemplate.java +++ b/core/java/android/service/controls/templates/RangeTemplate.java @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.os.Bundle; import android.os.Parcel; import android.service.controls.Control; -import android.service.controls.ControlState; import android.service.controls.actions.FloatAction; /** @@ -61,7 +60,7 @@ public final class RangeTemplate extends ControlTemplate { * @param templateId the identifier for this template object * @param minValue minimum value for the input * @param maxValue maximum value for the input - * @param currentValue the current value of the {@link ControlState} containing this object. + * @param currentValue the current value of the {@link Control} containing this object. * @param stepValue minimum value of increments/decrements when interacting with this control. * @param formatString a formatting string as per {@link String#format} used to display the * {@code currentValue}. If {@code null} is passed, the "%.1f" is used. |