Merge "Gate controls controllers with system feature flag" into rvc-dev

This commit is contained in:
Fabian Kozynski
2020-05-27 20:44:35 +00:00
committed by Android (Google) Code Review
9 changed files with 236 additions and 21 deletions

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2020 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.controls.dagger
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import dagger.Lazy
import java.util.Optional
import javax.inject.Inject
import javax.inject.Singleton
/**
* Pseudo-component to inject into classes outside `com.android.systemui.controls`.
*
* If `featureEnabled` is false, all the optionals should be empty. The controllers will only be
* instantiated if `featureEnabled` is true.
*/
@Singleton
class ControlsComponent @Inject constructor(
@ControlsFeatureEnabled private val featureEnabled: Boolean,
private val lazyControlsController: Lazy<ControlsController>,
private val lazyControlsUiController: Lazy<ControlsUiController>,
private val lazyControlsListingController: Lazy<ControlsListingController>
) {
fun getControlsController(): Optional<ControlsController> {
return if (featureEnabled) Optional.of(lazyControlsController.get()) else Optional.empty()
}
fun getControlsUiController(): Optional<ControlsUiController> {
return if (featureEnabled) Optional.of(lazyControlsUiController.get()) else Optional.empty()
}
fun getControlsListingController(): Optional<ControlsListingController> {
return if (featureEnabled) {
Optional.of(lazyControlsListingController.get())
} else {
Optional.empty()
}
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2020 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.controls.dagger
import javax.inject.Qualifier
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class ControlsFeatureEnabled

View File

@@ -17,6 +17,7 @@
package com.android.systemui.controls.dagger
import android.app.Activity
import android.content.pm.PackageManager
import com.android.systemui.controls.controller.ControlsBindingController
import com.android.systemui.controls.controller.ControlsBindingControllerImpl
import com.android.systemui.controls.controller.ControlsController
@@ -28,19 +29,39 @@ import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsListingControllerImpl
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.controls.management.ControlsRequestDialog
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.ControlsUiControllerImpl
import com.android.systemui.controls.ui.ControlActionCoordinator
import com.android.systemui.controls.ui.ControlActionCoordinatorImpl
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.ControlsUiControllerImpl
import dagger.Binds
import dagger.BindsOptionalOf
import dagger.Module
import dagger.Provides
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
import javax.inject.Singleton
/**
* Module for injecting classes in `com.android.systemui.controls`-
*
* Classes provided by this module should only be injected directly into other classes in this
* module. For injecting outside of this module (for example, [GlobalActionsDialog], inject
* [ControlsComponent] and obtain the corresponding optionals from it.
*/
@Module
abstract class ControlsModule {
@Module
companion object {
@JvmStatic
@Provides
@Singleton
@ControlsFeatureEnabled
fun providesControlsFeatureEnabled(pm: PackageManager): Boolean {
return pm.hasSystemFeature(PackageManager.FEATURE_CONTROLS)
}
}
@Binds
abstract fun provideControlsListingController(
controller: ControlsListingControllerImpl

View File

@@ -55,6 +55,9 @@ class ControlsRequestReceiver : BroadcastReceiver() {
}
override fun onReceive(context: Context, intent: Intent) {
if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_CONTROLS)) {
return
}
val packageName = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
?.packageName

View File

@@ -60,7 +60,6 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.globalactions.GlobalActionsPopupMenu
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.phone.ShadeController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Lazy
import java.text.Collator
@@ -80,7 +79,6 @@ class ControlsUiControllerImpl @Inject constructor (
@Main val sharedPreferences: SharedPreferences,
val controlActionCoordinator: ControlActionCoordinator,
private val activityStarter: ActivityStarter,
private val keyguardStateController: KeyguardStateController,
private val shadeController: ShadeController
) : ControlsUiController {

View File

@@ -120,8 +120,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.controls.ControlsServiceInfo;
import com.android.systemui.controls.controller.ControlsController;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.controls.management.ControlsAnimations;
import com.android.systemui.controls.management.ControlsListingController;
import com.android.systemui.controls.ui.ControlsUiController;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -140,6 +140,7 @@ import com.android.systemui.util.leak.RotationUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -234,11 +235,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final IStatusBarService mStatusBarService;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private GlobalActionsPanelPlugin mWalletPlugin;
private ControlsUiController mControlsUiController;
private Optional<ControlsUiController> mControlsUiControllerOptional;
private final IWindowManager mIWindowManager;
private final Executor mBackgroundExecutor;
private List<ControlsServiceInfo> mControlsServiceInfos = new ArrayList<>();
private ControlsController mControlsController;
private Optional<ControlsController> mControlsControllerOptional;
private SharedPreferences mControlsPreferences;
private final RingerModeTracker mRingerModeTracker;
private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
private Handler mMainHandler;
@@ -298,11 +300,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
NotificationShadeDepthController depthController, SysuiColorExtractor colorExtractor,
IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
ControlsUiController controlsUiController, IWindowManager iWindowManager,
IWindowManager iWindowManager,
@Background Executor backgroundExecutor,
ControlsListingController controlsListingController,
ControlsController controlsController, UiEventLogger uiEventLogger,
UiEventLogger uiEventLogger,
RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler,
ControlsComponent controlsComponent,
CurrentUserContextTracker currentUserContextTracker) {
mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
mWindowManagerFuncs = windowManagerFuncs;
@@ -325,11 +327,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mSysuiColorExtractor = colorExtractor;
mStatusBarService = statusBarService;
mNotificationShadeWindowController = notificationShadeWindowController;
mControlsUiController = controlsUiController;
mControlsUiControllerOptional = controlsComponent.getControlsUiController();
mIWindowManager = iWindowManager;
mBackgroundExecutor = backgroundExecutor;
mRingerModeTracker = ringerModeTracker;
mControlsController = controlsController;
mControlsControllerOptional = controlsComponent.getControlsController();
mSysUiState = sysUiState;
mMainHandler = handler;
mCurrentUserContextTracker = currentUserContextTracker;
@@ -374,7 +376,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mDialog.mWalletViewController.onDeviceLockStateChanged(!unlocked);
}
if (!mDialog.isShowingControls() && shouldShowControls()) {
mDialog.showControls(mControlsUiController);
mDialog.showControls(mControlsUiControllerOptional.get());
}
if (unlocked) {
mDialog.hideLockMessage();
@@ -383,7 +385,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
});
controlsListingController.addCallback(list -> mControlsServiceInfos = list);
if (controlsComponent.getControlsListingController().isPresent()) {
controlsComponent.getControlsListingController().get()
.addCallback(list -> mControlsServiceInfos = list);
}
// Need to be user-specific with the context to make sure we read the correct prefs
Context userContext = context.createContextAsUser(
new UserHandle(mUserManager.getUserHandle()), 0);
mControlsPreferences = userContext.getSharedPreferences(PREFS_CONTROLS_FILE,
Context.MODE_PRIVATE);
// Listen for changes to show controls on the power menu while locked
onPowerMenuLockScreenSettingsChanged();
@@ -399,8 +410,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
private void seedFavorites() {
if (!mControlsControllerOptional.isPresent()) return;
if (mControlsServiceInfos.isEmpty()
|| mControlsController.getFavorites().size() > 0) {
|| mControlsControllerOptional.get().getFavorites().size() > 0) {
return;
}
@@ -433,7 +445,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return;
}
mControlsController.seedFavoritesForComponent(
mControlsControllerOptional.get().seedFavoritesForComponent(
preferredComponent,
(accepted) -> {
Log.i(TAG, "Controls seeded: " + accepted);
@@ -636,10 +648,14 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mDepthController.setShowingHomeControls(true);
GlobalActionsPanelPlugin.PanelViewController walletViewController =
getWalletViewController();
ControlsUiController uiController = null;
if (mControlsUiControllerOptional.isPresent() && shouldShowControls()) {
uiController = mControlsUiControllerOptional.get();
}
ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mOverflowAdapter,
walletViewController, mDepthController, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController,
controlsAvailable(), shouldShowControls() ? mControlsUiController : null,
controlsAvailable(), uiController,
mSysUiState, this::onRotate, mKeyguardShowing);
boolean walletViewAvailable = walletViewController != null
&& walletViewController.getPanelContent() != null;
@@ -2403,7 +2419,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private boolean controlsAvailable() {
return mDeviceProvisioned
&& mControlsUiController.getAvailable()
&& mControlsUiControllerOptional.isPresent()
&& mControlsUiControllerOptional.get().getAvailable()
&& !mControlsServiceInfos.isEmpty();
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2020 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.controls.dagger
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import dagger.Lazy
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
class ControlsComponentTest : SysuiTestCase() {
@Mock
private lateinit var controller: ControlsController
@Mock
private lateinit var uiController: ControlsUiController
@Mock
private lateinit var listingController: ControlsListingController
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
}
@Test
fun testFeatureEnabled() {
val component = ControlsComponent(
true,
Lazy { controller },
Lazy { uiController },
Lazy { listingController }
)
assertTrue(component.getControlsController().isPresent)
assertEquals(controller, component.getControlsController().get())
assertTrue(component.getControlsUiController().isPresent)
assertEquals(uiController, component.getControlsUiController().get())
assertTrue(component.getControlsListingController().isPresent)
assertEquals(listingController, component.getControlsListingController().get())
}
@Test
fun testFeatureDisabled() {
val component = ControlsComponent(
false,
Lazy { controller },
Lazy { uiController },
Lazy { listingController }
)
assertFalse(component.getControlsController().isPresent)
assertFalse(component.getControlsUiController().isPresent)
assertFalse(component.getControlsListingController().isPresent)
}
}

View File

@@ -66,6 +66,7 @@ class ControlsRequestReceiverTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
mContext.setMockPackageManager(packageManager)
`when`(packageManager.hasSystemFeature(PackageManager.FEATURE_CONTROLS)).thenReturn(true)
mContext.addMockSystemService(ActivityManager::class.java, activityManager)
receiver = ControlsRequestReceiver()
@@ -145,6 +146,14 @@ class ControlsRequestReceiverTest : SysuiTestCase() {
} ?: run { fail("Null start intent") }
}
@Test
fun testFeatureDisabled_activityNotStarted() {
`when`(packageManager.hasSystemFeature(PackageManager.FEATURE_CONTROLS)).thenReturn(false)
receiver.onReceive(wrapper, intent)
assertNull(wrapper.intent)
}
class MyWrapper(context: Context) : ContextWrapper(context) {
var intent: Intent? = null

View File

@@ -59,6 +59,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.controls.controller.ControlsController;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.controls.management.ControlsListingController;
import com.android.systemui.controls.ui.ControlsUiController;
import com.android.systemui.model.SysUiState;
@@ -121,6 +122,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
@Mock GlobalActionsPanelPlugin.PanelViewController mWalletController;
@Mock private Handler mHandler;
@Mock private CurrentUserContextTracker mCurrentUserContextTracker;
private ControlsComponent mControlsComponent;
private TestableLooper mTestableLooper;
@@ -132,6 +134,13 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData);
when(mCurrentUserContextTracker.getCurrentUserContext()).thenReturn(mContext);
mControlsComponent = new ControlsComponent(
true,
() -> mControlsController,
() -> mControlsUiController,
() -> mControlsListingController
);
mGlobalActionsDialog = new GlobalActionsDialog(mContext,
mWindowManagerFuncs,
mAudioManager,
@@ -156,15 +165,13 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
mColorExtractor,
mStatusBarService,
mNotificationShadeWindowController,
mControlsUiController,
mWindowManager,
mBackgroundExecutor,
mControlsListingController,
mControlsController,
mUiEventLogger,
mRingerModeTracker,
mSysUiState,
mHandler,
mControlsComponent,
mCurrentUserContextTracker
);
mGlobalActionsDialog.setZeroDialogPressDelayForTesting();