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

Commit 802c97ba authored by Caitlin Cassidy's avatar Caitlin Cassidy
Browse files

[Media TTT] Define a chip controller and a way to issue commands via adb

to control the chip.

(To test, you will need to issue the command `adb shell am broadcast -a
com.android.systemui.action.SET_FLAG --ei id 900 --ez value 1` in order
to enable any media TTT code.)

Bug: 203800327
Test: `adb shell cmd statusbar media-ttt-chip-add` displays the chip
Test: `adb shell cmd statusbar media-ttt-chip-remove` removes the chip
Test: atest MediaTttChipControllerTest
Change-Id: Ib404206d0a0bdcbc8e2d1c9ddedbbe7c63dcd91e
parent d71cc858
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import com.android.systemui.InitController;
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.people.PeopleProvider;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
@@ -122,6 +123,8 @@ public interface SysUIComponent {
            c.getUnfoldTransitionWallpaperController().init();
        });
        getNaturalRotationUnfoldProgressProvider().ifPresent(o -> o.init());
        // No init method needed, just needs to be gotten so that it's created.
        getMediaTttChipController();
    }

    /**
@@ -168,6 +171,9 @@ public interface SysUIComponent {
     */
    Optional<NaturalRotationUnfoldProgressProvider> getNaturalRotationUnfoldProgressProvider();

    /** */
    Optional<MediaTttChipController> getMediaTttChipController();

    /**
     * Member injection into the supplied argument.
     */
+4 −0
Original line number Diff line number Diff line
@@ -114,6 +114,10 @@ public class Flags {
    public static final BooleanFlag MONET =
            new BooleanFlag(800, true, R.bool.flag_monet);

    /***************************************/
    // 900 - media
    public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, false);

    // Pay no attention to the reflection behind the curtain.
    // ========================== Curtain ==========================
    // |                                                           |
+22 −0
Original line number Diff line number Diff line
@@ -16,11 +16,19 @@

package com.android.systemui.media.dagger;

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

import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.media.MediaDataManager;
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.MediaTttFlags;
import com.android.systemui.statusbar.commandline.CommandRegistry;

import java.util.Optional;

import javax.inject.Named;

@@ -63,4 +71,18 @@ public interface MediaModule {
            MediaHostStatesManager statesManager) {
        return new MediaHost(stateHolder, hierarchyManager, dataManager, statesManager);
    }

    /** */
    @Provides
    @SysUISingleton
    static Optional<MediaTttChipController> providesMediaTttChipController(
            MediaTttFlags mediaTttFlags,
            Context context,
            CommandRegistry commandRegistry,
            WindowManager windowManager) {
        if (!mediaTttFlags.isMediaTttEnabled()) {
            return Optional.empty();
        }
        return Optional.of(new MediaTttChipController(context, commandRegistry, windowManager));
    }
}
+99 −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 android.content.Context
import android.graphics.PixelFormat
import android.view.Gravity
import android.view.WindowManager
import android.widget.TextView
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 controller to display and hide the Media Tap-To-Transfer chip. This chip is shown when a user
 * is currently playing media on a local "media cast sender" device (e.g. a phone) and gets close
 * enough to a "media cast receiver" device (e.g. a tablet). This chip encourages the user to
 * transfer the media from the sender device to the receiver device.
 */
@SysUISingleton
class MediaTttChipController @Inject constructor(
    context: Context,
    commandRegistry: CommandRegistry,
    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.MATCH_PARENT
        height = WindowManager.LayoutParams.MATCH_PARENT
        gravity = Gravity.CENTER_HORIZONTAL
        type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
        title = "Media Tap-To-Transfer Chip View"
        flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
        format = PixelFormat.TRANSLUCENT
        setTrustedOverlay()
    }

    // TODO(b/203800327): Create a layout that matches UX.
    private val chipView: TextView = TextView(context).apply {
        text = "Media Tap-To-Transfer Chip"
    }

    private var chipDisplaying: Boolean = false

    private fun addChip() {
        if (chipDisplaying) { return }
        windowManager.addView(chipView, windowLayoutParams)
        chipDisplaying = true
    }

    private fun removeChip() {
        if (!chipDisplaying) { return }
        windowManager.removeView(chipView)
        chipDisplaying = false
    }

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

    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"
    }
}
+29 −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 com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import javax.inject.Inject

/** Flags related to media tap-to-transfer. */
@SysUISingleton
class MediaTttFlags @Inject constructor(private val featureFlags: FeatureFlags) {
    /** */
    fun isMediaTttEnabled(): Boolean = featureFlags.isEnabled(Flags.MEDIA_TAP_TO_TRANSFER)
}
Loading