diff options
3 files changed, 189 insertions, 2 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 67d4a2e25051..31e792cae39b 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -80,10 +80,12 @@ import com.android.systemui.decor.OverlayWindow; import com.android.systemui.decor.PrivacyDotDecorProviderFactory; import com.android.systemui.decor.RoundedCornerDecorProviderFactory; import com.android.systemui.decor.RoundedCornerResDelegateImpl; +import com.android.systemui.decor.ScreenDecorCommand; import com.android.systemui.log.ScreenDecorationsLogger; import com.android.systemui.qs.SettingObserver; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.commandline.CommandRegistry; import com.android.systemui.statusbar.events.PrivacyDotViewController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.ThreadFactory; @@ -131,6 +133,7 @@ public class ScreenDecorations implements CoreStartable, Dumpable { protected boolean mIsRegistered; private final Context mContext; private final Executor mMainExecutor; + private final CommandRegistry mCommandRegistry; private final SecureSettings mSecureSettings; @VisibleForTesting DisplayTracker.Callback mDisplayListener; @@ -315,6 +318,7 @@ public class ScreenDecorations implements CoreStartable, Dumpable { public ScreenDecorations(Context context, @Main Executor mainExecutor, SecureSettings secureSettings, + CommandRegistry commandRegistry, UserTracker userTracker, DisplayTracker displayTracker, PrivacyDotViewController dotViewController, @@ -326,6 +330,7 @@ public class ScreenDecorations implements CoreStartable, Dumpable { mContext = context; mMainExecutor = mainExecutor; mSecureSettings = secureSettings; + mCommandRegistry = commandRegistry; mUserTracker = userTracker; mDisplayTracker = displayTracker; mDotViewController = dotViewController; @@ -350,6 +355,10 @@ public class ScreenDecorations implements CoreStartable, Dumpable { } }; + private final ScreenDecorCommand.Callback mScreenDecorCommandCallback = (cmd, pw) -> { + android.util.Log.d(TAG, cmd.toString()); + }; + @Override public void start() { if (DEBUG_DISABLE_SCREEN_DECORATIONS) { @@ -361,6 +370,8 @@ public class ScreenDecorations implements CoreStartable, Dumpable { mExecutor.execute(this::startOnScreenDecorationsThread); mDotViewController.setUiExecutor(mExecutor); mAuthController.addCallback(mAuthControllerCallback); + mCommandRegistry.registerCommand(ScreenDecorCommand.SCREEN_DECOR_CMD_NAME, + () -> new ScreenDecorCommand(mScreenDecorCommandCallback)); } /** diff --git a/packages/SystemUI/src/com/android/systemui/decor/ScreenDecorCommand.kt b/packages/SystemUI/src/com/android/systemui/decor/ScreenDecorCommand.kt new file mode 100644 index 000000000000..fa1d898de850 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/decor/ScreenDecorCommand.kt @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.decor + +import android.graphics.Color +import android.graphics.Path +import android.util.PathParser +import com.android.systemui.statusbar.commandline.ParseableCommand +import com.android.systemui.statusbar.commandline.Type +import com.android.systemui.statusbar.commandline.map +import java.io.PrintWriter + +/** Debug screen-decor command to be handled by the SystemUI command line interface */ +class ScreenDecorCommand( + private val callback: Callback, +) : ParseableCommand(SCREEN_DECOR_CMD_NAME) { + val debug: Boolean? by + param( + longName = "debug", + description = + "Enter or exits debug mode. Effectively makes the corners visible and allows " + + "for overriding the path data for the anti-aliasing corner paths and display " + + "cutout.", + valueParser = Type.Boolean, + ) + + val color: Int? by + param( + longName = "color", + shortName = "c", + description = + "Set a specific color for the debug assets. See Color#parseString() for " + + "accepted inputs.", + valueParser = Type.String.map { it.toColorIntOrNull() } + ) + + val roundedTop: RoundedCornerSubCommand? by subCommand(RoundedCornerSubCommand("rounded-top")) + + val roundedBottom: RoundedCornerSubCommand? by + subCommand(RoundedCornerSubCommand("rounded-bottom")) + + override fun execute(pw: PrintWriter) { + callback.onExecute(this, pw) + } + + override fun toString(): String { + return "ScreenDecorCommand(" + + "debug=$debug, " + + "color=$color, " + + "roundedTop=$roundedTop, " + + "roundedBottom=$roundedBottom)" + } + + /** For use in ScreenDecorations.java, define a Callback */ + interface Callback { + fun onExecute(cmd: ScreenDecorCommand, pw: PrintWriter) + } + + companion object { + const val SCREEN_DECOR_CMD_NAME = "screen-decor" + } +} + +/** + * Defines a subcommand suitable for `rounded-top` and `rounded-bottom`. They both have the same + * API. + */ +class RoundedCornerSubCommand(name: String) : ParseableCommand(name) { + val height by + param( + longName = "height", + description = "The height of a corner, in pixels.", + valueParser = Type.Int, + ) + .required() + + val width by + param( + longName = "width", + description = + "The width of the corner, in pixels. Likely should be equal to the height.", + valueParser = Type.Int, + ) + .required() + + val pathData by + param( + longName = "path-data", + shortName = "d", + description = + "PathParser-compatible path string to be rendered as the corner drawable. " + + "This path should be a closed arc oriented as the top-left corner " + + "of the device", + valueParser = Type.String.map { it.toPathOrNull() } + ) + .required() + + val viewportHeight: Float? by + param( + longName = "viewport-height", + description = + "The height of the viewport for the given path string. " + + "If null, the corner height will be used.", + valueParser = Type.Float, + ) + + val scaleY: Float + get() = viewportHeight?.let { height.toFloat() / it } ?: 1.0f + + val viewportWidth: Float? by + param( + longName = "viewport-width", + description = + "The width of the viewport for the given path string. " + + "If null, the corner width will be used.", + valueParser = Type.Float, + ) + + val scaleX: Float + get() = viewportWidth?.let { width.toFloat() / it } ?: 1.0f + + override fun execute(pw: PrintWriter) { + // Not needed for a subcommand + } + + override fun toString(): String { + return "RoundedCornerSubCommand(" + + "height=$height," + + " width=$width," + + " pathData='$pathData'," + + " viewportHeight=$viewportHeight," + + " viewportWidth=$viewportWidth)" + } + + fun toRoundedCornerDebugModel(): DebugRoundedCornerModel = + DebugRoundedCornerModel( + path = pathData, + width = width, + height = height, + scaleX = scaleX, + scaleY = scaleY, + ) +} + +fun String.toPathOrNull(): Path? = + try { + PathParser.createPathFromPathData(this) + } catch (e: Exception) { + null + } + +fun String.toColorIntOrNull(): Int? = + try { + Color.parseColor(this) + } catch (e: Exception) { + null + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index 79c87cfd1f3e..c1a6f28cdea6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -96,6 +96,7 @@ import com.android.systemui.log.ScreenDecorationsLogger; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.settings.FakeDisplayTracker; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.commandline.CommandRegistry; import com.android.systemui.statusbar.events.PrivacyDotViewController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeThreadFactory; @@ -139,6 +140,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { @Mock private Display mDisplay; @Mock + private CommandRegistry mCommandRegistry; + @Mock private UserTracker mUserTracker; @Mock private PrivacyDotViewController mDotViewController; @@ -232,7 +235,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")))); mScreenDecorations = spy(new ScreenDecorations(mContext, mExecutor, mSecureSettings, - mUserTracker, mDisplayTracker, mDotViewController, mThreadFactory, + mCommandRegistry, mUserTracker, mDisplayTracker, mDotViewController, + mThreadFactory, mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory, new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")), mAuthController) { @@ -1227,7 +1231,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders); when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(true); ScreenDecorations screenDecorations = new ScreenDecorations(mContext, mExecutor, - mSecureSettings, mUserTracker, mDisplayTracker, mDotViewController, + mSecureSettings, mCommandRegistry, mUserTracker, mDisplayTracker, + mDotViewController, mThreadFactory, mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory, new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")), mAuthController); screenDecorations.start(); |