• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.decor
18 
19 import android.graphics.Color
20 import android.graphics.Path
21 import android.util.PathParser
22 import com.android.systemui.statusbar.commandline.ParseableCommand
23 import com.android.systemui.statusbar.commandline.Type
24 import com.android.systemui.statusbar.commandline.map
25 import java.io.PrintWriter
26 
27 /** Debug screen-decor command to be handled by the SystemUI command line interface */
28 class ScreenDecorCommand(
29     private val callback: Callback,
30 ) : ParseableCommand(SCREEN_DECOR_CMD_NAME) {
31     val debug: Boolean? by
32         param(
33             longName = "debug",
34             description =
35                 "Enter or exits debug mode. Effectively makes the corners visible and allows " +
36                     "for overriding the path data for the anti-aliasing corner paths and display " +
37                     "cutout.",
38             valueParser = Type.Boolean,
39         )
40 
41     val color: Int? by
42         param(
43             longName = "color",
44             shortName = "c",
45             description =
46                 "Set a specific color for the debug assets. See Color#parseString() for " +
47                     "accepted inputs.",
<lambda>null48             valueParser = Type.String.map { it.toColorIntOrNull() }
49         )
50 
51     val roundedTop: RoundedCornerSubCommand? by subCommand(RoundedCornerSubCommand("rounded-top"))
52 
53     val roundedBottom: RoundedCornerSubCommand? by
54         subCommand(RoundedCornerSubCommand("rounded-bottom"))
55 
56     val faceAuthScreen: Int? by
57         param(
58             longName = "faceAuthScreen",
59             description =
60                 "Specify a screen to show face auth animation. 0:outer(default screen), 1:inner",
61             valueParser = Type.Int,
62         )
63 
executenull64     override fun execute(pw: PrintWriter) {
65         callback.onExecute(this, pw)
66     }
67 
toStringnull68     override fun toString(): String {
69         return "ScreenDecorCommand(" +
70             "debug=$debug, " +
71             "color=$color, " +
72             "faceAuthScreen=$faceAuthScreen, " +
73             "roundedTop=$roundedTop, " +
74             "roundedBottom=$roundedBottom)"
75     }
76 
77     /** For use in ScreenDecorations.java, define a Callback */
78     interface Callback {
onExecutenull79         fun onExecute(cmd: ScreenDecorCommand, pw: PrintWriter)
80     }
81 
82     companion object {
83         const val SCREEN_DECOR_CMD_NAME = "screen-decor"
84     }
85 }
86 
87 /**
88  * Defines a subcommand suitable for `rounded-top` and `rounded-bottom`. They both have the same
89  * API.
90  */
91 class RoundedCornerSubCommand(name: String) : ParseableCommand(name) {
92     val height by
93         param(
94                 longName = "height",
95                 description = "The height of a corner, in pixels.",
96                 valueParser = Type.Int,
97             )
98             .required()
99 
100     val width by
101         param(
102                 longName = "width",
103                 description =
104                     "The width of the corner, in pixels. Likely should be equal to the height.",
105                 valueParser = Type.Int,
106             )
107             .required()
108 
109     val pathData by
110         param(
111                 longName = "path-data",
112                 shortName = "d",
113                 description =
114                     "PathParser-compatible path string to be rendered as the corner drawable. " +
115                         "This path should be a closed arc oriented as the top-left corner " +
116                         "of the device",
<lambda>null117                 valueParser = Type.String.map { it.toPathOrNull() }
118             )
119             .required()
120 
121     val viewportHeight: Float? by
122         param(
123             longName = "viewport-height",
124             description =
125                 "The height of the viewport for the given path string. " +
126                     "If null, the corner height will be used.",
127             valueParser = Type.Float,
128         )
129 
130     val scaleY: Float
<lambda>null131         get() = viewportHeight?.let { height.toFloat() / it } ?: 1.0f
132 
133     val viewportWidth: Float? by
134         param(
135             longName = "viewport-width",
136             description =
137                 "The width of the viewport for the given path string. " +
138                     "If null, the corner width will be used.",
139             valueParser = Type.Float,
140         )
141 
142     val scaleX: Float
<lambda>null143         get() = viewportWidth?.let { width.toFloat() / it } ?: 1.0f
144 
executenull145     override fun execute(pw: PrintWriter) {
146         // Not needed for a subcommand
147     }
148 
toStringnull149     override fun toString(): String {
150         return "RoundedCornerSubCommand(" +
151             "height=$height," +
152             " width=$width," +
153             " pathData='$pathData'," +
154             " viewportHeight=$viewportHeight," +
155             " viewportWidth=$viewportWidth)"
156     }
157 
toRoundedCornerDebugModelnull158     fun toRoundedCornerDebugModel(): DebugRoundedCornerModel =
159         DebugRoundedCornerModel(
160             path = pathData,
161             width = width,
162             height = height,
163             scaleX = scaleX,
164             scaleY = scaleY,
165         )
166 }
167 
168 fun String.toPathOrNull(): Path? =
169     try {
170         PathParser.createPathFromPathData(this)
171     } catch (e: Exception) {
172         null
173     }
174 
toColorIntOrNullnull175 fun String.toColorIntOrNull(): Int? =
176     try {
177         Color.parseColor(this)
178     } catch (e: Exception) {
179         null
180     }
181