Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 733f7fb1 authored by Caitlin Cassidy's avatar Caitlin Cassidy
Browse files

[Media TTT] Refactor the command line interface into its own class and

use sealed classes for the chip states.

The sealed class doesn't do anything in this CL, but it will become
useful in future CLs.

Sample command: adb shell cmd statusbar media-ttt-chip-add Tablet TransferInitiated

Bug: 203800327
Test: MediaTttCommandLineHelperTest, MediaTttChipControllerTest
Test: Re-tested adb commands and they still trigger the correct UIs
Change-Id: Iffd53c5648dac0307d282158122365613fb7b653
parent 5913ddb2
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.media.taptotransfer.MediaTttChipController;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.people.PeopleProvider;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
@@ -133,6 +134,7 @@ public interface SysUIComponent {
        getNaturalRotationUnfoldProgressProvider().ifPresent(o -> o.init());
        // No init method needed, just needs to be gotten so that it's created.
        getMediaTttChipController();
        getMediaTttCommandLineHelper();
    }

    /**
@@ -182,6 +184,9 @@ public interface SysUIComponent {
    /** */
    Optional<MediaTttChipController> getMediaTttChipController();

    /** */
    Optional<MediaTttCommandLineHelper> getMediaTttCommandLineHelper();

    /**
     * Member injection into the supplied argument.
     */
+15 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.media.MediaHostStatesManager;
import com.android.systemui.media.taptotransfer.MediaTttChipController;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.MediaTttFlags;
import com.android.systemui.statusbar.commandline.CommandRegistry;

@@ -78,11 +79,23 @@ public interface MediaModule {
    static Optional<MediaTttChipController> providesMediaTttChipController(
            MediaTttFlags mediaTttFlags,
            Context context,
            CommandRegistry commandRegistry,
            WindowManager windowManager) {
        if (!mediaTttFlags.isMediaTttEnabled()) {
            return Optional.empty();
        }
        return Optional.of(new MediaTttChipController(commandRegistry, context, windowManager));
        return Optional.of(new MediaTttChipController(context, windowManager));
    }

    /** */
    @Provides
    @SysUISingleton
    static Optional<MediaTttCommandLineHelper> providesMediaTttCommandLineHelper(
            MediaTttFlags mediaTttFlags,
            CommandRegistry commandRegistry,
            MediaTttChipController mediaTttChipController) {
        if (!mediaTttFlags.isMediaTttEnabled()) {
            return Optional.empty();
        }
        return Optional.of(new MediaTttCommandLineHelper(commandRegistry, mediaTttChipController));
    }
}
+7 −59
Original line number Diff line number Diff line
@@ -24,13 +24,8 @@ import android.view.View
import android.view.WindowManager
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import java.io.PrintWriter
import javax.inject.Inject

/**
@@ -41,14 +36,9 @@ import javax.inject.Inject
 */
