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.content.Context; 24 import android.os.Bundle; 25 import android.service.controls.Control; 26 import android.service.controls.actions.ControlAction; 27 import android.util.Log; 28 29 import com.android.internal.util.Preconditions; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 34 /** 35 * An abstract input template for a {@link Control}. 36 * 37 * Specifies what layout is presented to the user for a given {@link Control}. 38 * <p> 39 * Some instances of {@link Control} can originate actions (via user interaction) to modify its 40 * associated state. The actions available to a given {@link Control} are determined by its 41 * {@link ControlTemplate}. 42 * @see ControlAction 43 */ 44 public abstract class ControlTemplate { 45 46 private static final String TAG = "ControlTemplate"; 47 48 private static final String KEY_TEMPLATE_ID = "key_template_id"; 49 private static final String KEY_TEMPLATE_TYPE = "key_template_type"; 50 51 /** 52 * Singleton representing a {@link Control} with no input. 53 * @hide 54 */ 55 public static final @NonNull ControlTemplate NO_TEMPLATE = new ControlTemplate("") { 56 @Override 57 public int getTemplateType() { 58 return TYPE_NO_TEMPLATE; 59 } 60 }; 61 62 /** 63 * Object returned when there is an unparcelling error. 64 * @hide 65 */ 66 private static final @NonNull ControlTemplate ERROR_TEMPLATE = new ControlTemplate("") { 67 @Override 68 public int getTemplateType() { 69 return TYPE_ERROR; 70 } 71 }; 72 73 /** 74 * @hide 75 */ 76 @Retention(RetentionPolicy.SOURCE) 77 @IntDef({ 78 TYPE_ERROR, 79 TYPE_NO_TEMPLATE, 80 TYPE_TOGGLE, 81 TYPE_RANGE, 82 TYPE_THUMBNAIL, 83 TYPE_TOGGLE_RANGE, 84 TYPE_TEMPERATURE, 85 TYPE_STATELESS 86 }) 87 public @interface TemplateType {} 88 89 /** 90 * Type identifier of the template returned by {@link #getErrorTemplate()}. 91 */ 92 public static final @TemplateType int TYPE_ERROR = -1; 93 94 /** 95 * Type identifier of {@link ControlTemplate#getNoTemplateObject}. 96 */ 97 public static final @TemplateType int TYPE_NO_TEMPLATE = 0; 98 99 /** 100 * Type identifier of {@link ToggleTemplate}. 101 */ 102 public static final @TemplateType int TYPE_TOGGLE = 1; 103 104 /** 105 * Type identifier of {@link RangeTemplate}. 106 */ 107 public static final @TemplateType int TYPE_RANGE = 2; 108 109 /** 110 * Type identifier of {@link ThumbnailTemplate}. 111 */ 112 public static final @TemplateType int TYPE_THUMBNAIL = 3; 113 114 /** 115 * Type identifier of {@link ToggleRangeTemplate}. 116 */ 117 public static final @TemplateType int TYPE_TOGGLE_RANGE = 6; 118 119 /** 120 * Type identifier of {@link TemperatureControlTemplate}. 121 */ 122 public static final @TemplateType int TYPE_TEMPERATURE = 7; 123 124 /** 125 * Type identifier of {@link StatelessTemplate}. 126 */ 127 public static final @TemplateType int TYPE_STATELESS = 8; 128 129 private @NonNull final String mTemplateId; 130 131 /** 132 * @return the identifier for this object. 133 */ 134 @NonNull getTemplateId()135 public String getTemplateId() { 136 return mTemplateId; 137 } 138 139 /** 140 * The template type associated with this class. 141 */ getTemplateType()142 public abstract @TemplateType int getTemplateType(); 143 144 /** 145 * Obtain a {@link Bundle} describing this object populated with data. 146 * @return a {@link Bundle} containing the data that represents this object. 147 * @hide 148 */ 149 @CallSuper 150 @NonNull getDataBundle()151 Bundle getDataBundle() { 152 Bundle b = new Bundle(); 153 b.putInt(KEY_TEMPLATE_TYPE, getTemplateType()); 154 b.putString(KEY_TEMPLATE_ID, mTemplateId); 155 return b; 156 } 157 ControlTemplate()158 private ControlTemplate() { 159 mTemplateId = ""; 160 } 161 162 /** 163 * @param b 164 * @hide 165 */ ControlTemplate(@onNull Bundle b)166 ControlTemplate(@NonNull Bundle b) { 167 mTemplateId = b.getString(KEY_TEMPLATE_ID); 168 } 169 170 /** 171 * @hide 172 */ ControlTemplate(@onNull String templateId)173 ControlTemplate(@NonNull String templateId) { 174 Preconditions.checkNotNull(templateId); 175 mTemplateId = templateId; 176 } 177 178 /** 179 * Call to prepare values for Binder transport. 180 * 181 * @hide 182 */ prepareTemplateForBinder(@onNull Context context)183 public void prepareTemplateForBinder(@NonNull Context context) {} 184 185 /** 186 * 187 * @param bundle 188 * @return 189 * @hide 190 */ 191 @NonNull createTemplateFromBundle(@ullable Bundle bundle)192 static ControlTemplate createTemplateFromBundle(@Nullable Bundle bundle) { 193 if (bundle == null) { 194 Log.e(TAG, "Null bundle"); 195 return ERROR_TEMPLATE; 196 } 197 int type = bundle.getInt(KEY_TEMPLATE_TYPE, TYPE_ERROR); 198 try { 199 switch (type) { 200 case TYPE_TOGGLE: 201 return new ToggleTemplate(bundle); 202 case TYPE_RANGE: 203 return new RangeTemplate(bundle); 204 case TYPE_THUMBNAIL: 205 return new ThumbnailTemplate(bundle); 206 case TYPE_TOGGLE_RANGE: 207 return new ToggleRangeTemplate(bundle); 208 case TYPE_TEMPERATURE: 209 return new TemperatureControlTemplate(bundle); 210 case TYPE_STATELESS: 211 return new StatelessTemplate(bundle); 212 case TYPE_NO_TEMPLATE: 213 return NO_TEMPLATE; 214 case TYPE_ERROR: 215 default: 216 return ERROR_TEMPLATE; 217 } 218 } catch (Exception e) { 219 Log.e(TAG, "Error creating template", e); 220 return ERROR_TEMPLATE; 221 } 222 } 223 224 /** 225 * @return a singleton {@link ControlTemplate} used for indicating an error in unparceling. 226 */ 227 @NonNull getErrorTemplate()228 public static ControlTemplate getErrorTemplate() { 229 return ERROR_TEMPLATE; 230 } 231 232 /** 233 * Get a singleton {@link ControlTemplate}, which supports no direct user input. 234 * 235 * Used by {@link Control.StatelessBuilder} when there is no known state. Can also be used 236 * in {@link Control.StatefulBuilder} for conveying information to a user about the 237 * {@link Control} but direct user interaction is not desired. Since this template has no 238 * corresponding {@link ControlAction}, any user interaction will launch the 239 * {@link Control#getAppIntent()}. 240 * 241 * @return a singleton {@link ControlTemplate} to indicate no specific template is used by 242 * this {@link Control} 243 */ 244 @NonNull getNoTemplateObject()245 public static ControlTemplate getNoTemplateObject() { 246 return NO_TEMPLATE; 247 } 248 249 } 250