1 /* 2 * Copyright (C) 2022 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 com.android.systemui.complication; 18 19 import android.annotation.IntDef; 20 import android.view.View; 21 22 import java.lang.annotation.Retention; 23 import java.lang.annotation.RetentionPolicy; 24 25 /** 26 * {@link Complication} is an interface for defining a complication, a visual component rendered 27 * above a dream. {@link Complication} instances encapsulate the logic for generating the view to be 28 * shown, along with the supporting control/logic. The decision for including the 29 * {@link Complication} is not the responsibility of the {@link Complication}. This is instead 30 * handled by domain logic and invocations to add and remove the {@link Complication} through 31 * {@link com.android.systemui.dreams.DreamOverlayStateController#addComplication(Complication)} and 32 * {@link com.android.systemui.dreams.DreamOverlayStateController#removeComplication(Complication)}. 33 * A {@link Complication} also does not represent a specific instance of the view. Instead, it 34 * should be viewed as a provider, where view instances are requested from it. The associated 35 * {@link ViewHolder} interface is requested for each view request. This object is retained for the 36 * view's lifetime, providing a container for any associated logic. The complication rendering 37 * system will consult this {@link ViewHolder} for {@link View} to show and 38 * {@link ComplicationLayoutParams} to position the view. {@link ComplicationLayoutParams} allow for 39 * specifying the sizing and position of the {@link Complication}. 40 * 41 * The following code sample exhibits the entities and lifecycle involved with a 42 * {@link Complication}. 43 * 44 * <pre>{@code 45 * // This component allows for the complication to generate a new ViewHolder for every request. 46 * @Subcomponent 47 * interface ExampleViewHolderComponent { 48 * @Subcomponent.Factory 49 * interface Factory { 50 * ExampleViewHolderComponent create(); 51 * } 52 * 53 * ExampleViewHolder getViewHolder(); 54 * } 55 * 56 * // An example entity that controls whether or not a complication should be included on dreams. 57 * // Note how the complication is tracked by reference for removal. 58 * public class ExampleComplicationProvider { 59 * private final DreamOverlayStateController mDreamOverlayStateController; 60 * private final ExampleComplication mComplication; 61 * @Inject 62 * public ExampleComplicationProvider( 63 * ExampleComplication complication, 64 * DreamOverlayStateController stateController) { 65 * mDreamOverlayStateController = stateController; 66 * mComplication = complication; 67 * } 68 * 69 * public void onShowConditionsMet(boolean met) { 70 * if (met) { 71 * mDreamOverlayStateController.addComplication(mComplication); 72 * } else { 73 * mDreamOverlayStateController.removeComplication(mComplication); 74 * } 75 * } 76 * } 77 * 78 * // An example complication. Note how a factory is created to supply a unique ViewHolder for each 79 * // request. Also, there is no particular view instance members defined in the complication. 80 * class ExampleComplication implements Complication { 81 * private final ExampleViewHolderComponent.Factory mFactory; 82 * @Inject 83 * public ExampleComplication(ExampleViewHolderComponent.Factory viewHolderComponentFactory) { 84 * mFactory = viewHolderComponentFactory; 85 * } 86 * 87 * @Override 88 * public ViewHolder createView(ComplicationViewModel model) { 89 * return mFactory.create().getViewHolder(); 90 * } 91 * } 92 * 93 * // Not every ViewHolder needs to include a view controller. It is included here as an example of 94 * // how such logic can be contained and associated with the ViewHolder lifecycle. 95 * class ExampleViewController extends ViewController<FrameLayout> { 96 * protected ExampleViewController(FrameLayout view) { 97 * super(view); 98 * } 99 * 100 * @Override 101 * protected void onViewAttached() { } 102 * 103 * @Override 104 * protected void onViewDetached() { } 105 * } 106 * 107 * // An example ViewHolder. This is the correct place to contain any value/logic associated with a 108 * // particular instance of the ComplicationView. 109 * class ExampleViewHolder implements Complication.ViewHolder { 110 * final FrameLayout mView; 111 * final ExampleViewController mController; 112 * 113 * @Inject 114 * public ExampleViewHolder(Context context) { 115 * mView = new FrameLayout(context); 116 * mController = new ExampleViewController(mView); 117 * } 118 * @Override 119 * public View getView() { 120 * return mView; 121 * } 122 * 123 * @Override 124 * public ComplicationLayoutParams getLayoutParams() { 125 * return new ComplicationLayoutParams( 126 * 200, 127 * 100, 128 * ComplicationLayoutParams.POSITION_TOP | ComplicationLayoutParams.DIRECTION_END, 129 * ComplicationLayoutParams.DIRECTION_DOWN, 130 * 4); 131 * } 132 * } 133 * } 134 * </pre> 135 */ 136 public interface Complication { 137 @Retention(RetentionPolicy.SOURCE) 138 @IntDef(prefix = { "CATEGORY_" }, value = { 139 CATEGORY_STANDARD, 140 CATEGORY_SYSTEM, 141 }) 142 143 @interface Category {} 144 /** 145 * {@code CATEGORY_STANDARD} indicates the complication is a normal component. Rules and 146 * settings, such as hiding all complications, will apply to this complication. 147 */ 148 int CATEGORY_STANDARD = 1 << 0; 149 /** 150 * {@code CATEGORY_SYSTEM} indicates complications driven by SystemUI. Usually, these are 151 * core components that are not user controlled. These can potentially deviate from given 152 * rule sets that would normally apply to {@code CATEGORY_STANDARD}. 153 */ 154 int CATEGORY_SYSTEM = 1 << 1; 155 156 /** 157 * The type of dream complications which can be provided by a {@link Complication}. 158 */ 159 @IntDef(prefix = {"COMPLICATION_TYPE_"}, flag = true, value = { 160 COMPLICATION_TYPE_NONE, 161 COMPLICATION_TYPE_TIME, 162 COMPLICATION_TYPE_DATE, 163 COMPLICATION_TYPE_WEATHER, 164 COMPLICATION_TYPE_AIR_QUALITY, 165 COMPLICATION_TYPE_CAST_INFO, 166 COMPLICATION_TYPE_HOME_CONTROLS, 167 COMPLICATION_TYPE_SMARTSPACE, 168 COMPLICATION_TYPE_MEDIA_ENTRY 169 }) 170 @Retention(RetentionPolicy.SOURCE) 171 @interface ComplicationType {} 172 173 int COMPLICATION_TYPE_NONE = 0; 174 int COMPLICATION_TYPE_TIME = 1; 175 int COMPLICATION_TYPE_DATE = 1 << 1; 176 int COMPLICATION_TYPE_WEATHER = 1 << 2; 177 int COMPLICATION_TYPE_AIR_QUALITY = 1 << 3; 178 int COMPLICATION_TYPE_CAST_INFO = 1 << 4; 179 int COMPLICATION_TYPE_HOME_CONTROLS = 1 << 5; 180 int COMPLICATION_TYPE_SMARTSPACE = 1 << 6; 181 int COMPLICATION_TYPE_MEDIA_ENTRY = 1 << 7; 182 183 /** 184 * The {@link Host} interface specifies a way a {@link Complication} to communicate with its 185 * parent entity for information and actions. 186 */ 187 interface Host { 188 /** 189 * Called to signal a {@link Complication} has requested to exit the dream. 190 */ requestExitDream()191 void requestExitDream(); 192 } 193 194 /** 195 * The implementation of this interface is in charge of managing the visible state of 196 * the shown complication. 197 */ 198 interface VisibilityController { 199 /** 200 * Called to set the visibility of all shown and future complications. Changes in visibility 201 * will always be animated. 202 * @param visibility The desired future visibility. 203 */ setVisibility(@iew.Visibility int visibility)204 void setVisibility(@View.Visibility int visibility); 205 } 206 207 /** 208 * Returned through {@link Complication#createView(ComplicationViewModel)}, {@link ViewHolder} 209 * is a container for a single {@link Complication} instance. The {@link Host} guarantees that 210 * the {@link ViewHolder} will be retained for the lifetime of the {@link Complication} 211 * instance's user. The view is responsible for providing the view that represents the 212 * {@link Complication}. This object is the proper place to store any related entities, such as 213 * a {@link com.android.systemui.util.ViewController} for the view. 214 */ 215 interface ViewHolder { 216 /** 217 * Returns the {@link View} associated with the {@link ViewHolder}. This {@link View} should 218 * be stable and generated once. 219 * @return 220 */ getView()221 View getView(); 222 223 /** 224 * Returns the {@link Category} associated with the {@link Complication}. {@link Category} 225 * is a grouping which helps define the relationship of the {@link Complication} to 226 * System UI and the rest of the system. It is used for presentation and other decisions. 227 */ 228 @Complication.Category getCategory()229 default int getCategory() { 230 return Complication.CATEGORY_STANDARD; 231 } 232 233 /** 234 * Returns the {@link ComplicationLayoutParams} associated with this complication. The 235 * values expressed here are treated as preference rather than requirement. The hosting 236 * entity is free to modify/interpret the parameters as deemed fit. 237 */ getLayoutParams()238 ComplicationLayoutParams getLayoutParams(); 239 } 240 241 /** 242 * Generates a {@link ViewHolder} for the {@link Complication}. This captures both the view and 243 * control logic for a single instance of the complication. The {@link Complication} may be 244 * asked at any time to generate another view. 245 * @param model The {@link ComplicationViewModel} associated with this particular 246 * {@link Complication} instance. 247 * @return a {@link ViewHolder} for this {@link Complication} instance. 248 */ createView(ComplicationViewModel model)249 ViewHolder createView(ComplicationViewModel model); 250 251 /** 252 * Returns the types that must be present in order for this complication to participate on 253 * the dream overlay. By default, this method returns 254 * {@code Complication.COMPLICATION_TYPE_NONE} to indicate no types are required. 255 * @return 256 */ 257 @Complication.ComplicationType getRequiredTypeAvailability()258 default int getRequiredTypeAvailability() { 259 return Complication.COMPLICATION_TYPE_NONE; 260 } 261 } 262