@SysUISingleton
class MediaTttChipController @Inject constructor(
    commandRegistry: CommandRegistry,
    private val context: Context,
    private val windowManager: WindowManager,
) {
    init {
        commandRegistry.registerCommand(ADD_CHIP_COMMAND_TAG) { AddChipCommand() }
        commandRegistry.registerCommand(REMOVE_CHIP_COMMAND_TAG) { RemoveChipCommand() }
    }

    private val windowLayoutParams = WindowManager.LayoutParams().apply {
        width = WindowManager.LayoutParams.WRAP_CONTENT
@@ -65,7 +55,8 @@ class MediaTttChipController @Inject constructor(
    /** The chip view currently being displayed. Null if the chip is not being displayed. */
    private var chipView: LinearLayout? = null

    private fun displayChip(chipType: ChipType, otherDeviceName: String) {
    /** Displays the chip view for the given state. */
    fun displayChip(chipState: MediaTttChipState) {
        val oldChipView = chipView
        if (chipView == null) {
            chipView = LayoutInflater
@@ -76,16 +67,16 @@ class MediaTttChipController @Inject constructor(

        // Text
        currentChipView.requireViewById<TextView>(R.id.text).apply {
            text = context.getString(chipType.chipText, otherDeviceName)
            text = context.getString(chipState.chipText, chipState.otherDeviceName)
        }

        // Loading
        val showLoading = chipType == ChipType.TRANSFER_INITIATED
        val showLoading = chipState is TransferInitiated
        currentChipView.requireViewById<View>(R.id.loading).visibility =
            if (showLoading) { View.VISIBLE } else { View.GONE }

        // Undo
        val showUndo = chipType == ChipType.TRANSFER_SUCCEEDED
        val showUndo = chipState is TransferSucceeded
        currentChipView.requireViewById<View>(R.id.undo).visibility =
            if (showUndo) { View.VISIBLE } else { View.GONE }

@@ -94,53 +85,10 @@ class MediaTttChipController @Inject constructor(
        }
    }

    private fun removeChip() {
    /** Hides the chip. */
    fun removeChip() {
        if (chipView == null) { return }
        windowManager.removeView(chipView)
        chipView = null
    }

    @VisibleForTesting
    enum class ChipType(
        @StringRes internal val chipText: Int
    ) {
        MOVE_CLOSER_TO_TRANSFER(R.string.media_move_closer_to_transfer),
        TRANSFER_INITIATED(R.string.media_transfer_playing),
        TRANSFER_SUCCEEDED(R.string.media_transfer_playing),
    }

    inner class AddChipCommand : Command {
        override fun execute(pw: PrintWriter, args: List<String>) {
            val chipTypeArg = args[1]
            ChipType.values().forEach {
                if (it.name == chipTypeArg) {
                    displayChip(it, otherDeviceName = args[0])
                    return
                }
            }

            pw.println("Chip type must be one of " +
                    ChipType.values().map { it.name }.reduce { acc, s -> "$acc, $s" })
        }

        override fun help(pw: PrintWriter) {
            pw.println(
                "Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_TAG <deviceName> <chipType>"
            )
        }
    }

    inner class RemoveChipCommand : Command {
        override fun execute(pw: PrintWriter, args: List<String>) = removeChip()
        override fun help(pw: PrintWriter) {
            pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_TAG")
        }
    }

    companion object {
        @VisibleForTesting
        const val ADD_CHIP_COMMAND_TAG = "media-ttt-chip-add"
        @VisibleForTesting
        const val REMOVE_CHIP_COMMAND_TAG = "media-ttt-chip-remove"
    }
}
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.media.taptotransfer

import androidx.annotation.StringRes
import com.android.systemui.R

/**
 * A class that stores all the information necessary to display the media tap-to-transfer chip in
 * certain states.
 *
 * This is a sealed class where each subclass represents a specific chip state. Each subclass can
 * contain additional information that is necessary for only that state.
 */
sealed class MediaTttChipState(
    /** A string resource for the text that the chip should display. */
    @StringRes internal val chipText: Int,
    /** The name of the other device involved in the transfer. */
    internal val otherDeviceName: String
)

/**
 * A state representing that the two devices are close but not close enough to initiate a transfer.
 * The chip will instruct the user to move closer in order to initiate the transfer.
 */
class MoveCloserToTransfer(
    otherDeviceName: String
) : MediaTttChipState(R.string.media_move_closer_to_transfer, otherDeviceName)

/**
 * A state representing that a transfer has been initiated (but not completed).
 */
class TransferInitiated(
    otherDeviceName: String
) : MediaTttChipState(R.string.media_transfer_playing, otherDeviceName)

/**
 * A state representing that a transfer has been successfully completed.
 */
class TransferSucceeded(
    otherDeviceName: String
) : MediaTttChipState(R.string.media_transfer_playing, otherDeviceName)
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.media.taptotransfer

import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import java.io.PrintWriter
import javax.inject.Inject

/**
 * A helper class to test the media tap-to-transfer chip via the command line. See inner classes for
 * command usages.
 */
@SysUISingleton
class MediaTttCommandLineHelper @Inject constructor(
    commandRegistry: CommandRegistry,
    private val mediaTttChipController: MediaTttChipController
) {
    init {
        commandRegistry.registerCommand(ADD_CHIP_COMMAND_TAG) { AddChipCommand() }
        commandRegistry.registerCommand(REMOVE_CHIP_COMMAND_TAG) { RemoveChipCommand() }
    }

    inner class AddChipCommand : Command {
        override fun execute(pw: PrintWriter, args: List<String>) {
            val otherDeviceName = args[0]
            when (args[1]) {
                MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME -> {
                    mediaTttChipController.displayChip(MoveCloserToTransfer(otherDeviceName))
                }
                TRANSFER_INITIATED_COMMAND_NAME -> {
                    mediaTttChipController.displayChip(TransferInitiated(otherDeviceName))
                }
                TRANSFER_SUCCEEDED_COMMAND_NAME -> {
                    mediaTttChipController.displayChip(TransferSucceeded(otherDeviceName))
                }
                else -> {
                    pw.println("Chip type must be one of " +
                            "$MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME, " +
                            "$TRANSFER_INITIATED_COMMAND_NAME, " +
                            TRANSFER_SUCCEEDED_COMMAND_NAME
                    )
                }
            }
        }

        override fun help(pw: PrintWriter) {
            pw.println(
                "Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_TAG <deviceName> <chipStatus>"
            )
        }
    }

    inner class RemoveChipCommand : Command {
        override fun execute(pw: PrintWriter, args: List<String>) {
            mediaTttChipController.removeChip()
        }
        override fun help(pw: PrintWriter) {
            pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_TAG")
        }
    }
}

@VisibleForTesting
const val ADD_CHIP_COMMAND_TAG = "media-ttt-chip-add"
@VisibleForTesting
const val REMOVE_CHIP_COMMAND_TAG = "media-ttt-chip-remove"
@VisibleForTesting
val MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME = MoveCloserToTransfer::class.simpleName!!
@VisibleForTesting
val TRANSFER_INITIATED_COMMAND_NAME = TransferInitiated::class.simpleName!!
@VisibleForTesting
val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!!
Loading