1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.service.controls.templates; 18 19 import android.annotation.CallSuper; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.os.Bundle; 24 import android.service.controls.Control; 25 import android.service.controls.actions.ControlAction; 26 import android.util.Log; 27 28 import com.android.internal.util.Preconditions; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 33 /** 34 * An abstract input template for a {@link Control}. 35 * 36 * Specifies what layout is presented to the user for a given {@link Control}. 37 * <p> 38 * Some instances of {@link Control} can originate actions (via user interaction) to modify its 39 * associated state. The actions available to a given {@link Control} are determined by its 40 * {@link ControlTemplate}. 41 * @see ControlAction 42 */ 43 public abstract class ControlTemplate { 44 45 private static final String TAG = "ControlTemplate"; 46 47 private static final String KEY_TEMPLATE_ID = "key_template_id"; 48 private static final String KEY_TEMPLATE_TYPE = "key_template_type"; 49 50 /** 51 * Singleton representing a {@link Control} with no input. 52 * @hide 53 */ 54 public static final @NonNull ControlTemplate NO_TEMPLATE = new ControlTemplate("") { 55 @Override 56 public int getTemplateType() { 57 return TYPE_NO_TEMPLATE; 58 } 59 }; 60 61 /** 62 * Object returned when there is an unparcelling error. 63 * @hide 64 */ 65 private static final @NonNull ControlTemplate ERROR_TEMPLATE = new ControlTemplate("") { 66 @Override 67 public int getTemplateType() { 68 return TYPE_ERROR; 69 } 70 }; 71 72 /** 73 * @hide 74 */ 75 @Retention(RetentionPolicy.SOURCE) 76 @IntDef({ 77 TYPE_ERROR, 78 TYPE_NO_TEMPLATE, 79 TYPE_TOGGLE, 80 TYPE_RANGE, 81 TYPE_TOGGLE_RANGE, 82 TYPE_TEMPERATURE, 83 TYPE_STATELESS 84 }) 85 public @interface TemplateType {} 86 87 /** 88 * Type identifier of the template returned by {@link #getErrorTemplate()}. 89 */ 90 public static final @TemplateType int TYPE_ERROR = -1; 91 92 /** 93 * Type identifier of {@link ControlTemplate#getNoTemplateObject}. 94 */ 95 public static final @TemplateType int TYPE_NO_TEMPLATE = 0; 96 97 /** 98 * Type identifier of {@link ToggleTemplate}. 99 */ 100 public static final @TemplateType int TYPE_TOGGLE = 1; 101 102 /** 103 * Type identifier of {@link RangeTemplate}. 104 */ 105 public static final @TemplateType int TYPE_RANGE = 2; 106 107 /** 108 * Type identifier of {@link ToggleRangeTemplate}. 109 */ 110 public static final @TemplateType int TYPE_TOGGLE_RANGE = 6; 111 112 /** 113 * Type identifier of {@link TemperatureControlTemplate}. 114 */ 115 public static final @TemplateType int TYPE_TEMPERATURE = 7; 116 117 /** 118 * Type identifier of {@link StatelessTemplate}. 119 */ 120 public static final @TemplateType int TYPE_STATELESS = 8; 121 122 private @NonNull final String mTemplateId; 123 124 /** 125 * @return the identifier for this object. 126 */ 127 @NonNull getTemplateId()128 public String getTemplateId() { 129 return mTemplateId; 130 } 131 132 /** 133 * The {@link TemplateType} associated with this class. 134 */ getTemplateType()135 public abstract @TemplateType int getTemplateType(); 136 137 /** 138 * Obtain a {@link Bundle} describing this object populated with data. 139 * @return a {@link Bundle} containing the data that represents this object. 140 * @hide 141 */ 142 @CallSuper 143 @NonNull getDataBundle()144 Bundle getDataBundle() { 145 Bundle b = new Bundle(); 146 b.putInt(KEY_TEMPLATE_TYPE, getTemplateType()); 147 b.putString(KEY_TEMPLATE_ID, mTemplateId); 148 return b; 149 } 150 ControlTemplate()151 private ControlTemplate() { 152 mTemplateId = ""; 153 } 154 155 /** 156 * @param b 157 * @hide 158 */ ControlTemplate(@onNull Bundle b)159 ControlTemplate(@NonNull Bundle b) { 160 mTemplateId = b.getString(KEY_TEMPLATE_ID); 161 } 162 163 /** 164 * @hide 165 */ ControlTemplate(@onNull String templateId)166 ControlTemplate(@NonNull String templateId) { 167 Preconditions.checkNotNull(templateId); 168 mTemplateId = templateId; 169 } 170 171 /** 172 * 173 * @param bundle 174 * @return 175 * @hide 176 */ 177 @NonNull createTemplateFromBundle(@ullable Bundle bundle)178 static ControlTemplate createTemplateFromBundle(@Nullable Bundle bundle) { 179 if (bundle == null) { 180 Log.e(TAG, "Null bundle"); 181 return ERROR_TEMPLATE; 182 } 183 int type = bundle.getInt(KEY_TEMPLATE_TYPE, TYPE_ERROR); 184 try { 185 switch (type) { 186 case TYPE_TOGGLE: 187 return new ToggleTemplate(bundle); 188 case TYPE_RANGE: 189 return new RangeTemplate(bundle); 190 case TYPE_TOGGLE_RANGE: 191 return new ToggleRangeTemplate(bundle); 192 case TYPE_TEMPERATURE: 193 return new TemperatureControlTemplate(bundle); 194 case TYPE_STATELESS: 195 return new StatelessTemplate(bundle); 196 case TYPE_NO_TEMPLATE: 197 return NO_TEMPLATE; 198 case TYPE_ERROR: 199 default: 200 return ERROR_TEMPLATE; 201 } 202 } catch (Exception e) { 203 Log.e(TAG, "Error creating template", e); 204 return ERROR_TEMPLATE; 205 } 206 } 207 208 /** 209 * @return a singleton {@link ControlTemplate} used for indicating an error in unparceling. 210 */ 211 @NonNull getErrorTemplate()212 public static ControlTemplate getErrorTemplate() { 213 return ERROR_TEMPLATE; 214 } 215 216 /** 217 * Get a singleton {@link ControlTemplate}, which supports no direct user input. 218 * 219 * Used by {@link Control.StatelessBuilder} when there is no known state. Can also be used 220 * in {@link Control.StatefulBuilder} for conveying information to a user about the 221 * {@link Control} but direct user interaction is not desired. Since this template has no 222 * corresponding {@link ControlAction}, any user interaction will launch the 223 * {@link Control#getAppIntent()}. 224 * 225 * @return a singleton {@link ControlTemplate} to indicate no specific template is used by 226 * this {@link Control} 227 */ 228 @NonNull getNoTemplateObject()229 public static ControlTemplate getNoTemplateObject() { 230 return NO_TEMPLATE; 231 } 232 233 } 234