Merge changes from topics "presubmit-am-75f37079dffc432aa517bc8e4eb8269b", "presubmit-am-b883696932b4444b93bf6cb6589993f3" into tm-dev
* changes: [Media TTT] Don't hide the chip if we're in a transfer triggered state. Also give those states a longer timeout. [Media TTT] Add debug logging to the sender and receiver.
This commit is contained in:
committed by
Android (Google) Code Review
commit
edd81e4e8c
@@ -154,6 +154,28 @@ public class LogModule {
|
|||||||
return factory.create("SwipeStatusBarAwayLog", 30);
|
return factory.create("SwipeStatusBarAwayLog", 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a logging buffer for logs related to the media tap-to-transfer chip on the sender
|
||||||
|
* device. See {@link com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger}.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@SysUISingleton
|
||||||
|
@MediaTttSenderLogBuffer
|
||||||
|
public static LogBuffer provideMediaTttSenderLogBuffer(LogBufferFactory factory) {
|
||||||
|
return factory.create("MediaTttSender", 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a logging buffer for logs related to the media tap-to-transfer chip on the receiver
|
||||||
|
* device. See {@link com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger}.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@SysUISingleton
|
||||||
|
@MediaTttReceiverLogBuffer
|
||||||
|
public static LogBuffer provideMediaTttReceiverLogBuffer(LogBufferFactory factory) {
|
||||||
|
return factory.create("MediaTttReceiver", 20);
|
||||||
|
}
|
||||||
|
|
||||||
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
|
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
|
||||||
@Provides
|
@Provides
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.log.dagger;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import com.android.systemui.log.LogBuffer;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
import javax.inject.Qualifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link LogBuffer} for
|
||||||
|
* {@link com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger}.
|
||||||
|
*/
|
||||||
|
@Qualifier
|
||||||
|
@Documented
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface MediaTttReceiverLogBuffer {
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.log.dagger;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import com.android.systemui.log.LogBuffer;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
import javax.inject.Qualifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link LogBuffer} for
|
||||||
|
* {@link com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger}.
|
||||||
|
*/
|
||||||
|
@Qualifier
|
||||||
|
@Documented
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface MediaTttSenderLogBuffer {
|
||||||
|
}
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
package com.android.systemui.media.dagger;
|
package com.android.systemui.media.dagger;
|
||||||
|
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
|
import com.android.systemui.log.LogBuffer;
|
||||||
|
import com.android.systemui.log.dagger.MediaTttReceiverLogBuffer;
|
||||||
|
import com.android.systemui.log.dagger.MediaTttSenderLogBuffer;
|
||||||
import com.android.systemui.media.MediaDataManager;
|
import com.android.systemui.media.MediaDataManager;
|
||||||
import com.android.systemui.media.MediaFlags;
|
import com.android.systemui.media.MediaFlags;
|
||||||
import com.android.systemui.media.MediaHierarchyManager;
|
import com.android.systemui.media.MediaHierarchyManager;
|
||||||
@@ -27,8 +30,11 @@ import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli;
|
|||||||
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
|
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
|
||||||
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
|
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
|
||||||
import com.android.systemui.media.taptotransfer.MediaTttFlags;
|
import com.android.systemui.media.taptotransfer.MediaTttFlags;
|
||||||
|
import com.android.systemui.media.taptotransfer.common.MediaTttLogger;
|
||||||
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
|
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
|
||||||
|
import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger;
|
||||||
import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
|
import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
|
||||||
|
import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -112,6 +118,24 @@ public interface MediaModule {
|
|||||||
return Optional.of(controllerReceiverLazy.get());
|
return Optional.of(controllerReceiverLazy.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@SysUISingleton
|
||||||
|
@MediaTttSenderLogger
|
||||||
|
static MediaTttLogger providesMediaTttSenderLogger(
|
||||||
|
@MediaTttSenderLogBuffer LogBuffer buffer
|
||||||
|
) {
|
||||||
|
return new MediaTttLogger("Sender", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@SysUISingleton
|
||||||
|
@MediaTttReceiverLogger
|
||||||
|
static MediaTttLogger providesMediaTttReceiverLogger(
|
||||||
|
@MediaTttReceiverLogBuffer LogBuffer buffer
|
||||||
|
) {
|
||||||
|
return new MediaTttLogger("Receiver", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@Provides
|
@Provides
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.android.systemui.util.view.ViewUtil
|
|||||||
*/
|
*/
|
||||||
abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
||||||
internal val context: Context,
|
internal val context: Context,
|
||||||
|
internal val logger: MediaTttLogger,
|
||||||
private val windowManager: WindowManager,
|
private val windowManager: WindowManager,
|
||||||
private val viewUtil: ViewUtil,
|
private val viewUtil: ViewUtil,
|
||||||
@Main private val mainExecutor: DelayableExecutor,
|
@Main private val mainExecutor: DelayableExecutor,
|
||||||
@@ -93,18 +94,26 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
|
|
||||||
// Cancel and re-set the chip timeout each time we get a new state.
|
// Cancel and re-set the chip timeout each time we get a new state.
|
||||||
cancelChipViewTimeout?.run()
|
cancelChipViewTimeout?.run()
|
||||||
cancelChipViewTimeout = mainExecutor.executeDelayed(this::removeChip, TIMEOUT_MILLIS)
|
cancelChipViewTimeout = mainExecutor.executeDelayed(
|
||||||
|
{ removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
|
||||||
|
chipState.getTimeoutMs()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Hides the chip. */
|
/**
|
||||||
fun removeChip() {
|
* Hides the chip.
|
||||||
// TODO(b/203800347): We may not want to hide the chip if we're currently in a
|
*
|
||||||
// TransferTriggered state: Once the user has initiated the transfer, they should be able
|
* @param removalReason a short string describing why the chip was removed (timeout, state
|
||||||
// to move away from the receiver device but still see the status of the transfer.
|
* change, etc.)
|
||||||
|
*/
|
||||||
|
open fun removeChip(removalReason: String) {
|
||||||
if (chipView == null) { return }
|
if (chipView == null) { return }
|
||||||
|
logger.logChipRemoval(removalReason)
|
||||||
tapGestureDetector.removeOnGestureDetectedCallback(TAG)
|
tapGestureDetector.removeOnGestureDetectedCallback(TAG)
|
||||||
windowManager.removeView(chipView)
|
windowManager.removeView(chipView)
|
||||||
chipView = null
|
chipView = null
|
||||||
|
// No need to time the chip out since it's already gone
|
||||||
|
cancelChipViewTimeout?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,7 +145,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
// If the tap is within the chip bounds, we shouldn't hide the chip (in case users think the
|
// If the tap is within the chip bounds, we shouldn't hide the chip (in case users think the
|
||||||
// chip is tappable).
|
// chip is tappable).
|
||||||
if (!viewUtil.touchIsWithinView(view, e.x, e.y)) {
|
if (!viewUtil.touchIsWithinView(view, e.x, e.y)) {
|
||||||
removeChip()
|
removeChip(MediaTttRemovalReason.REASON_SCREEN_TAP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,5 +154,9 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
|
|||||||
// UpdateMediaTapToTransferReceiverDisplayTest
|
// UpdateMediaTapToTransferReceiverDisplayTest
|
||||||
private const val WINDOW_TITLE = "Media Transfer Chip View"
|
private const val WINDOW_TITLE = "Media Transfer Chip View"
|
||||||
private val TAG = MediaTttChipControllerCommon::class.simpleName!!
|
private val TAG = MediaTttChipControllerCommon::class.simpleName!!
|
||||||
@VisibleForTesting
|
|
||||||
const val TIMEOUT_MILLIS = 3000L
|
object MediaTttRemovalReason {
|
||||||
|
const val REASON_TIMEOUT = "TIMEOUT"
|
||||||
|
const val REASON_SCREEN_TAP = "SCREEN_TAP"
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,14 @@ open class MediaTttChipState(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount of time this chip should display on the screen before it times out and
|
||||||
|
* disappears. [MediaTttChipControllerCommon] will ensure that the timeout resets each time we
|
||||||
|
* receive a new state.
|
||||||
|
*/
|
||||||
|
open fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val DEFAULT_TIMEOUT_MILLIS = 3000L
|
||||||
private val TAG = MediaTttChipState::class.simpleName!!
|
private val TAG = MediaTttChipState::class.simpleName!!
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.media.taptotransfer.common
|
||||||
|
|
||||||
|
import com.android.systemui.log.LogBuffer
|
||||||
|
import com.android.systemui.log.LogLevel
|
||||||
|
import com.android.systemui.log.dagger.MediaTttSenderLogBuffer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A logger for media tap-to-transfer events.
|
||||||
|
*
|
||||||
|
* @property deviceTypeTag the type of device triggering the logs -- "Sender" or "Receiver".
|
||||||
|
*/
|
||||||
|
class MediaTttLogger(
|
||||||
|
private val deviceTypeTag: String,
|
||||||
|
@MediaTttSenderLogBuffer private val buffer: LogBuffer
|
||||||
|
){
|
||||||
|
/** Logs a change in the chip state for the given [mediaRouteId]. */
|
||||||
|
fun logStateChange(stateName: String, mediaRouteId: String) {
|
||||||
|
buffer.log(
|
||||||
|
BASE_TAG + deviceTypeTag,
|
||||||
|
LogLevel.DEBUG,
|
||||||
|
{
|
||||||
|
str1 = stateName
|
||||||
|
str2 = mediaRouteId
|
||||||
|
},
|
||||||
|
{ "State changed to $str1 for ID=$str2" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Logs that we removed the chip for the given [reason]. */
|
||||||
|
fun logChipRemoval(reason: String) {
|
||||||
|
buffer.log(
|
||||||
|
BASE_TAG + deviceTypeTag,
|
||||||
|
LogLevel.DEBUG,
|
||||||
|
{ str1 = reason },
|
||||||
|
{ "Chip removed due to $str1" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val BASE_TAG = "MediaTtt"
|
||||||
@@ -28,6 +28,7 @@ import com.android.systemui.R
|
|||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Main
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
|
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
|
||||||
|
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
|
||||||
import com.android.systemui.statusbar.CommandQueue
|
import com.android.systemui.statusbar.CommandQueue
|
||||||
import com.android.systemui.statusbar.gesture.TapGestureDetector
|
import com.android.systemui.statusbar.gesture.TapGestureDetector
|
||||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||||
@@ -43,6 +44,7 @@ import javax.inject.Inject
|
|||||||
class MediaTttChipControllerReceiver @Inject constructor(
|
class MediaTttChipControllerReceiver @Inject constructor(
|
||||||
commandQueue: CommandQueue,
|
commandQueue: CommandQueue,
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@MediaTttReceiverLogger logger: MediaTttLogger,
|
||||||
windowManager: WindowManager,
|
windowManager: WindowManager,
|
||||||
viewUtil: ViewUtil,
|
viewUtil: ViewUtil,
|
||||||
mainExecutor: DelayableExecutor,
|
mainExecutor: DelayableExecutor,
|
||||||
@@ -50,6 +52,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
@Main private val mainHandler: Handler,
|
@Main private val mainHandler: Handler,
|
||||||
) : MediaTttChipControllerCommon<ChipStateReceiver>(
|
) : MediaTttChipControllerCommon<ChipStateReceiver>(
|
||||||
context,
|
context,
|
||||||
|
logger,
|
||||||
windowManager,
|
windowManager,
|
||||||
viewUtil,
|
viewUtil,
|
||||||
mainExecutor,
|
mainExecutor,
|
||||||
@@ -79,6 +82,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
appIcon: Icon?,
|
appIcon: Icon?,
|
||||||
appName: CharSequence?
|
appName: CharSequence?
|
||||||
) {
|
) {
|
||||||
|
logger.logStateChange(stateIntToString(displayState), routeInfo.id)
|
||||||
when(displayState) {
|
when(displayState) {
|
||||||
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> {
|
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> {
|
||||||
val packageName = routeInfo.packageName
|
val packageName = routeInfo.packageName
|
||||||
@@ -97,7 +101,8 @@ class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> removeChip()
|
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER ->
|
||||||
|
removeChip(removalReason = FAR_FROM_SENDER)
|
||||||
else ->
|
else ->
|
||||||
Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
|
Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
|
||||||
}
|
}
|
||||||
@@ -106,6 +111,16 @@ class MediaTttChipControllerReceiver @Inject constructor(
|
|||||||
override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) {
|
override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) {
|
||||||
setIcon(chipState, currentChipView)
|
setIcon(chipState, currentChipView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun stateIntToString(@StatusBarManager.MediaTransferReceiverState state: Int): String {
|
||||||
|
return when (state) {
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER -> CLOSE_TO_SENDER
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> FAR_FROM_SENDER
|
||||||
|
else -> "INVALID: $state"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val RECEIVER_TAG = "MediaTapToTransferRcvr"
|
private const val RECEIVER_TAG = "MediaTapToTransferRcvr"
|
||||||
|
private const val CLOSE_TO_SENDER = "CLOSE_TO_SENDER"
|
||||||
|
private const val FAR_FROM_SENDER = "FAR_FROM_SENDER"
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.media.taptotransfer.receiver
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented
|
||||||
|
import java.lang.annotation.Retention
|
||||||
|
import java.lang.annotation.RetentionPolicy
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
annotation class MediaTttReceiverLogger
|
||||||
@@ -97,6 +97,7 @@ class TransferToReceiverTriggered(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showLoading() = true
|
override fun showLoading() = true
|
||||||
|
override fun getTimeoutMs() = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,6 +112,7 @@ class TransferToThisDeviceTriggered(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showLoading() = true
|
override fun showLoading() = true
|
||||||
|
override fun getTimeoutMs() = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -194,3 +196,8 @@ class TransferFailed(
|
|||||||
return context.getString(R.string.media_transfer_failed)
|
return context.getString(R.string.media_transfer_failed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Give the Transfer*Triggered states a longer timeout since those states represent an active
|
||||||
|
// process and we should keep the user informed about it as long as possible (but don't allow it to
|
||||||
|
// continue indefinitely).
|
||||||
|
private const val TRANSFER_TRIGGERED_TIMEOUT_MILLIS = 15000L
|
||||||
@@ -29,6 +29,8 @@ import com.android.systemui.R
|
|||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.Main
|
import com.android.systemui.dagger.qualifiers.Main
|
||||||
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
|
import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
|
||||||
|
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
|
||||||
|
import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason
|
||||||
import com.android.systemui.statusbar.CommandQueue
|
import com.android.systemui.statusbar.CommandQueue
|
||||||
import com.android.systemui.statusbar.gesture.TapGestureDetector
|
import com.android.systemui.statusbar.gesture.TapGestureDetector
|
||||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||||
@@ -43,13 +45,22 @@ import javax.inject.Inject
|
|||||||
class MediaTttChipControllerSender @Inject constructor(
|
class MediaTttChipControllerSender @Inject constructor(
|
||||||
commandQueue: CommandQueue,
|
commandQueue: CommandQueue,
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@MediaTttSenderLogger logger: MediaTttLogger,
|
||||||
windowManager: WindowManager,
|
windowManager: WindowManager,
|
||||||
viewUtil: ViewUtil,
|
viewUtil: ViewUtil,
|
||||||
@Main mainExecutor: DelayableExecutor,
|
@Main mainExecutor: DelayableExecutor,
|
||||||
tapGestureDetector: TapGestureDetector,
|
tapGestureDetector: TapGestureDetector,
|
||||||
) : MediaTttChipControllerCommon<ChipStateSender>(
|
) : MediaTttChipControllerCommon<ChipStateSender>(
|
||||||
context, windowManager, viewUtil, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip
|
context,
|
||||||
|
logger,
|
||||||
|
windowManager,
|
||||||
|
viewUtil,
|
||||||
|
mainExecutor,
|
||||||
|
tapGestureDetector,
|
||||||
|
R.layout.media_ttt_chip
|
||||||
) {
|
) {
|
||||||
|
private var currentlyDisplayedChipState: ChipStateSender? = null
|
||||||
|
|
||||||
private val commandQueueCallbacks = object : CommandQueue.Callbacks {
|
private val commandQueueCallbacks = object : CommandQueue.Callbacks {
|
||||||
override fun updateMediaTapToTransferSenderDisplay(
|
override fun updateMediaTapToTransferSenderDisplay(
|
||||||
@StatusBarManager.MediaTransferSenderState displayState: Int,
|
@StatusBarManager.MediaTransferSenderState displayState: Int,
|
||||||
@@ -71,6 +82,7 @@ class MediaTttChipControllerSender @Inject constructor(
|
|||||||
routeInfo: MediaRoute2Info,
|
routeInfo: MediaRoute2Info,
|
||||||
undoCallback: IUndoMediaTransferCallback?
|
undoCallback: IUndoMediaTransferCallback?
|
||||||
) {
|
) {
|
||||||
|
logger.logStateChange(stateIntToString(displayState), routeInfo.id)
|
||||||
val appPackageName = routeInfo.packageName
|
val appPackageName = routeInfo.packageName
|
||||||
val otherDeviceName = routeInfo.name.toString()
|
val otherDeviceName = routeInfo.name.toString()
|
||||||
val chipState = when(displayState) {
|
val chipState = when(displayState) {
|
||||||
@@ -90,7 +102,7 @@ class MediaTttChipControllerSender @Inject constructor(
|
|||||||
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED ->
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED ->
|
||||||
TransferFailed(appPackageName)
|
TransferFailed(appPackageName)
|
||||||
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> {
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> {
|
||||||
removeChip()
|
removeChip(removalReason = FAR_FROM_RECEIVER)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@@ -106,6 +118,8 @@ class MediaTttChipControllerSender @Inject constructor(
|
|||||||
|
|
||||||
/** Displays the chip view for the given state. */
|
/** Displays the chip view for the given state. */
|
||||||
override fun updateChipView(chipState: ChipStateSender, currentChipView: ViewGroup) {
|
override fun updateChipView(chipState: ChipStateSender, currentChipView: ViewGroup) {
|
||||||
|
currentlyDisplayedChipState = chipState
|
||||||
|
|
||||||
// App icon
|
// App icon
|
||||||
setIcon(chipState, currentChipView)
|
setIcon(chipState, currentChipView)
|
||||||
|
|
||||||
@@ -129,6 +143,43 @@ class MediaTttChipControllerSender @Inject constructor(
|
|||||||
currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
|
currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
|
||||||
if (showFailure) { View.VISIBLE } else { View.GONE }
|
if (showFailure) { View.VISIBLE } else { View.GONE }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun removeChip(removalReason: String) {
|
||||||
|
// Don't remove the chip if we're mid-transfer since the user should still be able to
|
||||||
|
// see the status of the transfer. (But do remove it if it's finally timed out.)
|
||||||
|
if ((currentlyDisplayedChipState is TransferToReceiverTriggered ||
|
||||||
|
currentlyDisplayedChipState is TransferToThisDeviceTriggered)
|
||||||
|
&& removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
super.removeChip(removalReason)
|
||||||
|
currentlyDisplayedChipState = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stateIntToString(@StatusBarManager.MediaTransferSenderState state: Int): String {
|
||||||
|
return when(state) {
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST ->
|
||||||
|
"ALMOST_CLOSE_TO_START_CAST"
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST ->
|
||||||
|
"ALMOST_CLOSE_TO_END_CAST"
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED ->
|
||||||
|
"TRANSFER_TO_RECEIVER_TRIGGERED"
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED ->
|
||||||
|
"TRANSFER_TO_THIS_DEVICE_TRIGGERED"
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED ->
|
||||||
|
"TRANSFER_TO_RECEIVER_SUCCEEDED"
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED ->
|
||||||
|
"TRANSFER_TO_THIS_DEVICE_SUCCEEDED"
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED ->
|
||||||
|
"TRANSFER_TO_RECEIVER_FAILED"
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED ->
|
||||||
|
"TRANSFER_TO_THIS_DEVICE_FAILED"
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER ->
|
||||||
|
FAR_FROM_RECEIVER
|
||||||
|
else -> "INVALID: $state"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const val SENDER_TAG = "MediaTapToTransferSender"
|
const val SENDER_TAG = "MediaTapToTransferSender"
|
||||||
|
private const val FAR_FROM_RECEIVER = "FAR_FROM_RECEIVER"
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.media.taptotransfer.sender
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented
|
||||||
|
import java.lang.annotation.Retention
|
||||||
|
import java.lang.annotation.RetentionPolicy
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
annotation class MediaTttSenderLogger
|
||||||
@@ -55,6 +55,8 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
|
|
||||||
private lateinit var appIconDrawable: Drawable
|
private lateinit var appIconDrawable: Drawable
|
||||||
@Mock
|
@Mock
|
||||||
|
private lateinit var logger: MediaTttLogger
|
||||||
|
@Mock
|
||||||
private lateinit var windowManager: WindowManager
|
private lateinit var windowManager: WindowManager
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var viewUtil: ViewUtil
|
private lateinit var viewUtil: ViewUtil
|
||||||
@@ -69,7 +71,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
fakeExecutor = FakeExecutor(fakeClock)
|
fakeExecutor = FakeExecutor(fakeClock)
|
||||||
|
|
||||||
controllerCommon = TestControllerCommon(
|
controllerCommon = TestControllerCommon(
|
||||||
context, windowManager, viewUtil, fakeExecutor, tapGestureDetector
|
context, logger, windowManager, viewUtil, fakeExecutor, tapGestureDetector
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,20 +96,22 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun displayChip_chipDoesNotDisappearsBeforeTimeout() {
|
fun displayChip_chipDoesNotDisappearsBeforeTimeout() {
|
||||||
controllerCommon.displayChip(getState())
|
val state = getState()
|
||||||
|
controllerCommon.displayChip(state)
|
||||||
reset(windowManager)
|
reset(windowManager)
|
||||||
|
|
||||||
fakeClock.advanceTime(TIMEOUT_MILLIS - 1)
|
fakeClock.advanceTime(state.getTimeoutMs() - 1)
|
||||||
|
|
||||||
verify(windowManager, never()).removeView(any())
|
verify(windowManager, never()).removeView(any())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun displayChip_chipDisappearsAfterTimeout() {
|
fun displayChip_chipDisappearsAfterTimeout() {
|
||||||
controllerCommon.displayChip(getState())
|
val state = getState()
|
||||||
|
controllerCommon.displayChip(state)
|
||||||
reset(windowManager)
|
reset(windowManager)
|
||||||
|
|
||||||
fakeClock.advanceTime(TIMEOUT_MILLIS + 1)
|
fakeClock.advanceTime(state.getTimeoutMs() + 1)
|
||||||
|
|
||||||
verify(windowManager).removeView(any())
|
verify(windowManager).removeView(any())
|
||||||
}
|
}
|
||||||
@@ -115,7 +119,8 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun displayChip_calledAgainBeforeTimeout_timeoutReset() {
|
fun displayChip_calledAgainBeforeTimeout_timeoutReset() {
|
||||||
// First, display the chip
|
// First, display the chip
|
||||||
controllerCommon.displayChip(getState())
|
val state = getState()
|
||||||
|
controllerCommon.displayChip(state)
|
||||||
|
|
||||||
// After some time, re-display the chip
|
// After some time, re-display the chip
|
||||||
val waitTime = 1000L
|
val waitTime = 1000L
|
||||||
@@ -123,7 +128,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
controllerCommon.displayChip(getState())
|
controllerCommon.displayChip(getState())
|
||||||
|
|
||||||
// Wait until the timeout for the first display would've happened
|
// Wait until the timeout for the first display would've happened
|
||||||
fakeClock.advanceTime(TIMEOUT_MILLIS - waitTime + 1)
|
fakeClock.advanceTime(state.getTimeoutMs() - waitTime + 1)
|
||||||
|
|
||||||
// Verify we didn't hide the chip
|
// Verify we didn't hide the chip
|
||||||
verify(windowManager, never()).removeView(any())
|
verify(windowManager, never()).removeView(any())
|
||||||
@@ -132,33 +137,36 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun displayChip_calledAgainBeforeTimeout_eventuallyTimesOut() {
|
fun displayChip_calledAgainBeforeTimeout_eventuallyTimesOut() {
|
||||||
// First, display the chip
|
// First, display the chip
|
||||||
controllerCommon.displayChip(getState())
|
val state = getState()
|
||||||
|
controllerCommon.displayChip(state)
|
||||||
|
|
||||||
// After some time, re-display the chip
|
// After some time, re-display the chip
|
||||||
fakeClock.advanceTime(1000L)
|
fakeClock.advanceTime(1000L)
|
||||||
controllerCommon.displayChip(getState())
|
controllerCommon.displayChip(getState())
|
||||||
|
|
||||||
// Ensure we still hide the chip eventually
|
// Ensure we still hide the chip eventually
|
||||||
fakeClock.advanceTime(TIMEOUT_MILLIS + 1)
|
fakeClock.advanceTime(state.getTimeoutMs() + 1)
|
||||||
|
|
||||||
verify(windowManager).removeView(any())
|
verify(windowManager).removeView(any())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun removeChip_chipRemovedAndGestureDetectionStopped() {
|
fun removeChip_chipRemovedAndGestureDetectionStoppedAndRemovalLogged() {
|
||||||
// First, add the chip
|
// First, add the chip
|
||||||
controllerCommon.displayChip(getState())
|
controllerCommon.displayChip(getState())
|
||||||
|
|
||||||
// Then, remove it
|
// Then, remove it
|
||||||
controllerCommon.removeChip()
|
val reason = "test reason"
|
||||||
|
controllerCommon.removeChip(reason)
|
||||||
|
|
||||||
verify(windowManager).removeView(any())
|
verify(windowManager).removeView(any())
|
||||||
verify(tapGestureDetector).removeOnGestureDetectedCallback(any())
|
verify(tapGestureDetector).removeOnGestureDetectedCallback(any())
|
||||||
|
verify(logger).logChipRemoval(reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun removeChip_noAdd_viewNotRemoved() {
|
fun removeChip_noAdd_viewNotRemoved() {
|
||||||
controllerCommon.removeChip()
|
controllerCommon.removeChip("reason")
|
||||||
|
|
||||||
verify(windowManager, never()).removeView(any())
|
verify(windowManager, never()).removeView(any())
|
||||||
}
|
}
|
||||||
@@ -222,12 +230,19 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
|
|||||||
|
|
||||||
inner class TestControllerCommon(
|
inner class TestControllerCommon(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
logger: MediaTttLogger,
|
||||||
windowManager: WindowManager,
|
windowManager: WindowManager,
|
||||||
viewUtil: ViewUtil,
|
viewUtil: ViewUtil,
|
||||||
@Main mainExecutor: DelayableExecutor,
|
@Main mainExecutor: DelayableExecutor,
|
||||||
tapGestureDetector: TapGestureDetector,
|
tapGestureDetector: TapGestureDetector,
|
||||||
) : MediaTttChipControllerCommon<MediaTttChipState>(
|
) : MediaTttChipControllerCommon<MediaTttChipState>(
|
||||||
context, windowManager, viewUtil, mainExecutor, tapGestureDetector, R.layout.media_ttt_chip
|
context,
|
||||||
|
logger,
|
||||||
|
windowManager,
|
||||||
|
viewUtil,
|
||||||
|
mainExecutor,
|
||||||
|
tapGestureDetector,
|
||||||
|
R.layout.media_ttt_chip
|
||||||
) {
|
) {
|
||||||
override fun updateChipView(chipState: MediaTttChipState, currentChipView: ViewGroup) {
|
override fun updateChipView(chipState: MediaTttChipState, currentChipView: ViewGroup) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.media.taptotransfer.common
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.dump.DumpManager
|
||||||
|
import com.android.systemui.log.LogBuffer
|
||||||
|
import com.android.systemui.log.LogBufferFactory
|
||||||
|
import com.android.systemui.log.LogcatEchoTracker
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import java.io.StringWriter
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
class MediaTttLoggerTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private lateinit var buffer: LogBuffer
|
||||||
|
private lateinit var logger: MediaTttLogger
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp () {
|
||||||
|
buffer = LogBufferFactory(DumpManager(), mock(LogcatEchoTracker::class.java))
|
||||||
|
.create("buffer", 10)
|
||||||
|
logger = MediaTttLogger(DEVICE_TYPE_TAG, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun logStateChange_bufferHasDeviceTypeTagAndStateNameAndId() {
|
||||||
|
val stateName = "test state name"
|
||||||
|
val id = "test id"
|
||||||
|
|
||||||
|
logger.logStateChange(stateName, id)
|
||||||
|
|
||||||
|
val stringWriter = StringWriter()
|
||||||
|
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
|
||||||
|
val actualString = stringWriter.toString()
|
||||||
|
|
||||||
|
assertThat(actualString).contains(DEVICE_TYPE_TAG)
|
||||||
|
assertThat(actualString).contains(stateName)
|
||||||
|
assertThat(actualString).contains(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun logChipRemoval_bufferHasDeviceTypeAndReason() {
|
||||||
|
val reason = "test reason"
|
||||||
|
logger.logChipRemoval(reason)
|
||||||
|
|
||||||
|
val stringWriter = StringWriter()
|
||||||
|
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
|
||||||
|
val actualString = stringWriter.toString()
|
||||||
|
|
||||||
|
assertThat(actualString).contains(DEVICE_TYPE_TAG)
|
||||||
|
assertThat(actualString).contains(reason)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val DEVICE_TYPE_TAG = "TEST TYPE"
|
||||||
@@ -31,6 +31,7 @@ import android.widget.ImageView
|
|||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
|
||||||
import com.android.systemui.statusbar.CommandQueue
|
import com.android.systemui.statusbar.CommandQueue
|
||||||
import com.android.systemui.statusbar.gesture.TapGestureDetector
|
import com.android.systemui.statusbar.gesture.TapGestureDetector
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
@@ -60,6 +61,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
@Mock
|
@Mock
|
||||||
private lateinit var applicationInfo: ApplicationInfo
|
private lateinit var applicationInfo: ApplicationInfo
|
||||||
@Mock
|
@Mock
|
||||||
|
private lateinit var logger: MediaTttLogger
|
||||||
|
@Mock
|
||||||
private lateinit var windowManager: WindowManager
|
private lateinit var windowManager: WindowManager
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var viewUtil: ViewUtil
|
private lateinit var viewUtil: ViewUtil
|
||||||
@@ -83,6 +86,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
controllerReceiver = MediaTttChipControllerReceiver(
|
controllerReceiver = MediaTttChipControllerReceiver(
|
||||||
commandQueue,
|
commandQueue,
|
||||||
context,
|
context,
|
||||||
|
logger,
|
||||||
windowManager,
|
windowManager,
|
||||||
viewUtil,
|
viewUtil,
|
||||||
FakeExecutor(FakeSystemClock()),
|
FakeExecutor(FakeSystemClock()),
|
||||||
@@ -141,6 +145,18 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
|
|||||||
verify(windowManager).removeView(viewCaptor.value)
|
verify(windowManager).removeView(viewCaptor.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun receivesNewStateFromCommandQueue_isLogged() {
|
||||||
|
commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
|
||||||
|
routeInfo,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
|
verify(logger).logStateChange(any(), any())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun displayChip_nullAppIconDrawable_iconIsFromPackageName() {
|
fun displayChip_nullAppIconDrawable_iconIsFromPackageName() {
|
||||||
val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, "appName")
|
val state = ChipStateReceiver(PACKAGE_NAME, appIconDrawable = null, "appName")
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest
|
|||||||
import com.android.internal.statusbar.IUndoMediaTransferCallback
|
import com.android.internal.statusbar.IUndoMediaTransferCallback
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
|
||||||
import com.android.systemui.statusbar.CommandQueue
|
import com.android.systemui.statusbar.CommandQueue
|
||||||
import com.android.systemui.statusbar.gesture.TapGestureDetector
|
import com.android.systemui.statusbar.gesture.TapGestureDetector
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
@@ -62,6 +63,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
@Mock
|
@Mock
|
||||||
private lateinit var applicationInfo: ApplicationInfo
|
private lateinit var applicationInfo: ApplicationInfo
|
||||||
@Mock
|
@Mock
|
||||||
|
private lateinit var logger: MediaTttLogger
|
||||||
|
@Mock
|
||||||
private lateinit var windowManager: WindowManager
|
private lateinit var windowManager: WindowManager
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var viewUtil: ViewUtil
|
private lateinit var viewUtil: ViewUtil
|
||||||
@@ -69,6 +72,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
private lateinit var commandQueue: CommandQueue
|
private lateinit var commandQueue: CommandQueue
|
||||||
private lateinit var commandQueueCallback: CommandQueue.Callbacks
|
private lateinit var commandQueueCallback: CommandQueue.Callbacks
|
||||||
private lateinit var fakeAppIconDrawable: Drawable
|
private lateinit var fakeAppIconDrawable: Drawable
|
||||||
|
private lateinit var fakeClock: FakeSystemClock
|
||||||
|
private lateinit var fakeExecutor: FakeExecutor
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
@@ -82,12 +87,16 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
)).thenReturn(applicationInfo)
|
)).thenReturn(applicationInfo)
|
||||||
context.setMockPackageManager(packageManager)
|
context.setMockPackageManager(packageManager)
|
||||||
|
|
||||||
|
fakeClock = FakeSystemClock()
|
||||||
|
fakeExecutor = FakeExecutor(fakeClock)
|
||||||
|
|
||||||
controllerSender = MediaTttChipControllerSender(
|
controllerSender = MediaTttChipControllerSender(
|
||||||
commandQueue,
|
commandQueue,
|
||||||
context,
|
context,
|
||||||
|
logger,
|
||||||
windowManager,
|
windowManager,
|
||||||
viewUtil,
|
viewUtil,
|
||||||
FakeExecutor(FakeSystemClock()),
|
fakeExecutor,
|
||||||
TapGestureDetector(context)
|
TapGestureDetector(context)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -222,6 +231,17 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
verify(windowManager).removeView(viewCaptor.value)
|
verify(windowManager).removeView(viewCaptor.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun receivesNewStateFromCommandQueue_isLogged() {
|
||||||
|
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
|
||||||
|
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
|
||||||
|
routeInfo,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
|
verify(logger).logStateChange(any(), any())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
|
fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
|
||||||
val state = almostCloseToStartCast()
|
val state = almostCloseToStartCast()
|
||||||
@@ -460,6 +480,52 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
|
|||||||
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
|
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun transferToReceiverTriggeredThenRemoveChip_chipStillDisplayed() {
|
||||||
|
controllerSender.displayChip(transferToReceiverTriggered())
|
||||||
|
fakeClock.advanceTime(1000L)
|
||||||
|
|
||||||
|
controllerSender.removeChip("fakeRemovalReason")
|
||||||
|
fakeExecutor.runAllReady()
|
||||||
|
|
||||||
|
verify(windowManager, never()).removeView(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun transferToReceiverTriggeredThenFarFromReceiver_eventuallyTimesOut() {
|
||||||
|
val state = transferToReceiverTriggered()
|
||||||
|
controllerSender.displayChip(state)
|
||||||
|
fakeClock.advanceTime(1000L)
|
||||||
|
controllerSender.removeChip("fakeRemovalReason")
|
||||||
|
|
||||||
|
fakeClock.advanceTime(state.getTimeoutMs() + 1)
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun transferToThisDeviceTriggeredThenRemoveChip_chipStillDisplayed() {
|
||||||
|
controllerSender.displayChip(transferToThisDeviceTriggered())
|
||||||
|
fakeClock.advanceTime(1000L)
|
||||||
|
|
||||||
|
controllerSender.removeChip("fakeRemovalReason")
|
||||||
|
fakeExecutor.runAllReady()
|
||||||
|
|
||||||
|
verify(windowManager, never()).removeView(any())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun transferToThisDeviceTriggeredThenFarFromReceiver_eventuallyTimesOut() {
|
||||||
|
val state = transferToThisDeviceTriggered()
|
||||||
|
controllerSender.displayChip(state)
|
||||||
|
fakeClock.advanceTime(1000L)
|
||||||
|
controllerSender.removeChip("fakeRemovalReason")
|
||||||
|
|
||||||
|
fakeClock.advanceTime(state.getTimeoutMs() + 1)
|
||||||
|
|
||||||
|
verify(windowManager).removeView(any())
|
||||||
|
}
|
||||||
|
|
||||||
private fun LinearLayout.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
|
private fun LinearLayout.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
|
||||||
|
|
||||||
private fun LinearLayout.getChipText(): String =
|
private fun LinearLayout.getChipText(): String =
|
||||||
|
|||||||
Reference in New Issue
Block a user