Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java +2 −31 Original line number Diff line number Diff line Loading @@ -50,7 +50,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tiles.dialog.CastDetailsViewModel; import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor; import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor; import com.android.systemui.statusbar.connectivity.IconState; Loading @@ -64,7 +63,6 @@ import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading Loading @@ -106,8 +104,6 @@ public class CastTileTest extends SysuiTestCase { private DialogTransitionAnimator mDialogTransitionAnimator; @Mock private QsEventLogger mUiEventLogger; @Mock private CastDetailsViewModel.Factory mCastDetailsViewModelFactory; private final TileJavaAdapter mJavaAdapter = new TileJavaAdapter(); private final FakeConnectivityRepository mConnectivityRepository = Loading Loading @@ -521,29 +517,6 @@ public class CastTileTest extends SysuiTestCase { assertTrue(mCastTile.getState().forceExpandIcon); } @Test public void testDetailsViewUnavailableState_returnsNull() { createAndStartTileNewImpl(); mTestableLooper.processAllMessages(); assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state); mCastTile.getDetailsViewModel(Assert::assertNull); } @Test public void testDetailsViewAvailableState_returnsNotNull() { createAndStartTileNewImpl(); CastDevice device = createConnectedCastDevice(); List<CastDevice> devices = new ArrayList<>(); devices.add(device); when(mController.getCastDevices()).thenReturn(devices); mConnectivityRepository.setWifiConnected(true); mTestableLooper.processAllMessages(); assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state); mCastTile.getDetailsViewModel(Assert::assertNotNull); } /** * For simplicity, let this method still set the field even though that's kind of gross */ Loading @@ -567,8 +540,7 @@ public class CastTileTest extends SysuiTestCase { mConnectivityRepository, mJavaAdapter, mFeatureFlags, mShadeDialogContextInteractor, mCastDetailsViewModelFactory mShadeDialogContextInteractor ); mCastTile.initialize(); Loading Loading @@ -612,8 +584,7 @@ public class CastTileTest extends SysuiTestCase { mConnectivityRepository, mJavaAdapter, mFeatureFlags, mShadeDialogContextInteractor, mCastDetailsViewModelFactory mShadeDialogContextInteractor ); mCastTile.initialize(); Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt +0 −3 Original line number Diff line number Diff line Loading @@ -43,8 +43,6 @@ import com.android.systemui.bluetooth.qsdialog.BluetoothDetailsViewModel import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.qs.flags.QsDetailedView import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel import com.android.systemui.qs.tiles.dialog.CastDetailsContent import com.android.systemui.qs.tiles.dialog.CastDetailsViewModel import com.android.systemui.qs.tiles.dialog.InternetDetailsContent import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel import com.android.systemui.qs.tiles.dialog.ModesDetailsContent Loading Loading @@ -133,7 +131,6 @@ private fun MapTileDetailsContent(tileDetailsViewModel: TileDetailsViewModel) { is BluetoothDetailsViewModel -> BluetoothDetailsContent(tileDetailsViewModel.detailsContentViewModel) is ModesDetailsViewModel -> ModesDetailsContent(tileDetailsViewModel) is CastDetailsViewModel -> CastDetailsContent() } } Loading packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +13 −40 Original line number Diff line number Diff line Loading @@ -48,13 +48,11 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.qs.TileDetailsViewModel; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.qs.tiles.dialog.CastDetailsViewModel; import com.android.systemui.res.R; import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor; import com.android.systemui.statusbar.connectivity.NetworkController; Loading Loading @@ -95,7 +93,6 @@ public class CastTile extends QSTileImpl<BooleanState> { private final ShadeDialogContextInteractor mShadeDialogContextInteractor; private boolean mCastTransportAllowed; private boolean mHotspotConnected; private final CastDetailsViewModel.Factory mCastDetailsViewModelFactory; @Inject public CastTile( Loading @@ -116,8 +113,7 @@ public class CastTile extends QSTileImpl<BooleanState> { ConnectivityRepository connectivityRepository, TileJavaAdapter javaAdapter, FeatureFlags featureFlags, ShadeDialogContextInteractor shadeDialogContextInteractor, CastDetailsViewModel.Factory castDetailsViewModelFactory ShadeDialogContextInteractor shadeDialogContextInteractor ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); Loading @@ -128,7 +124,6 @@ public class CastTile extends QSTileImpl<BooleanState> { mJavaAdapter = javaAdapter; mFeatureFlags = featureFlags; mShadeDialogContextInteractor = shadeDialogContextInteractor; mCastDetailsViewModelFactory = castDetailsViewModelFactory; mController.observe(this, mCallback); mKeyguard.observe(this, mCallback); if (!mFeatureFlags.isEnabled(SIGNAL_CALLBACK_DEPRECATION)) { Loading Loading @@ -177,7 +172,12 @@ public class CastTile extends QSTileImpl<BooleanState> { @Override protected void handleClick(@Nullable Expandable expandable) { handleClick(() -> { if (getState().state == Tile.STATE_UNAVAILABLE) { return; } List<CastDevice> activeDevices = getActiveDevices(); if (willPopDialog()) { if (!mKeyguard.isShowing()) { showDialog(expandable); } else { Loading @@ -187,43 +187,16 @@ public class CastTile extends QSTileImpl<BooleanState> { showDialog(null /* view */); }); } }); } @Override public boolean getDetailsViewModel(Consumer<TileDetailsViewModel> callback) { CastDetailsViewModel viewModel = mCastDetailsViewModelFactory.create(); handleClick(() -> { if (!mKeyguard.isShowing()) { callback.accept(viewModel); } else { mActivityStarter.dismissKeyguardThenExecute(() -> { callback.accept(viewModel); return false; }, null /* cancelAction */, true/* afterKeyguardGone */); } }); return true; } private void handleClick(Runnable showPromptCallback) { if (getState().state == Tile.STATE_UNAVAILABLE) { return; } List<CastDevice> activeDevices = getActiveDevices(); if (willShowPrompt()) { showPromptCallback.run(); } else { mController.stopCasting(activeDevices.get(0), StopReason.STOP_QS_TILE); } } // We want to pop up the media route selection dialog (or show the cast details view) if we // either have no active devices (neither routes nor projection), or if we have an active // route. In other cases, we assume that a projection is active. This is messy, but this tile // never correctly handled the case where multiple devices were active :-/. private boolean willShowPrompt() { // We want to pop up the media route selection dialog if we either have no active devices // (neither routes nor projection), or if we have an active route. In other cases, we assume // that a projection is active. This is messy, but this tile never correctly handled the // case where multiple devices were active :-/. private boolean willPopDialog() { List<CastDevice> activeDevices = getActiveDevices(); return activeDevices.isEmpty() || (activeDevices.get(0).getTag() instanceof RouteInfo); } Loading Loading @@ -330,7 +303,7 @@ public class CastTile extends QSTileImpl<BooleanState> { state.secondaryLabel = ""; } state.expandedAccessibilityClassName = Button.class.getName(); state.forceExpandIcon = willShowPrompt(); state.forceExpandIcon = willPopDialog(); } else { state.state = Tile.STATE_UNAVAILABLE; String noWifi = mContext.getString(R.string.quick_settings_cast_no_network); Loading packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/CastDetailsContent.ktdeleted 100644 → 0 +0 −37 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.qs.tiles.dialog import android.view.LayoutInflater import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView import com.android.internal.R @Composable fun CastDetailsContent() { // TODO(b/378514236): Finish implementing this function. AndroidView( modifier = Modifier.fillMaxWidth().fillMaxHeight(), factory = { context -> // Inflate with the existing dialog xml layout LayoutInflater.from(context).inflate(R.layout.media_route_controller_dialog, null) }, ) } packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/CastDetailsViewModel.ktdeleted 100644 → 0 +0 −50 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.qs.tiles.dialog import android.content.Intent import android.provider.Settings import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject /** The view model used for the screen record details view in the Quick Settings */ class CastDetailsViewModel @AssistedInject constructor(private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler) : TileDetailsViewModel { @AssistedFactory fun interface Factory { fun create(): CastDetailsViewModel } override fun clickOnSettingsButton() { qsTileIntentUserActionHandler.handle( /* expandable= */ null, Intent(Settings.ACTION_CAST_SETTINGS), ) } // TODO(b/388321032): Replace this string with a string in a translatable xml file, override val title: String get() = "Cast screen to device" // TODO(b/388321032): Replace this string with a string in a translatable xml file, override val subTitle: String get() = "Searching for devices..." } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java +2 −31 Original line number Diff line number Diff line Loading @@ -50,7 +50,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tiles.dialog.CastDetailsViewModel; import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor; import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor; import com.android.systemui.statusbar.connectivity.IconState; Loading @@ -64,7 +63,6 @@ import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading Loading @@ -106,8 +104,6 @@ public class CastTileTest extends SysuiTestCase { private DialogTransitionAnimator mDialogTransitionAnimator; @Mock private QsEventLogger mUiEventLogger; @Mock private CastDetailsViewModel.Factory mCastDetailsViewModelFactory; private final TileJavaAdapter mJavaAdapter = new TileJavaAdapter(); private final FakeConnectivityRepository mConnectivityRepository = Loading Loading @@ -521,29 +517,6 @@ public class CastTileTest extends SysuiTestCase { assertTrue(mCastTile.getState().forceExpandIcon); } @Test public void testDetailsViewUnavailableState_returnsNull() { createAndStartTileNewImpl(); mTestableLooper.processAllMessages(); assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state); mCastTile.getDetailsViewModel(Assert::assertNull); } @Test public void testDetailsViewAvailableState_returnsNotNull() { createAndStartTileNewImpl(); CastDevice device = createConnectedCastDevice(); List<CastDevice> devices = new ArrayList<>(); devices.add(device); when(mController.getCastDevices()).thenReturn(devices); mConnectivityRepository.setWifiConnected(true); mTestableLooper.processAllMessages(); assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state); mCastTile.getDetailsViewModel(Assert::assertNotNull); } /** * For simplicity, let this method still set the field even though that's kind of gross */ Loading @@ -567,8 +540,7 @@ public class CastTileTest extends SysuiTestCase { mConnectivityRepository, mJavaAdapter, mFeatureFlags, mShadeDialogContextInteractor, mCastDetailsViewModelFactory mShadeDialogContextInteractor ); mCastTile.initialize(); Loading Loading @@ -612,8 +584,7 @@ public class CastTileTest extends SysuiTestCase { mConnectivityRepository, mJavaAdapter, mFeatureFlags, mShadeDialogContextInteractor, mCastDetailsViewModelFactory mShadeDialogContextInteractor ); mCastTile.initialize(); Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt +0 −3 Original line number Diff line number Diff line Loading @@ -43,8 +43,6 @@ import com.android.systemui.bluetooth.qsdialog.BluetoothDetailsViewModel import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.qs.flags.QsDetailedView import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel import com.android.systemui.qs.tiles.dialog.CastDetailsContent import com.android.systemui.qs.tiles.dialog.CastDetailsViewModel import com.android.systemui.qs.tiles.dialog.InternetDetailsContent import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel import com.android.systemui.qs.tiles.dialog.ModesDetailsContent Loading Loading @@ -133,7 +131,6 @@ private fun MapTileDetailsContent(tileDetailsViewModel: TileDetailsViewModel) { is BluetoothDetailsViewModel -> BluetoothDetailsContent(tileDetailsViewModel.detailsContentViewModel) is ModesDetailsViewModel -> ModesDetailsContent(tileDetailsViewModel) is CastDetailsViewModel -> CastDetailsContent() } } Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +13 −40 Original line number Diff line number Diff line Loading @@ -48,13 +48,11 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.qs.TileDetailsViewModel; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.qs.tiles.dialog.CastDetailsViewModel; import com.android.systemui.res.R; import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor; import com.android.systemui.statusbar.connectivity.NetworkController; Loading Loading @@ -95,7 +93,6 @@ public class CastTile extends QSTileImpl<BooleanState> { private final ShadeDialogContextInteractor mShadeDialogContextInteractor; private boolean mCastTransportAllowed; private boolean mHotspotConnected; private final CastDetailsViewModel.Factory mCastDetailsViewModelFactory; @Inject public CastTile( Loading @@ -116,8 +113,7 @@ public class CastTile extends QSTileImpl<BooleanState> { ConnectivityRepository connectivityRepository, TileJavaAdapter javaAdapter, FeatureFlags featureFlags, ShadeDialogContextInteractor shadeDialogContextInteractor, CastDetailsViewModel.Factory castDetailsViewModelFactory ShadeDialogContextInteractor shadeDialogContextInteractor ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); Loading @@ -128,7 +124,6 @@ public class CastTile extends QSTileImpl<BooleanState> { mJavaAdapter = javaAdapter; mFeatureFlags = featureFlags; mShadeDialogContextInteractor = shadeDialogContextInteractor; mCastDetailsViewModelFactory = castDetailsViewModelFactory; mController.observe(this, mCallback); mKeyguard.observe(this, mCallback); if (!mFeatureFlags.isEnabled(SIGNAL_CALLBACK_DEPRECATION)) { Loading Loading @@ -177,7 +172,12 @@ public class CastTile extends QSTileImpl<BooleanState> { @Override protected void handleClick(@Nullable Expandable expandable) { handleClick(() -> { if (getState().state == Tile.STATE_UNAVAILABLE) { return; } List<CastDevice> activeDevices = getActiveDevices(); if (willPopDialog()) { if (!mKeyguard.isShowing()) { showDialog(expandable); } else { Loading @@ -187,43 +187,16 @@ public class CastTile extends QSTileImpl<BooleanState> { showDialog(null /* view */); }); } }); } @Override public boolean getDetailsViewModel(Consumer<TileDetailsViewModel> callback) { CastDetailsViewModel viewModel = mCastDetailsViewModelFactory.create(); handleClick(() -> { if (!mKeyguard.isShowing()) { callback.accept(viewModel); } else { mActivityStarter.dismissKeyguardThenExecute(() -> { callback.accept(viewModel); return false; }, null /* cancelAction */, true/* afterKeyguardGone */); } }); return true; } private void handleClick(Runnable showPromptCallback) { if (getState().state == Tile.STATE_UNAVAILABLE) { return; } List<CastDevice> activeDevices = getActiveDevices(); if (willShowPrompt()) { showPromptCallback.run(); } else { mController.stopCasting(activeDevices.get(0), StopReason.STOP_QS_TILE); } } // We want to pop up the media route selection dialog (or show the cast details view) if we // either have no active devices (neither routes nor projection), or if we have an active // route. In other cases, we assume that a projection is active. This is messy, but this tile // never correctly handled the case where multiple devices were active :-/. private boolean willShowPrompt() { // We want to pop up the media route selection dialog if we either have no active devices // (neither routes nor projection), or if we have an active route. In other cases, we assume // that a projection is active. This is messy, but this tile never correctly handled the // case where multiple devices were active :-/. private boolean willPopDialog() { List<CastDevice> activeDevices = getActiveDevices(); return activeDevices.isEmpty() || (activeDevices.get(0).getTag() instanceof RouteInfo); } Loading Loading @@ -330,7 +303,7 @@ public class CastTile extends QSTileImpl<BooleanState> { state.secondaryLabel = ""; } state.expandedAccessibilityClassName = Button.class.getName(); state.forceExpandIcon = willShowPrompt(); state.forceExpandIcon = willPopDialog(); } else { state.state = Tile.STATE_UNAVAILABLE; String noWifi = mContext.getString(R.string.quick_settings_cast_no_network); Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/CastDetailsContent.ktdeleted 100644 → 0 +0 −37 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.qs.tiles.dialog import android.view.LayoutInflater import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView import com.android.internal.R @Composable fun CastDetailsContent() { // TODO(b/378514236): Finish implementing this function. AndroidView( modifier = Modifier.fillMaxWidth().fillMaxHeight(), factory = { context -> // Inflate with the existing dialog xml layout LayoutInflater.from(context).inflate(R.layout.media_route_controller_dialog, null) }, ) }
packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/CastDetailsViewModel.ktdeleted 100644 → 0 +0 −50 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.qs.tiles.dialog import android.content.Intent import android.provider.Settings import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject /** The view model used for the screen record details view in the Quick Settings */ class CastDetailsViewModel @AssistedInject constructor(private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler) : TileDetailsViewModel { @AssistedFactory fun interface Factory { fun create(): CastDetailsViewModel } override fun clickOnSettingsButton() { qsTileIntentUserActionHandler.handle( /* expandable= */ null, Intent(Settings.ACTION_CAST_SETTINGS), ) } // TODO(b/388321032): Replace this string with a string in a translatable xml file, override val title: String get() = "Cast screen to device" // TODO(b/388321032): Replace this string with a string in a translatable xml file, override val subTitle: String get() = "Searching for devices..." }