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

Commit 71abd123 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[Media TTT] Add the aidl interface for the sender and a service that implements it."

parents f1e7be07 38aa601a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -855,6 +855,12 @@
            android:singleUser="true"
            android:permission="android.permission.BIND_DREAM_SERVICE" />

        <!-- Service for external clients to do media transfer -->
        <!-- TODO(b/203800643): Export and guard with a permission. -->
        <service
            android:name=".media.taptotransfer.sender.MediaTttSenderService"
           />

        <receiver
            android:name=".tuner.TunerService$ClearReceiver"
            android:exported="false">
+2 −2
Original line number Diff line number Diff line
@@ -2152,8 +2152,8 @@
    <!--- ****** Media tap-to-transfer ****** -->
    <!-- Text for a button to undo the media transfer. [CHAR LIMIT=20] -->
    <string name="media_transfer_undo">Undo</string>
    <!-- Text to ask the user to move their device closer to a different device (deviceName) in order to play music on the different device. [CHAR LIMIT=75] -->
    <string name="media_move_closer_to_transfer">Move closer to play on <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g></string>
    <!-- Text to ask the user to move their device closer to a different device (deviceName) in order to play media on the different device. [CHAR LIMIT=75] -->
    <string name="media_move_closer_to_start_cast">Move closer to play on <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g></string>
    <!-- Text informing the user that their media is now playing on a different device (deviceName). [CHAR LIMIT=50] -->
    <string name="media_transfer_playing">Playing on <xliff:g id="deviceName" example="My Tablet">%1$s</xliff:g></string>

+45 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.shared.mediattt;

import android.media.MediaRoute2Info;

/**
 * A callback interface that can be invoked to trigger media transfer events on System UI.
 *
 * This interface is for the *sender* device, which is the device currently playing media. This
 * sender device can transfer the media to a different device, called the receiver.
 *
 * System UI will implement this interface and other services will invoke it.
 */
interface IDeviceSenderCallback {
    /**
     * Invoke to notify System UI that this device (the sender) is close to a receiver device, so
     * the user can potentially *start* a cast to the receiver device if the user moves their device
     * a bit closer.
     *
     * Important notes:
     *   - When this callback triggers, the device is close enough to inform the user that
     *     transferring is an option, but the device is *not* close enough to actually initiate a
     *     transfer yet.
     *   - This callback is for *starting* a cast. It should be used when this device is currently
     *     playing media locally and the media should be transferred to be played on the receiver
     *     device instead.
     */
     // TODO(b/203800643): Add the otherDeviceInfo parameter.
    oneway void closeToReceiverToStartCast(in MediaRoute2Info mediaInfo);
}
+11 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.media.dagger;

import android.app.Service;
import android.content.Context;
import android.view.WindowManager;

@@ -30,6 +31,7 @@ import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.MediaTttFlags;
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderService;
import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.util.concurrency.DelayableExecutor;

@@ -38,8 +40,11 @@ import java.util.concurrent.Executor;

import javax.inject.Named;

import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.ClassKey;
import dagger.multibindings.IntoMap;

/** Dagger module for the media package. */
@Module
@@ -128,4 +133,10 @@ public interface MediaModule {
                        mediaTttChipControllerReceiver,
                        mainExecutor));
    }

    /** Inject into MediaTttSenderService. */
    @Binds
    @IntoMap
    @ClassKey(MediaTttSenderService.class)
    Service bindMediaTttSenderService(MediaTttSenderService service);
}
+70 −11
Original line number Diff line number Diff line
@@ -16,9 +16,14 @@

