1 /* 2 * Copyright (C) 2024 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 package com.android.internal.widget.remotecompose.core.operations; 17 18 import android.annotation.NonNull; 19 20 import com.android.internal.widget.remotecompose.core.Operation; 21 import com.android.internal.widget.remotecompose.core.Operations; 22 import com.android.internal.widget.remotecompose.core.RemoteComposeOperation; 23 import com.android.internal.widget.remotecompose.core.RemoteContext; 24 import com.android.internal.widget.remotecompose.core.WireBuffer; 25 import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; 26 import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; 27 import com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent; 28 29 import java.util.List; 30 31 /** 32 * Describe some basic information for a RemoteCompose document 33 * 34 * <p>It encodes the version of the document (following semantic versioning) as well as the 35 * dimensions of the document in pixels. 36 */ 37 public class RootContentBehavior extends Operation 38 implements RemoteComposeOperation, ScrollableComponent { 39 private static final int OP_CODE = Operations.ROOT_CONTENT_BEHAVIOR; 40 private static final String CLASS_NAME = "RootContentBehavior"; 41 int mScroll = NONE; 42 int mSizing = NONE; 43 44 int mAlignment = ALIGNMENT_CENTER; 45 46 int mMode = NONE; 47 48 protected static final String TAG = "RootContentBehavior"; 49 50 public static final int NONE = ScrollableComponent.SCROLL_NONE; 51 52 /////////////////////////////////////////////////////////////////////////////////////////////// 53 // Scrolling 54 /////////////////////////////////////////////////////////////////////////////////////////////// 55 public static final int SCROLL_HORIZONTAL = ScrollableComponent.SCROLL_HORIZONTAL; 56 public static final int SCROLL_VERTICAL = ScrollableComponent.SCROLL_VERTICAL; 57 58 /////////////////////////////////////////////////////////////////////////////////////////////// 59 // Sizing 60 /////////////////////////////////////////////////////////////////////////////////////////////// 61 public static final int SIZING_LAYOUT = 1; 62 public static final int SIZING_SCALE = 2; 63 64 /////////////////////////////////////////////////////////////////////////////////////////////// 65 // Sizing 66 /////////////////////////////////////////////////////////////////////////////////////////////// 67 public static final int ALIGNMENT_TOP = 1; 68 public static final int ALIGNMENT_VERTICAL_CENTER = 2; 69 public static final int ALIGNMENT_BOTTOM = 4; 70 public static final int ALIGNMENT_START = 16; 71 public static final int ALIGNMENT_HORIZONTAL_CENTER = 32; 72 public static final int ALIGNMENT_END = 64; 73 public static final int ALIGNMENT_CENTER = 74 ALIGNMENT_HORIZONTAL_CENTER + ALIGNMENT_VERTICAL_CENTER; 75 76 /////////////////////////////////////////////////////////////////////////////////////////////// 77 // Layout mode 78 /////////////////////////////////////////////////////////////////////////////////////////////// 79 public static final int LAYOUT_HORIZONTAL_MATCH_PARENT = 1; 80 public static final int LAYOUT_HORIZONTAL_WRAP_CONTENT = 2; 81 public static final int LAYOUT_HORIZONTAL_FIXED = 4; 82 public static final int LAYOUT_VERTICAL_MATCH_PARENT = 8; 83 public static final int LAYOUT_VERTICAL_WRAP_CONTENT = 16; 84 public static final int LAYOUT_VERTICAL_FIXED = 32; 85 public static final int LAYOUT_MATCH_PARENT = 86 LAYOUT_HORIZONTAL_MATCH_PARENT + LAYOUT_VERTICAL_MATCH_PARENT; 87 public static final int LAYOUT_WRAP_CONTENT = 88 LAYOUT_HORIZONTAL_WRAP_CONTENT + LAYOUT_VERTICAL_WRAP_CONTENT; 89 90 /////////////////////////////////////////////////////////////////////////////////////////////// 91 // Sizing mode 92 /////////////////////////////////////////////////////////////////////////////////////////////// 93 94 public static final int SCALE_INSIDE = 1; 95 public static final int SCALE_FILL_WIDTH = 2; 96 public static final int SCALE_FILL_HEIGHT = 3; 97 public static final int SCALE_FIT = 4; 98 public static final int SCALE_CROP = 5; 99 public static final int SCALE_FILL_BOUNDS = 6; 100 101 /** 102 * Sets the way the player handles the content 103 * 104 * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL) 105 * @param alignment set the alignment of the content (TOP|CENTER|BOTTOM|START|END) 106 * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE) 107 * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes the LAYOUT modes are: 108 * - LAYOUT_MATCH_PARENT - LAYOUT_WRAP_CONTENT or adding an horizontal mode and a vertical 109 * mode: - LAYOUT_HORIZONTAL_MATCH_PARENT - LAYOUT_HORIZONTAL_WRAP_CONTENT - 110 * LAYOUT_HORIZONTAL_FIXED - LAYOUT_VERTICAL_MATCH_PARENT - LAYOUT_VERTICAL_WRAP_CONTENT - 111 * LAYOUT_VERTICAL_FIXED The LAYOUT_*_FIXED modes will use the intrinsic document size 112 */ RootContentBehavior(int scroll, int alignment, int sizing, int mode)113 public RootContentBehavior(int scroll, int alignment, int sizing, int mode) { 114 switch (scroll) { 115 case NONE: 116 case SCROLL_HORIZONTAL: 117 case SCROLL_VERTICAL: 118 mScroll = scroll; 119 break; 120 default: 121 System.out.println(TAG + "incorrect scroll value " + scroll); 122 } 123 if (alignment == ALIGNMENT_CENTER) { 124 mAlignment = alignment; 125 } else { 126 int horizontalContentAlignment = alignment & 0xF0; 127 int verticalContentAlignment = alignment & 0xF; 128 boolean validHorizontalAlignment = 129 horizontalContentAlignment == ALIGNMENT_START 130 || horizontalContentAlignment == ALIGNMENT_HORIZONTAL_CENTER 131 || horizontalContentAlignment == ALIGNMENT_END; 132 boolean validVerticalAlignment = 133 verticalContentAlignment == ALIGNMENT_TOP 134 || verticalContentAlignment == ALIGNMENT_VERTICAL_CENTER 135 || verticalContentAlignment == ALIGNMENT_BOTTOM; 136 if (validHorizontalAlignment && validVerticalAlignment) { 137 mAlignment = alignment; 138 } else { 139 System.out.println( 140 TAG 141 + "incorrect alignment " 142 + " h: " 143 + horizontalContentAlignment 144 + " v: " 145 + verticalContentAlignment); 146 } 147 } 148 switch (sizing) { 149 case SIZING_LAYOUT: 150 System.out.println(TAG + "sizing_layout is not yet supported"); 151 break; 152 case SIZING_SCALE: 153 mSizing = sizing; 154 break; 155 default: 156 System.out.println(TAG + "incorrect sizing value " + sizing); 157 } 158 if (mSizing == SIZING_LAYOUT) { 159 if (mode != NONE) { 160 System.out.println(TAG + "mode for sizing layout is not yet supported"); 161 } 162 } else if (mSizing == SIZING_SCALE) { 163 switch (mode) { 164 case SCALE_INSIDE: 165 case SCALE_FIT: 166 case SCALE_FILL_WIDTH: 167 case SCALE_FILL_HEIGHT: 168 case SCALE_CROP: 169 case SCALE_FILL_BOUNDS: 170 mMode = mode; 171 break; 172 default: 173 System.out.println(TAG + "incorrect mode for scale sizing, mode: " + mode); 174 } 175 } 176 } 177 178 @Override write(@onNull WireBuffer buffer)179 public void write(@NonNull WireBuffer buffer) { 180 apply(buffer, mScroll, mAlignment, mSizing, mMode); 181 } 182 183 @NonNull 184 @Override toString()185 public String toString() { 186 return "ROOT_CONTENT_BEHAVIOR scroll: " 187 + mScroll 188 + " sizing: " 189 + mSizing 190 + " mode: " 191 + mMode; 192 } 193 194 @Override apply(@onNull RemoteContext context)195 public void apply(@NonNull RemoteContext context) { 196 context.setRootContentBehavior(mScroll, mAlignment, mSizing, mMode); 197 } 198 199 @NonNull 200 @Override deepToString(@onNull String indent)201 public String deepToString(@NonNull String indent) { 202 return toString(); 203 } 204 205 /** 206 * The name of the class 207 * 208 * @return the name 209 */ 210 @NonNull name()211 public static String name() { 212 return CLASS_NAME; 213 } 214 215 /** 216 * The OP_CODE for this command 217 * 218 * @return the opcode 219 */ id()220 public static int id() { 221 return OP_CODE; 222 } 223 224 /** 225 * Write the operation on the buffer 226 * 227 * @param buffer 228 * @param scroll 229 * @param alignment 230 * @param sizing 231 * @param mode 232 */ apply( @onNull WireBuffer buffer, int scroll, int alignment, int sizing, int mode)233 public static void apply( 234 @NonNull WireBuffer buffer, int scroll, int alignment, int sizing, int mode) { 235 buffer.start(OP_CODE); 236 buffer.writeInt(scroll); 237 buffer.writeInt(alignment); 238 buffer.writeInt(sizing); 239 buffer.writeInt(mode); 240 } 241 242 /** 243 * Read this operation and add it to the list of operations 244 * 245 * @param buffer the buffer to read 246 * @param operations the list of operations that will be added to 247 */ read(@onNull WireBuffer buffer, @NonNull List<Operation> operations)248 public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { 249 int scroll = buffer.readInt(); 250 int alignment = buffer.readInt(); 251 int sizing = buffer.readInt(); 252 int mode = buffer.readInt(); 253 RootContentBehavior rootContentBehavior = 254 new RootContentBehavior(scroll, alignment, sizing, mode); 255 operations.add(rootContentBehavior); 256 } 257 258 /** 259 * Populate the documentation with a description of this operation 260 * 261 * @param doc to append the description to. 262 */ documentation(@onNull DocumentationBuilder doc)263 public static void documentation(@NonNull DocumentationBuilder doc) { 264 doc.operation("Protocol Operations", OP_CODE, CLASS_NAME) 265 .description("Describes the behaviour of the root") 266 .field(DocumentedOperation.INT, "scroll", "scroll") 267 .possibleValues("SCROLL_HORIZONTAL", SCROLL_HORIZONTAL) 268 .possibleValues("SCROLL_VERTICAL", SCROLL_VERTICAL) 269 .field(DocumentedOperation.INT, "alignment", "alignment") 270 .possibleValues("ALIGNMENT_TOP", ALIGNMENT_TOP) 271 .possibleValues("ALIGNMENT_VERTICAL_CENTER", ALIGNMENT_VERTICAL_CENTER) 272 .possibleValues("ALIGNMENT_BOTTOM", ALIGNMENT_BOTTOM) 273 .possibleValues("ALIGNMENT_START", ALIGNMENT_START) 274 .possibleValues("ALIGNMENT_START", ALIGNMENT_START) 275 .possibleValues("ALIGNMENT_END", ALIGNMENT_END) 276 .field(DocumentedOperation.INT, "sizing", "sizing") 277 .possibleValues("SCALE_INSIDE", SCALE_INSIDE) 278 .possibleValues("SCALE_FIT", SCALE_FIT) 279 .possibleValues("SCALE_FILL_WIDTH", SCALE_FILL_WIDTH) 280 .possibleValues("SCALE_FILL_HEIGHT", SCALE_FILL_HEIGHT) 281 .possibleValues("SCALE_CROP", SCALE_CROP) 282 .possibleValues("SCALE_FILL_BOUNDS", SCALE_FILL_BOUNDS) 283 .field(DocumentedOperation.INT, "mode", "mode") 284 .possibleValues("LAYOUT_HORIZONTAL_MATCH_PARENT", LAYOUT_HORIZONTAL_MATCH_PARENT) 285 .possibleValues("LAYOUT_HORIZONTAL_WRAP_CONTENT", LAYOUT_HORIZONTAL_WRAP_CONTENT) 286 .possibleValues("LAYOUT_HORIZONTAL_FIXED", LAYOUT_HORIZONTAL_FIXED) 287 .possibleValues("LAYOUT_VERTICAL_MATCH_PARENT", LAYOUT_VERTICAL_MATCH_PARENT) 288 .possibleValues("LAYOUT_VERTICAL_WRAP_CONTENT", LAYOUT_VERTICAL_WRAP_CONTENT) 289 .possibleValues("LAYOUT_VERTICAL_FIXED", LAYOUT_VERTICAL_FIXED) 290 .possibleValues("LAYOUT_MATCH_PARENT", LAYOUT_MATCH_PARENT) 291 .possibleValues("LAYOUT_WRAP_CONTENT", LAYOUT_WRAP_CONTENT); 292 } 293 294 @Override isInterestingForSemantics()295 public boolean isInterestingForSemantics() { 296 return mScroll != SCROLL_NONE; 297 } 298 299 @Override supportsScrollByOffset()300 public boolean supportsScrollByOffset() { 301 return mScroll != SCROLL_NONE; 302 } 303 304 @Override scrollByOffset(RemoteContext context, int offset)305 public int scrollByOffset(RemoteContext context, int offset) { 306 // TODO implement scroll handling 307 return offset; 308 } 309 310 @Override scrollDirection()311 public int scrollDirection() { 312 return mScroll; 313 } 314 } 315