package com.android.systemui.media.taptotransfer

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.graphics.Color
import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
import android.os.IBinder
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.systemui.R
@@ -27,9 +32,11 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender
import com.android.systemui.media.taptotransfer.sender.MoveCloserToTransfer
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderService
import com.android.systemui.media.taptotransfer.sender.MoveCloserToStartCast
import com.android.systemui.media.taptotransfer.sender.TransferInitiated
import com.android.systemui.media.taptotransfer.sender.TransferSucceeded
import com.android.systemui.shared.mediattt.IDeviceSenderCallback
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -44,11 +51,14 @@ import javax.inject.Inject
@SysUISingleton
class MediaTttCommandLineHelper @Inject constructor(
    commandRegistry: CommandRegistry,
    context: Context,
    private val context: Context,
    private val mediaTttChipControllerSender: MediaTttChipControllerSender,
    private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver,
    @Main private val mainExecutor: DelayableExecutor,
) {
    private var senderCallback: IDeviceSenderCallback? = null
    private val senderServiceConnection = SenderServiceConnection()

    private val appIconDrawable =
        Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also {
            it.setTint(Color.YELLOW)
@@ -68,14 +78,19 @@ class MediaTttCommandLineHelper @Inject constructor(
    inner class AddChipCommandSender : Command {
        override fun execute(pw: PrintWriter, args: List<String>) {
            val otherDeviceName = args[0]
            val mediaInfo = MediaRoute2Info.Builder("id", "Test Name")
                .addFeature("feature")
                .build()

            when (args[1]) {
                MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME -> {
                    mediaTttChipControllerSender.displayChip(
                        MoveCloserToTransfer(
                            appIconDrawable, APP_ICON_CONTENT_DESCRIPTION, otherDeviceName
                        )
                    )
                MOVE_CLOSER_TO_START_CAST_COMMAND_NAME -> {
                    runOnService { senderCallback ->
                        senderCallback.closeToReceiverToStartCast(mediaInfo)
                    }
                }

                // TODO(b/203800643): Migrate other commands to invoke the service instead of the
                //   controller.
                TRANSFER_INITIATED_COMMAND_NAME -> {
                    val futureTask = FutureTask { fakeUndoRunnable }
                    mediaTttChipControllerSender.displayChip(
@@ -101,7 +116,7 @@ class MediaTttCommandLineHelper @Inject constructor(
                }
                else -> {
                    pw.println("Chip type must be one of " +
                            "$MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME, " +
                            "$MOVE_CLOSER_TO_START_CAST_COMMAND_NAME, " +
                            "$TRANSFER_INITIATED_COMMAND_NAME, " +
                            TRANSFER_SUCCEEDED_COMMAND_NAME
                    )
@@ -114,19 +129,40 @@ class MediaTttCommandLineHelper @Inject constructor(
                    "$ADD_CHIP_COMMAND_SENDER_TAG <deviceName> <chipStatus>"
            )
        }

        private fun runOnService(command: SenderCallbackCommand) {
            val currentServiceCallback = senderCallback
            if (currentServiceCallback != null) {
                command.run(currentServiceCallback)
            } else {
                bindService(command)
            }
        }

        private fun bindService(command: SenderCallbackCommand) {
            senderServiceConnection.pendingCommand = command
            val binding = context.bindService(
                Intent(context, MediaTttSenderService::class.java),
                senderServiceConnection,
                Context.BIND_AUTO_CREATE
            )
            Log.i(TAG, "Starting service binding? $binding")
        }
    }

    /** A command to REMOVE the media ttt chip on the SENDER device. */
    inner class RemoveChipCommandSender : Command {
        override fun execute(pw: PrintWriter, args: List<String>) {
            mediaTttChipControllerSender.removeChip()
            if (senderCallback != null) {
                context.unbindService(senderServiceConnection)
            }
        }
        override fun help(pw: PrintWriter) {
            pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_SENDER_TAG")
        }
    }


    /** A command to DISPLAY the media ttt chip on the RECEIVER device. */
    inner class AddChipCommandReceiver : Command {
        override fun execute(pw: PrintWriter, args: List<String>) {
@@ -149,6 +185,29 @@ class MediaTttCommandLineHelper @Inject constructor(
        }
    }

    /** A service connection for [IDeviceSenderCallback]. */
    private inner class SenderServiceConnection : ServiceConnection {
        // A command that should be run when the service gets connected.
        var pendingCommand: SenderCallbackCommand? = null

        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            val newCallback = IDeviceSenderCallback.Stub.asInterface(service)
            senderCallback = newCallback
            pendingCommand?.run(newCallback)
            pendingCommand = null
        }

        override fun onServiceDisconnected(className: ComponentName) {
            senderCallback = null
        }
    }

    /** An interface defining a command that should be run on the sender callback. */
    private fun interface SenderCallbackCommand {
        /** Runs the command on the provided [senderCallback]. */
        fun run(senderCallback: IDeviceSenderCallback)
    }

    private val fakeUndoRunnable = Runnable {
        Log.i(TAG, "Undo runnable triggered")
    }
@@ -163,7 +222,7 @@ const val ADD_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-add-receiver"
@VisibleForTesting
const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver"
@VisibleForTesting
val MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME = MoveCloserToTransfer::class.simpleName!!
val MOVE_CLOSER_TO_START_CAST_COMMAND_NAME = MoveCloserToStartCast::class.simpleName!!
@VisibleForTesting
val TRANSFER_INITIATED_COMMAND_NAME = TransferInitiated::class.simpleName!!
@VisibleForTesting
Loading